Search code examples
sqldatabasepostgresqldatabase-designcheck-constraints

PostgreSQL query for a list of allowed values in a constraint?


Given a PostgreSQL table named requests with a column named status and a constraint like this:

ALTER TABLE requests ADD CONSTRAINT allowed_status_types
  CHECK (status IN (
    'pending', -- request has not been attempted
    'success', -- request succeeded
    'failure'  -- request failed
  ));

In psql I can pull up information about this constraint like this:

example-database=# \d requests
                                          Table "public.example-database"
        Column        |            Type             |                             Modifiers
----------------------+-----------------------------+-------------------------------------------------------------------
 id                   | integer                     | not null default nextval('requests_id_seq'::regclass)
 status               | character varying           | not null default 'pending'::character varying
 created_at           | timestamp without time zone | not null
 updated_at           | timestamp without time zone | not null

Indexes:
    "requests_pkey" PRIMARY KEY, btree (id)
Check constraints:
    "allowed_status_types" CHECK (status::text = ANY (ARRAY['pending'::character varying, 'success'::character varying, 'failure'::character varying]::text[]))

But is it possible to write a query that specifically returns the allowed_status_types of pending, success, failure?

It would be great to be able to memoize the results of this query within my application, vs. having to maintain a duplicate copy.


Solution

  • You can query the system catalog pg_constraint, e.g.:

    select consrc
    from pg_constraint
    where conrelid = 'requests'::regclass
    and consrc like '(status%';
    
                                      consrc                                   
    ---------------------------------------------------------------------------
     (status = ANY (ARRAY['pending'::text, 'success'::text, 'failure'::text]))
    (1 row) 
    

    Use the following function to unpack the string:

    create or replace function get_check_values(str text)
    returns setof text language plpgsql as $$
    begin
        return query
            execute format (
                'select * from unnest(%s)',
                regexp_replace(str, '.*(ARRAY\[.*\]).*', '\1'));
    end $$;
    
    select get_check_values(consrc)
    from pg_constraint
    where conrelid = 'requests'::regclass
    and consrc like '(status%';
    
     get_check_values 
    ------------------
     pending
     success
     failure
    (3 rows)