Thread

  1. Re: domain for WITHOUT OVERLAPS

    Paul A Jungwirth <pj@illuminatedcomputing.com> — 2025-12-03T18:39:40Z

    On Tue, Dec 2, 2025 at 11:39 PM jian he <jian.universality@gmail.com> wrote:
    >
    > While working on domain IS JSON, I found out that
    > WITHOUT OVERLAPS does not support for domain too.
    > but it does support user-defined range types (via CREATE TYPE).
    >
    > after looking around:
    > check_exclusion_or_unique_constraint->ExecWithoutOverlapsNotEmpty
    > ExecWithoutOverlapsNotEmpty typtype should be domain's basetype's typtype
    > otherwise it will fallback to:
    >             elog(ERROR, "WITHOUT OVERLAPS column \"%s\" is not a range
    > or multirange",
    >                  NameStr(attname));
    >
    > That means we need to cheaply get the domain basetype's
    > pg_type.typtype in lookup_type_cache.
    > so I added a new char field: TypeCacheEntry.domainBaseTyptype.
    
    Thanks for the bug report and fix! Have you created a commitfest entry
    for this? I didn't find one.
    
    +CREATE DOMAIN d_textrange1 AS int4range CHECK (VALUE <> '[10,10]');
    +CREATE DOMAIN d_textrange2 AS textrange2 CHECK (VALUE <> '[c,c]');
    +CREATE DOMAIN d_textrange2c AS d_textrange2;
    
    The first domain should be called d_int4range or d_int4range1, right?
    
    Also let's name them like int4range_d so that we can use int4_d_range
    for a range over a domain.
    
    Please use closed/open notation to match the rest of the ranges in the
    file: '[10,11)' and '[c,d)'.
    
    I think there are these cases to consider:
    
    - WITHOUT OVERLAPS on a rangetype whose subtype has a domain
    - WITHOUT OVERLAPS on a rangetype with a domain on itself
    - WITHOUT OVERLAPS on a multirangetype whose subtype has a domain
    - WITHOUT OVERLAPS on a multirangetype whose rangetype has a domain
    - WITHOUT OVERLAPS on a multirangetype with a domain on itself
    
    For instance we could set things up like so:
    
    -- range+multirange over a domain:
    create domain int4_d as integer check (value <> 10);
    create type int4_d_range as range (subtype = int4_d);
    
    -- domain on a range:
    create domain int4range_d as int4range check (value <> '[10,11)');
    
    -- domain on a multirange:
    create domain int4multirange_d as int4multirange check (value <> '{[10,11)}');
    
    Then we have this:
    
    ```
    [v19devel:5432][426675] postgres=# select oid, typname, typtype,
    typbasetype, typtypmod from pg_type where oid >= 20000 order by oid ;
      oid  |      typname       | typtype | typbasetype | typtypmod
    -------+--------------------+---------+-------------+-----------
     24595 | _int4_d            | b       |           0 |        -1
     24596 | int4_d             | d       |          23 |        -1
     24598 | _int4_d_range      | b       |           0 |        -1
     24599 | int4_d_multirange  | m       |           0 |        -1
     24600 | _int4_d_multirange | b       |           0 |        -1
     24601 | int4_d_range       | r       |           0 |        -1
     24608 | _int4range_d       | b       |           0 |        -1
     24609 | int4range_d        | d       |        3904 |        -1
     24611 | _int4multirange_d  | b       |           0 |        -1
     24612 | int4multirange_d   | d       |        4451 |        -1
    ```
    
    Note that creating a domain on a range does not create a corresponding
    multirange. Maybe that is a bug. It means we can't test the 4th case
    above.
    
    It looks like domains on the subtype work, but not directly on a range
    or multirange:
    
    ```
    [v19devel:5432][426675] postgres=# create table t1 (id int4range,
    valid_at int4_d_range, primary key (id, valid_at without overlaps));
    CREATE TABLE
    [v19devel:5432][426675] postgres=# create table t2 (id int4range,
    valid_at int4range_d, primary key (id, valid_at without overlaps));
    ERROR:  column "valid_at" in WITHOUT OVERLAPS is not a range or multirange type
    LINE 1: ...ate table t2 (id int4range, valid_at int4range_d, primary ke...
                                                                 ^
    [v19devel:5432][426675] postgres=# create table t3 (id int4range,
    valid_at int4_d_multirange, primary key (id, valid_at without
    overlaps));
    CREATE TABLE
    [v19devel:5432][426675] postgres=# create table t4 (id int4range,
    valid_at int4_multirange_d, primary key (id, valid_at without
    overlaps));
    ERROR:  type "int4_multirange_d" does not exist
    LINE 1: create table t4 (id int4range, valid_at int4_multirange_d, p...
    ```
    
    It would be good to have tests for all of those. For instance:
    
    ```
    -- domain on a multirange:
    
    CREATE DOMAIN textmultirange2_d AS textmultirange2 CHECK (VALUE <> '{[c,d)}');
    CREATE TABLE temporal_mltrng4 (
      id d_int4range1,
      valid_at textmultirange2_d,
      CONSTRAINT temporal_rng4_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)
    );
    
    INSERT INTO temporal_mltrng4 VALUES ('[1,2)', '{[c,d)}'); --domain
    constraint violation
    INSERT INTO temporal_mltrng4 VALUES ('[1,2)', '{[a,g)}');
    INSERT INTO temporal_mltrng4 VALUES ('[1,2)', '{[b,c)}'); --error
    INSERT INTO temporal_mltrng4 VALUES ('[2,3)', '{[B,C)}'), ('[2,2]',
    '{[A,C)}'); --error
    
    CREATE TABLE temporal_mltrngfk (parent_id d_int4range1, id int4range,
    valid_at textmultirange2_d);
    ALTER TABLE temporal_mltrngfk
      ADD CONSTRAINT temporal_mltrngfk_fk
        FOREIGN KEY (parent_id, PERIOD valid_at)
        REFERENCES temporal_mltrng4;
    
    INSERT INTO temporal_mltrngfk VALUES ('[1,2)', '[2,3)', '{[d,e)}');
    TABLE temporal_mltrng4;
    TABLE temporal_mltrngfk;
    
    UPDATE temporal_mltrng4 SET valid_at = '{[c,d)}'; --error
    UPDATE temporal_mltrng4 SET valid_at = '{[a,h)}';
    UPDATE temporal_mltrng4 SET valid_at = '{[f,g)}'; --error
    
    DROP TABLE temporal_mltrng4, temporal_mltrngfk;
    ```
    
    When I try that, it looks like your patch fixes multiranges too.
    
    Yours,
    
    -- 
    Paul              ~{:-)
    pj@illuminatedcomputing.com