On 02.11.23 21:21, Paul Jungwirth wrote:
New patches attached (rebased to 0bc726d9).

I went over the patch v17-0001-Add-temporal-PRIMARY-KEY-and-UNIQUE-constraints.patch in more detail. Attached is a fixup patch that addresses a variety of cosmetic issues.

Some details:

- Renamed contemporal to conwithoutoverlaps, as previously discussed. Also renamed various variables and function arguments similarly.

- Rearranged text in CREATE TABLE reference page so there are no forward references. (Describe WITHOUT OVERLAPS under UNIQUE and then PRIMARY KEy says "see above", rather than describe it under PRIMARY KEY and have UNIQUE say "see below.)

- Removed various bits that related to temporal foreign keys, which belong in a later patch.

- Reverted some apparently unrelated changes in src/backend/catalog/index.c.

- Removed the "temporal UNIQUE" constraint_type assignment in DefineIndex(). This is meant to be used in error messages and should refer to actual syntax. I think it's fine without it this change.

- Field contemporal in NewConstraint struct is not used by this patch.

- Rearrange the grammar so that the rule with WITHOUT OVERLAPS is just a Boolean attribute rather than column name plus keywords. This was kind of confusing earlier and led to weird error messages for invalid syntax. I kept the restriction that you need at least one non-overlaps column, but that is now enforced in parse analysis, not in the grammar. (But maybe we don't need it?)

(After your earlier explanation, I'm content to just allow one WITHOUT OVERLAPS column for now.)

- Some places looked at conexclop to check whether something is a WITHOUT OVERLAPS constraint, instead of looking at conwithoutoverlaps directly.

- Removed some redundant "unlike" entries in the pg_dump tests. (This caused cfbot tests to fail.)

- Moved the "without_overlaps" test later in the schedule. It should at least be after "constraints" so that normal constraints are tested first.


Two areas that could be improved:

1) In src/backend/commands/indexcmds.c, get_index_attr_temporal_operator() has this comment:

+    * This seems like a hack
+    * but I can't find any existing lookup function
+    * that knows about pseudotypes.

This doesn't see very confident. ;-) I don't quite understand this. Is this a gap in the currently available APIs, do we need to improve something here, or does this need more research?

2) In src/backend/parser/parse_utilcmd.c, transformIndexConstraint(), there is too much duplication between the normal and the if (constraint->without_overlaps) case, like the whole not-null constraints stuff at the end. This should be one code block with a few conditionals inside. Also, the normal case deals with things like table inheritance, which the added parts do not. Is this all complete?

I'm not sure the validateWithoutOverlaps() function is needed at this point in the code. We just need to check that the column exists, which the normal code path already does, and then have the index creation code later check that an appropriate overlaps operator exists. We don't even need to restrict this to range types. Consider for example, it's possible that a type does not have a btree equality operator. We don't check that here either, but let the index code later check it.


Overall, with these fixes, I think this patch is structurally okay. We just need to make sure we have all the weird corner cases covered.
From 6d7af1f78505c08fb205a56bd1ba3cb951f04002 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Thu, 9 Nov 2023 14:11:34 +0100
Subject: [PATCH] fixup! Add temporal PRIMARY KEY and UNIQUE constraints

---
 doc/src/sgml/catalogs.sgml                    |  8 +--
 doc/src/sgml/ref/create_table.sgml            | 68 ++++++++-----------
 src/backend/catalog/heap.c                    |  4 +-
 src/backend/catalog/index.c                   | 14 ++--
 src/backend/catalog/pg_constraint.c           |  4 +-
 src/backend/commands/indexcmds.c              | 30 ++++----
 src/backend/commands/tablecmds.c              | 16 ++---
 src/backend/commands/trigger.c                |  2 +-
 src/backend/commands/typecmds.c               |  2 +-
 src/backend/parser/gram.y                     | 19 +++---
 src/backend/parser/parse_utilcmd.c            | 28 ++++++--
 src/backend/utils/adt/ruleutils.c             | 27 +++-----
 src/backend/utils/cache/relcache.c            | 16 +++--
 src/bin/pg_dump/pg_dump.c                     | 33 +++------
 src/bin/pg_dump/pg_dump.h                     |  2 +-
 src/bin/pg_dump/t/002_pg_dump.pl              | 14 ++--
 src/bin/psql/describe.c                       | 10 +--
 src/include/catalog/index.h                   |  2 +-
 src/include/catalog/pg_constraint.h           | 11 +--
 src/include/commands/defrem.h                 |  2 +-
 src/include/nodes/parsenodes.h                |  6 +-
 .../regress/expected/without_overlaps.out     |  8 +--
 src/test/regress/parallel_schedule            |  4 +-
 23 files changed, 148 insertions(+), 182 deletions(-)

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 5412f2daa0..618a05ac89 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -2711,13 +2711,11 @@ <title><structname>pg_constraint</structname> 
Columns</title>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>contemporal</structfield> <type>bool</type>
+       <structfield>conwithoutoverlaps</structfield> <type>bool</type>
       </para>
       <para>
-       This constraint is a application-time temporal constraint,
-       defined with <literal>WITHOUT OVERLAPS</literal> (for primary
-       key and unique constraints) or <literal>PERIOD</literal> (for
-       foreign keys).
+       This constraint is defined with <literal>WITHOUT OVERLAPS</literal>
+       (for primary keys and unique constraints).
       </para></entry>
      </row>
 
diff --git a/doc/src/sgml/ref/create_table.sgml 
b/doc/src/sgml/ref/create_table.sgml
index ad5bf21453..a0bd2b8adc 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -78,8 +78,8 @@
 [ CONSTRAINT <replaceable class="parameter">constraint_name</replaceable> ]
 { CHECK ( <replaceable class="parameter">expression</replaceable> ) [ NO 
INHERIT ] |
   NOT NULL <replaceable class="parameter">column_name</replaceable> [ NO 
INHERIT ] |
-  UNIQUE [ NULLS [ NOT ] DISTINCT ] ( <replaceable 
class="parameter">column_name</replaceable> [, ... ] [, <replaceable 
class="parameter">temporal_interval</replaceable> WITHOUT OVERLAPS ] ) 
<replaceable class="parameter">index_parameters</replaceable> |
-  PRIMARY KEY ( <replaceable class="parameter">column_name</replaceable> [, 
... ] [, <replaceable class="parameter">temporal_interval</replaceable> WITHOUT 
OVERLAPS ] ) <replaceable class="parameter">index_parameters</replaceable> |
+  UNIQUE [ NULLS [ NOT ] DISTINCT ] ( <replaceable 
class="parameter">column_name</replaceable> [, ... ] [, <replaceable 
class="parameter">column_name</replaceable> WITHOUT OVERLAPS ] ) <replaceable 
class="parameter">index_parameters</replaceable> |
+  PRIMARY KEY ( <replaceable class="parameter">column_name</replaceable> [, 
... ] [, <replaceable class="parameter">column_name</replaceable> WITHOUT 
OVERLAPS ] ) <replaceable class="parameter">index_parameters</replaceable> |
   EXCLUDE [ USING <replaceable class="parameter">index_method</replaceable> ] 
( <replaceable class="parameter">exclude_element</replaceable> WITH 
<replaceable class="parameter">operator</replaceable> [, ... ] ) <replaceable 
class="parameter">index_parameters</replaceable> [ WHERE ( <replaceable 
class="parameter">predicate</replaceable> ) ] |
   FOREIGN KEY ( <replaceable class="parameter">column_name</replaceable> [, 
... ] ) REFERENCES <replaceable class="parameter">reftable</replaceable> [ ( 
<replaceable class="parameter">refcolumn</replaceable> [, ... ] ) ]
     [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE <replaceable
@@ -107,10 +107,6 @@
 
 { <replaceable class="parameter">column_name</replaceable> | ( <replaceable 
class="parameter">expression</replaceable> ) } [ <replaceable 
class="parameter">opclass</replaceable> ] [ ASC | DESC ] [ NULLS { FIRST | LAST 
} ]
 
-<phrase><replaceable class="parameter">temporal_interval</replaceable> in a 
<literal>PRIMARY KEY</literal>, <literal>UNIQUE</literal>, or <literal>FOREIGN 
KEY</literal> constraint is:</phrase>
-
-<replaceable class="parameter">range_column_name</replaceable>
-
 <phrase><replaceable class="parameter">referential_action</replaceable> in a 
<literal>FOREIGN KEY</literal>/<literal>REFERENCES</literal> constraint 
is:</phrase>
 
 { NO ACTION | RESTRICT | CASCADE | SET NULL [ ( <replaceable 
class="parameter">column_name</replaceable> [, ... ] ) ] | SET DEFAULT [ ( 
<replaceable class="parameter">column_name</replaceable> [, ... ] ) ] }
@@ -969,7 +965,7 @@ <title>Parameters</title>
 
    <varlistentry id="sql-createtable-parms-unique">
     <term><literal>UNIQUE [ NULLS [ NOT ] DISTINCT ]</literal> (column 
constraint)</term>
-    <term><literal>UNIQUE [ NULLS [ NOT ] DISTINCT ] ( <replaceable 
class="parameter">column_name</replaceable> [, ... ] )</literal>
+    <term><literal>UNIQUE [ NULLS [ NOT ] DISTINCT ] ( <replaceable 
class="parameter">column_name</replaceable> [, ... ] [, <replaceable 
class="parameter">column_name</replaceable> WITHOUT OVERLAPS ] )</literal>
     <optional> <literal>INCLUDE ( <replaceable 
class="parameter">column_name</replaceable> [, ...])</literal> </optional> 
(table constraint)</term>
 
     <listitem>
@@ -983,6 +979,26 @@ <title>Parameters</title>
       of these columns.
      </para>
 
+     <para>
+      If the <literal>WITHOUT OVERLAPS</literal> option is specified for the
+      last column, then that column is checked for overlaps instead of
+      equality.  In that case, the other columns of the constraint will allow
+      duplicates so long as the duplicates don't overlap in the
+      <literal>WITHOUT OVERLAPS</literal> column.  (This is sometimes called a
+      temporal key, if the column is a range of dates or timestamps, but
+      PostgreSQL allows ranges over any base type.)  In effect, such a
+      constraint is enforced with an <literal>EXCLUDE</literal> constraint
+      rather than a <literal>UNIQUE</literal> constraint.  So for example
+      <literal>UNIQUE (id, valid_at WITHOUT OVERLAPS)</literal> behaves like
+      <literal>EXCLUDE USING GIST (id WITH =, valid_at WITH
+      &amp;&amp;)</literal>.  The <literal>WITHOUT OVERLAPS</literal> column
+      must have a range type.  The non-<literal>WITHOUT OVERLAPS</literal>
+      columns of the constraint can be any type that can be compared for
+      equality in a GiST index. By default only range types are supported, but
+      you can use other types by adding the <xref linkend="btree-gist"/>
+      extension (which is the expected way to use this feature).
+     </para>
+
      <para>
       For the purpose of a unique constraint, null values are not
       considered equal, unless <literal>NULLS NOT DISTINCT</literal> is
@@ -1007,8 +1023,7 @@ <title>Parameters</title>
       Adding a unique constraint will automatically create a unique btree
       index on the column or group of columns used in the constraint. But if
       the constraint includes a <literal>WITHOUT OVERLAPS</literal> clause,
-      it will use a GiST index and behave like a temporal <literal>PRIMARY
-      KEY</literal>: preventing duplicates only in overlapping time periods.
+      it will use a GiST index.
      </para>
 
      <para>
@@ -1026,8 +1041,7 @@ <title>Parameters</title>
 
    <varlistentry id="sql-createtable-parms-primary-key">
     <term><literal>PRIMARY KEY</literal> (column constraint)</term>
-    <term><literal>PRIMARY KEY ( <replaceable 
class="parameter">column_name</replaceable> [, ... ]
-    [, <replaceable class="parameter">temporal_interval</replaceable> WITHOUT 
OVERLAPS ] )</literal>
+    <term><literal>PRIMARY KEY ( <replaceable 
class="parameter">column_name</replaceable> [, ... ] [, <replaceable 
class="parameter">column_name</replaceable> WITHOUT OVERLAPS ] )</literal>
     <optional> <literal>INCLUDE ( <replaceable 
class="parameter">column_name</replaceable> [, ...])</literal> </optional> 
(table constraint)</term>
     <listitem>
      <para>
@@ -1060,9 +1074,10 @@ <title>Parameters</title>
      </para>
 
      <para>
-      Adding a <literal>PRIMARY KEY</literal> constraint will automatically
-      create a unique btree index (or GiST if temporal) on the column or group 
of
-      columns used in the constraint.
+      As with a <literal>UNIQUE</literal> constraint, adding a
+      <literal>PRIMARY KEY</literal> constraint will automatically create a
+      unique btree index, or GiST if <literal>WITHOUT OVERLAPS</literal> was
+      specified, on the column or group of columns used in the constraint.
      </para>
 
      <para>
@@ -1075,31 +1090,6 @@ <title>Parameters</title>
       (e.g., <literal>DROP COLUMN</literal>) can cause cascaded constraint and
       index deletion.
      </para>
-
-     <para>
-      A <literal>PRIMARY KEY</literal> with a <literal>WITHOUT 
OVERLAPS</literal> option
-      is a <emphasis>temporal</emphasis> primary key.
-      The <literal>WITHOUT OVERLAPS</literal> column
-      must be a range type or a <literal>PERIOD</literal>
-      and is used to constrain the record's applicability
-      to just that range/period (usually a range of dates or timestamps,
-      although Postgres allows a range/period over any base type).
-     </para>
-
-     <para>
-      The non-<literal>WITHOUT OVERLAPS</literal> part(s) of the key can be any
-      type that can be compared for equality in a GiST index. By default
-      only range types are supported, but you can use other types by
-      adding the <xref linkend="btree-gist"/> extension
-      (which is the expected way to use this feature).
-      These ordinary parts of the primary key do allow duplicates,
-      so long as the duplicates don't overlap in the
-      <literal>WITHOUT OVERLAPS</literal> column.
-      In effect a temporal <literal>PRIMARY KEY</literal> is enforced with an
-      <literal>EXCLUDE</literal> constraint rather than a 
<literal>UNIQUE</literal>
-      constraint. So for example <literal>PRIMARY KEY (id, valid_at WITHOUT 
OVERLAPS)</literal>
-      behaves like <literal>EXCLUDE USING GIST (id WITH =, valid_at WITH 
&amp;&amp;)</literal>.
-     </para>
     </listitem>
    </varlistentry>
 
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 3e9cc4bb10..f126d8e676 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2140,7 +2140,7 @@ StoreRelCheck(Relation rel, const char *ccname, Node 
*expr,
                                                          is_local, /* 
conislocal */
                                                          inhcount, /* 
coninhcount */
                                                          is_no_inherit,        
/* connoinherit */
-                                                         false,        /* 
contemporal */
+                                                         false,        /* 
conwithoutoverlaps */
                                                          is_internal); /* 
internally constructed? */
 
        pfree(ccbin);
@@ -2191,7 +2191,7 @@ StoreRelNotNull(Relation rel, const char *nnname, 
AttrNumber attnum,
                                                          is_local,
                                                          inhcount,
                                                          is_no_inherit,
-                                                         false,        /* 
contemporal */
+                                                         false,        /* 
conwithoutoverlaps */
                                                          false);
        return constrOid;
 }
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 2f1ec3b0ac..8444d768e5 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -254,8 +254,8 @@ index_check_primary_key(Relation heapRel,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("primary keys cannot be 
expressions")));
 
-               /* System attributes are never null, so no need to check. */
-               if (attnum <= 0)
+               /* System attributes are never null, so no need to check */
+               if (attnum < 0)
                        continue;
 
                atttuple = SearchSysCache2(ATTNUM,
@@ -1326,7 +1326,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid 
oldIndexId,
                                                                                
        Anum_pg_index_indoption);
        indcoloptions = (int2vector *) DatumGetPointer(colOptionDatum);
 
-       /* Fetch options of index if any */
+       /* Fetch reloptions of index if any */
        classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(oldIndexId));
        if (!HeapTupleIsValid(classTuple))
                elog(ERROR, "cache lookup failed for relation %u", oldIndexId);
@@ -1895,7 +1895,7 @@ index_concurrently_set_dead(Oid heapId, Oid indexId)
  *             INDEX_CONSTR_CREATE_UPDATE_INDEX: update the pg_index row
  *             INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS: remove existing 
dependencies
  *                     of index on table's columns
- *             INDEX_CONSTR_CREATE_TEMPORAL: constraint is for a temporal 
primary key
+ *             INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS: constraint uses WITHOUT 
OVERLAPS
  * allow_system_table_mods: allow table to be a system catalog
  * is_internal: index is constructed due to internal process
  */
@@ -1919,13 +1919,13 @@ index_constraint_create(Relation heapRelation,
        bool            mark_as_primary;
        bool            islocal;
        bool            noinherit;
-       bool            is_temporal;
+       bool            is_without_overlaps;
        int                     inhcount;
 
        deferrable = (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) != 0;
        initdeferred = (constr_flags & INDEX_CONSTR_CREATE_INIT_DEFERRED) != 0;
        mark_as_primary = (constr_flags & INDEX_CONSTR_CREATE_MARK_AS_PRIMARY) 
!= 0;
-       is_temporal = (constr_flags & INDEX_CONSTR_CREATE_TEMPORAL) != 0;
+       is_without_overlaps = (constr_flags & 
INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS) != 0;
 
        /* constraint creation support doesn't work while bootstrapping */
        Assert(!IsBootstrapProcessingMode());
@@ -2002,7 +2002,7 @@ index_constraint_create(Relation heapRelation,
                                                                   islocal,
                                                                   inhcount,
                                                                   noinherit,
-                                                                  is_temporal, 
/* contemporal */
+                                                                  
is_without_overlaps,
                                                                   is_internal);
 
        /*
diff --git a/src/backend/catalog/pg_constraint.c 
b/src/backend/catalog/pg_constraint.c
index d5329ca8c9..ffd340a2e4 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -78,7 +78,7 @@ CreateConstraintEntry(const char *constraintName,
                                          bool conIsLocal,
                                          int conInhCount,
                                          bool conNoInherit,
-                                         bool conTemporal,
+                                         bool conWithoutOverlaps,
                                          bool is_internal)
 {
        Relation        conDesc;
@@ -194,7 +194,7 @@ CreateConstraintEntry(const char *constraintName,
        values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
        values[Anum_pg_constraint_coninhcount - 1] = Int16GetDatum(conInhCount);
        values[Anum_pg_constraint_connoinherit - 1] = 
BoolGetDatum(conNoInherit);
-       values[Anum_pg_constraint_contemporal - 1] = BoolGetDatum(conTemporal);
+       values[Anum_pg_constraint_conwithoutoverlaps - 1] = 
BoolGetDatum(conWithoutOverlaps);
 
        if (conkeyArray)
                values[Anum_pg_constraint_conkey - 1] = 
PointerGetDatum(conkeyArray);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index e9d1b17935..d56db81fa1 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -91,7 +91,7 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo,
                                                          Oid accessMethodId,
                                                          bool amcanorder,
                                                          bool isconstraint,
-                                                         bool istemporal,
+                                                         bool 
iswithoutoverlaps,
                                                          Oid ddl_userid,
                                                          int ddl_sec_context,
                                                          int 
*ddl_save_nestlevel);
@@ -149,7 +149,7 @@ typedef struct ReindexErrorInfo
  *             to index on.
  * 'exclusionOpNames': list of names of exclusion-constraint operators,
  *             or NIL if not an exclusion constraint.
- * 'istemporal': true iff this index has a WITHOUT OVERLAPS clause.
+ * 'isWithoutOverlaps': true iff this index has a WITHOUT OVERLAPS clause.
  *
  * This is tailored to the needs of ALTER TABLE ALTER TYPE, which recreates
  * any indexes that depended on a changing column from their pg_get_indexdef
@@ -180,7 +180,7 @@ CheckIndexCompatible(Oid oldId,
                                         const char *accessMethodName,
                                         const List *attributeList,
                                         const List *exclusionOpNames,
-                                        bool istemporal)
+                                        bool isWithoutOverlaps)
 {
        bool            isconstraint;
        Oid                *typeIds;
@@ -255,7 +255,7 @@ CheckIndexCompatible(Oid oldId,
                                          coloptions, attributeList,
                                          exclusionOpNames, relationId,
                                          accessMethodName, accessMethodId,
-                                         amcanorder, isconstraint, istemporal, 
InvalidOid,
+                                         amcanorder, isconstraint, 
isWithoutOverlaps, InvalidOid,
                                          0, NULL);
 
        /* Get the soon-obsolete pg_index tuple. */
@@ -689,7 +689,7 @@ DefineIndex(Oid tableId,
         * It has exclusion constraint behavior if it's an EXCLUDE constraint
         * or a temporal PRIMARY KEY/UNIQUE constraint
         */
-       exclusion = stmt->excludeOpNames || stmt->istemporal;
+       exclusion = stmt->excludeOpNames || stmt->iswithoutoverlaps;
 
        /* Ensure that it makes sense to index this kind of relation */
        switch (rel->rd_rel->relkind)
@@ -859,7 +859,7 @@ DefineIndex(Oid tableId,
        pgstat_progress_update_param(PROGRESS_CREATEIDX_ACCESS_METHOD_OID,
                                                                 
accessMethodId);
 
-       if (stmt->unique && !stmt->istemporal && !amRoutine->amcanunique)
+       if (stmt->unique && !stmt->iswithoutoverlaps && !amRoutine->amcanunique)
                ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                 errmsg("access method \"%s\" does not support 
unique indexes",
@@ -927,7 +927,7 @@ DefineIndex(Oid tableId,
                                          coloptions, allIndexParams,
                                          stmt->excludeOpNames, tableId,
                                          accessMethodName, accessMethodId,
-                                         amcanorder, stmt->isconstraint, 
stmt->istemporal,
+                                         amcanorder, stmt->isconstraint, 
stmt->iswithoutoverlaps,
                                          root_save_userid, 
root_save_sec_context,
                                          &root_save_nestlevel);
 
@@ -955,8 +955,6 @@ DefineIndex(Oid tableId,
 
                if (stmt->primary)
                        constraint_type = "PRIMARY KEY";
-               else if (stmt->unique && stmt->istemporal)
-                       constraint_type = "temporal UNIQUE";
                else if (stmt->unique)
                        constraint_type = "UNIQUE";
                else if (stmt->excludeOpNames)
@@ -1006,7 +1004,7 @@ DefineIndex(Oid tableId,
                         * we have an exclusion constraint (or a temporal PK), 
it already
                         * knows the operators, so we don't have to infer them.
                         */
-                       if (stmt->unique && !stmt->istemporal && accessMethodId 
!= BTREE_AM_OID)
+                       if (stmt->unique && !stmt->iswithoutoverlaps && 
accessMethodId != BTREE_AM_OID)
                                ereport(ERROR,
                                                
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                 errmsg("cannot match partition 
key to an index using access method \"%s\"",
@@ -1039,7 +1037,7 @@ DefineIndex(Oid tableId,
                                        {
                                                Oid                     
idx_eqop = InvalidOid;
 
-                                               if (stmt->unique && 
!stmt->istemporal)
+                                               if (stmt->unique && 
!stmt->iswithoutoverlaps)
                                                        idx_eqop = 
get_opfamily_member(idx_opfamily,
                                                                                
                                   idx_opcintype,
                                                                                
                                   idx_opcintype,
@@ -1197,8 +1195,8 @@ DefineIndex(Oid tableId,
                constr_flags |= INDEX_CONSTR_CREATE_DEFERRABLE;
        if (stmt->initdeferred)
                constr_flags |= INDEX_CONSTR_CREATE_INIT_DEFERRED;
-       if (stmt->istemporal)
-               constr_flags |= INDEX_CONSTR_CREATE_TEMPORAL;
+       if (stmt->iswithoutoverlaps)
+               constr_flags |= INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS;
 
        indexRelationId =
                index_create(rel, indexRelationName, indexRelationId, 
parentIndexId,
@@ -1975,7 +1973,7 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
                                  Oid accessMethodId,
                                  bool amcanorder,
                                  bool isconstraint,
-                                 bool istemporal,
+                                 bool iswithoutoverlaps,
                                  Oid ddl_userid,
                                  int ddl_sec_context,
                                  int *ddl_save_nestlevel)
@@ -2000,7 +1998,7 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
                nextExclOp = NULL;
 
        /* exclusionOpNames can be non-NIL if we are creating a partition */
-       if (istemporal && exclusionOpNames == NIL)
+       if (iswithoutoverlaps && exclusionOpNames == NIL)
        {
                indexInfo->ii_ExclusionOps = palloc_array(Oid, nkeycols);
                indexInfo->ii_ExclusionProcs = palloc_array(Oid, nkeycols);
@@ -2283,7 +2281,7 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
                        indexInfo->ii_ExclusionStrats[attn] = strat;
                        nextExclOp = lnext(exclusionOpNames, nextExclOp);
                }
-               else if (istemporal)
+               else if (iswithoutoverlaps)
                {
                        int strat;
                        Oid opid;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 4cc645282a..04527a3540 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -208,7 +208,6 @@ typedef struct NewConstraint
        Oid                     refrelid;               /* PK rel, if FOREIGN */
        Oid                     refindid;               /* OID of PK's index, 
if FOREIGN */
        Oid                     conid;                  /* OID of pg_constraint 
entry, if FOREIGN */
-       bool            contemporal;    /* Whether the new constraint is 
temporal */
        Node       *qual;                       /* Check expr or CONSTR_FOREIGN 
Constraint */
        ExprState  *qualstate;          /* Execution state for CHECK expr */
 } NewConstraint;
@@ -10094,7 +10093,7 @@ addFkRecurseReferenced(List **wqueue, Constraint 
*fkconstraint, Relation rel,
                                                                          
conislocal,   /* islocal */
                                                                          
coninhcount,  /* inhcount */
                                                                          
connoinherit, /* conNoInherit */
-                                                                         
false,        /* conTemporal */
+                                                                         
false,        /* conWithoutOverlaps */
                                                                          
false);       /* is_internal */
 
        ObjectAddressSet(address, ConstraintRelationId, constrOid);
@@ -10393,7 +10392,7 @@ addFkRecurseReferencing(List **wqueue, Constraint 
*fkconstraint, Relation rel,
                                                                          false,
                                                                          1,
                                                                          false,
-                                                                         
false,        /* conTemporal */
+                                                                         
false,        /* conWithoutOverlaps */
                                                                          
false);
 
                        /*
@@ -10899,7 +10898,7 @@ CloneFkReferencing(List **wqueue, Relation parentRel, 
Relation partRel)
                                                                  false,        
/* islocal */
                                                                  1,    /* 
inhcount */
                                                                  false,        
/* conNoInherit */
-                                                                 false,        
/* conTemporal */
+                                                                 false,        
/* conWithoutOverlaps */
                                                                  true);
 
                /* Set up partition dependencies for the new constraint */
@@ -11574,7 +11573,6 @@ ATExecValidateConstraint(List **wqueue, Relation rel, 
char *constrName,
                        newcon->refrelid = con->confrelid;
                        newcon->refindid = con->conindid;
                        newcon->conid = con->oid;
-                       newcon->contemporal = con->contemporal;
                        newcon->qual = (Node *) fkconstraint;
 
                        /* Find or create work queue entry for this table */
@@ -11741,12 +11739,10 @@ transformColumnNameList(Oid relId, List *colList,
  *
  *     Look up the names, attnums, and types of the primary key attributes
  *     for the pkrel.  Also return the index OID and index opclasses of the
- *     index supporting the primary key.  If this is a temporal primary key,
- *     also set the WITHOUT OVERLAPS attribute name, attnum, and atttypid.
+ *     index supporting the primary key.
  *
  *     All parameters except pkrel are output parameters.  Also, the function
- *     return value is the number of attributes in the primary key,
- *     not including the WITHOUT OVERLAPS if any.
+ *     return value is the number of attributes in the primary key.
  *
  *     Used when the column list in the REFERENCES specification is omitted.
  */
@@ -14292,7 +14288,7 @@ TryReuseIndex(Oid oldId, IndexStmt *stmt)
                                                         stmt->accessMethod,
                                                         stmt->indexParams,
                                                         stmt->excludeOpNames,
-                                                        stmt->istemporal))
+                                                        
stmt->iswithoutoverlaps))
        {
                Relation        irel = index_open(oldId, NoLock);
 
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 0577b60415..a10a42b97f 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -841,7 +841,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char 
*queryString,
                                                                                
          true, /* islocal */
                                                                                
          0,    /* inhcount */
                                                                                
          true, /* noinherit */
-                                                                               
          false, /* contemporal */
+                                                                               
          false, /* conwithoutoverlaps */
                                                                                
          isInternal);  /* is_internal */
        }
 
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 1773556053..2470019818 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -3544,7 +3544,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, 
Oid baseTypeOid,
                                                          true, /* is local */
                                                          0,    /* inhcount */
                                                          false,        /* 
connoinherit */
-                                                         false,        /* 
contemporal */
+                                                         false,        /* 
conwithoutoverlaps */
                                                          false);       /* 
is_internal */
        if (constrAddr)
                ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 14d4e24fcc..ff4add6225 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -523,13 +523,12 @@ static Node *makeRecursiveViewSelect(char *relname, List 
*aliases, Node *query);
 %type <node>   TableElement TypedTableElement ConstraintElem TableFuncElement
 %type <node>   columnDef columnOptions
 %type <defelt> def_elem reloption_elem old_aggr_elem operator_def_elem
-%type <node>   def_arg columnElem without_overlaps_clause
-                               where_clause where_or_current_clause
+%type <node>   def_arg columnElem where_clause where_or_current_clause
                                a_expr b_expr c_expr AexprConst indirection_el 
opt_slice_bound
                                columnref in_expr having_clause func_table 
xmltable array_expr
                                OptWhereClause operator_def_arg
 %type <list>   rowsfrom_item rowsfrom_list opt_col_def_list
-%type <boolean> opt_ordinality
+%type <boolean> opt_ordinality opt_without_overlaps
 %type <list>   ExclusionConstraintList ExclusionConstraintElem
 %type <list>   func_arg_list func_arg_list_opt
 %type <node>   func_arg_expr
@@ -4105,7 +4104,7 @@ ConstraintElem:
                                        n->initially_valid = true;
                                        $$ = (Node *) n;
                                }
-                       | UNIQUE opt_unique_null_treatment '(' columnList 
without_overlaps_clause ')' opt_c_include opt_definition OptConsTableSpace
+                       | UNIQUE opt_unique_null_treatment '(' columnList 
opt_without_overlaps ')' opt_c_include opt_definition OptConsTableSpace
                                ConstraintAttributeSpec
                                {
                                        Constraint *n = makeNode(Constraint);
@@ -4140,7 +4139,7 @@ ConstraintElem:
                                                                   NULL, 
yyscanner);
                                        $$ = (Node *) n;
                                }
-                       | PRIMARY KEY '(' columnList without_overlaps_clause 
')' opt_c_include opt_definition OptConsTableSpace
+                       | PRIMARY KEY '(' columnList opt_without_overlaps ')' 
opt_c_include opt_definition OptConsTableSpace
                                ConstraintAttributeSpec
                                {
                                        Constraint *n = makeNode(Constraint);
@@ -4221,6 +4220,11 @@ opt_no_inherit:  NO INHERIT                              
                        {  $$ = true; }
                        | /* EMPTY */                                           
        {  $$ = false; }
                ;
 
+opt_without_overlaps:
+                       WITHOUT OVERLAPS                                        
        { $$ = true; }
+                       | /*EMPTY*/                                             
                { $$ = false; }
+       ;
+
 opt_column_list:
                        '(' columnList ')'                                      
        { $$ = $2; }
                        | /*EMPTY*/                                             
                { $$ = NIL; }
@@ -4231,11 +4235,6 @@ columnList:
                        | columnList ',' columnElem                             
{ $$ = lappend($1, $3); }
                ;
 
-without_overlaps_clause:
-                       ',' columnElem WITHOUT OVERLAPS { $$ = $2; }
-                       | /*EMPTY*/               { $$ = NULL; }
-       ;
-
 columnElem: ColId
                                {
                                        $$ = (Node *) makeString($1);
diff --git a/src/backend/parser/parse_utilcmd.c 
b/src/backend/parser/parse_utilcmd.c
index f4705ecc2b..547e3058b9 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -124,7 +124,7 @@ static List *get_opclass(Oid opclass, Oid actual_datatype);
 static void transformIndexConstraints(CreateStmtContext *cxt);
 static IndexStmt *transformIndexConstraint(Constraint *constraint,
                                                                                
   CreateStmtContext *cxt);
-static void validateWithoutOverlaps(CreateStmtContext *cxt, char *colname, int 
location);
+static void validateWithoutOverlaps(CreateStmtContext *cxt, const char 
*colname, int location);
 static void transformExtendedStatistics(CreateStmtContext *cxt);
 static void transformFKConstraints(CreateStmtContext *cxt,
                                                                   bool 
skipValidation,
@@ -1717,7 +1717,7 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation 
source_idx,
        index->unique = idxrec->indisunique;
        index->nulls_not_distinct = idxrec->indnullsnotdistinct;
        index->primary = idxrec->indisprimary;
-       index->istemporal = (idxrec->indisprimary || idxrec->indisunique) && 
idxrec->indisexclusion;
+       index->iswithoutoverlaps = (idxrec->indisprimary || 
idxrec->indisunique) && idxrec->indisexclusion;
        index->transformed = true;      /* don't need transformIndexStmt */
        index->concurrent = false;
        index->if_not_exists = false;
@@ -1768,7 +1768,7 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation 
source_idx,
                                int                     i;
 
                                Assert(conrec->contype == CONSTRAINT_EXCLUSION 
||
-                                               (index->istemporal &&
+                                               (index->iswithoutoverlaps &&
                                                 (conrec->contype == 
CONSTRAINT_PRIMARY || conrec->contype == CONSTRAINT_UNIQUE)));
                                /* Extract operator OIDs from the pg_constraint 
tuple */
                                datum = SysCacheGetAttrNotNull(CONSTROID, 
ht_constr,
@@ -2309,7 +2309,7 @@ transformIndexConstraint(Constraint *constraint, 
CreateStmtContext *cxt)
        }
        index->nulls_not_distinct = constraint->nulls_not_distinct;
        index->isconstraint = true;
-       index->istemporal = constraint->without_overlaps != NULL;
+       index->iswithoutoverlaps = constraint->without_overlaps;
        index->deferrable = constraint->deferrable;
        index->initdeferred = constraint->initdeferred;
 
@@ -2555,6 +2555,10 @@ transformIndexConstraint(Constraint *constraint, 
CreateStmtContext *cxt)
                        ListCell   *columns;
                        IndexElem  *iparam;
 
+                       /* handled below */
+                       if (constraint->without_overlaps && lc == 
list_last_cell(constraint->keys))
+                               break;
+
                        /* Make sure referenced column exists. */
                        foreach(columns, cxt->columns)
                        {
@@ -2688,11 +2692,21 @@ transformIndexConstraint(Constraint *constraint, 
CreateStmtContext *cxt)
                 * Anything in without_overlaps should be included,
                 * but with the overlaps operator (&&) instead of equality.
                 */
-               if (constraint->without_overlaps != NULL)
+               if (constraint->without_overlaps)
                {
-                       char *without_overlaps_str = 
strVal(constraint->without_overlaps);
+                       char *without_overlaps_str = 
strVal(llast(constraint->keys));
                        IndexElem *iparam = makeNode(IndexElem);
 
+                       /*
+                        * This enforces that there is at last one equality 
column besides
+                        * the WITHOUT OVERLAPS columns.  This is per SQL 
standard.  XXX
+                        * Do we need this?
+                        */
+                       if (list_length(constraint->keys) < 2)
+                               ereport(ERROR,
+                                               errcode(ERRCODE_SYNTAX_ERROR),
+                                               errmsg("constraint using 
WITHOUT OVERLAPS needs at least two columns"));
+
                        /*
                         * Iterate through the table's columns
                         * (like just a little bit above).
@@ -2855,7 +2869,7 @@ transformIndexConstraint(Constraint *constraint, 
CreateStmtContext *cxt)
  * and the new ones. Raises an error if we can't find one or it's not a range 
type.
  */
 static void
-validateWithoutOverlaps(CreateStmtContext *cxt, char *colname, int location)
+validateWithoutOverlaps(CreateStmtContext *cxt, const char *colname, int 
location)
 {
        /* Check the new columns first in case their type is changing. */
 
diff --git a/src/backend/utils/adt/ruleutils.c 
b/src/backend/utils/adt/ruleutils.c
index f2da27eb50..25ac0ad1bc 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -338,7 +338,7 @@ static char *deparse_expression_pretty(Node *expr, List 
*dpcontext,
 static char *pg_get_viewdef_worker(Oid viewoid,
                                                                   int 
prettyFlags, int wrapColumn);
 static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
-static int     decompile_column_index_array(Datum column_index_array, Oid 
relId, Oid indexId,
+static int     decompile_column_index_array(Datum column_index_array, Oid 
relId,
                                                                                
 bool withoutOverlaps, StringInfo buf);
 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
 static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
@@ -2247,7 +2247,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool 
fullCommand,
                                val = SysCacheGetAttrNotNull(CONSTROID, tup,
                                                                                
         Anum_pg_constraint_conkey);
 
-                               decompile_column_index_array(val, 
conForm->conrelid, conForm->conindid, false, &buf);
+                               decompile_column_index_array(val, 
conForm->conrelid, false, &buf);
 
                                /* add foreign relation name */
                                appendStringInfo(&buf, ") REFERENCES %s(",
@@ -2258,7 +2258,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool 
fullCommand,
                                val = SysCacheGetAttrNotNull(CONSTROID, tup,
                                                                                
         Anum_pg_constraint_confkey);
 
-                               decompile_column_index_array(val, 
conForm->confrelid, conForm->conindid, false, &buf);
+                               decompile_column_index_array(val, 
conForm->confrelid, false, &buf);
 
                                appendStringInfoChar(&buf, ')');
 
@@ -2344,7 +2344,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool 
fullCommand,
                                if (!isnull)
                                {
                                        appendStringInfoString(&buf, " (");
-                                       decompile_column_index_array(val, 
conForm->conrelid, InvalidOid, false, &buf);
+                                       decompile_column_index_array(val, 
conForm->conrelid, false, &buf);
                                        appendStringInfoChar(&buf, ')');
                                }
 
@@ -2357,7 +2357,6 @@ pg_get_constraintdef_worker(Oid constraintId, bool 
fullCommand,
                                Oid                     indexId;
                                int                     keyatts;
                                HeapTuple       indtup;
-                               bool            isnull;
 
                                /* Start off the constraint definition */
                                if (conForm->contype == CONSTRAINT_PRIMARY)
@@ -2380,14 +2379,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool 
fullCommand,
                                val = SysCacheGetAttrNotNull(CONSTROID, tup,
                                                                                
         Anum_pg_constraint_conkey);
 
-                               /*
-                                * If it has exclusion-style operator OIDs
-                                * then it uses WITHOUT OVERLAPS.
-                                */
-                               indexId = conForm->conindid;
-                               SysCacheGetAttr(CONSTROID, tup,
-                                                 Anum_pg_constraint_conexclop, 
&isnull);
-                               keyatts = decompile_column_index_array(val, 
conForm->conrelid, indexId, !isnull, &buf);
+                               keyatts = decompile_column_index_array(val, 
conForm->conrelid, conForm->conwithoutoverlaps, &buf);
 
                                appendStringInfoChar(&buf, ')');
 
@@ -2582,7 +2574,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool 
fullCommand,
  * of keys.
  */
 static int
-decompile_column_index_array(Datum column_index_array, Oid relId, Oid indexId,
+decompile_column_index_array(Datum column_index_array, Oid relId,
                                                         bool withoutOverlaps, 
StringInfo buf)
 {
        Datum      *keys;
@@ -2596,17 +2588,16 @@ decompile_column_index_array(Datum column_index_array, 
Oid relId, Oid indexId,
        for (j = 0; j < nKeys; j++)
        {
                char       *colName;
-               int                     colid = DatumGetInt16(keys[j]);
 
-               colName = get_attname(relId, colid, false);
+               colName = get_attname(relId, DatumGetInt16(keys[j]), false);
 
                if (j == 0)
                        appendStringInfoString(buf, quote_identifier(colName));
-               else if (withoutOverlaps && j == nKeys - 1)
-                       appendStringInfo(buf, ", %s WITHOUT OVERLAPS", 
quote_identifier(colName));
                else
                        appendStringInfo(buf, ", %s", 
quote_identifier(colName));
        }
+       if (withoutOverlaps)
+               appendStringInfoString(buf, " WITHOUT OVERLAPS");
 
        return nKeys;
 }
diff --git a/src/backend/utils/cache/relcache.c 
b/src/backend/utils/cache/relcache.c
index 45810ac35f..f341c5c370 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -5568,12 +5568,14 @@ RelationGetIdentityKeyBitmap(Relation relation)
 /*
  * RelationGetExclusionInfo -- get info about index's exclusion constraint
  *
- * This should be called only for an index that is known to have an
- * associated exclusion constraint or temporal primary key/unique
- * constraint. It returns arrays (palloc'd in caller's context)
- * of the exclusion operator OIDs, their underlying functions'
- * OIDs, and their strategy numbers in the index's opclasses.  We cache
- * all this information since it requires a fair amount of work to get.
+ * This should be called only for an index that is known to have an associated
+ * exclusion constraint or primary key/unique constraint using WITHOUT
+ * OVERLAPS.
+
+ * It returns arrays (palloc'd in caller's context) of the exclusion operator
+ * OIDs, their underlying functions' OIDs, and their strategy numbers in the
+ * index's opclasses.  We cache all this information since it requires a fair
+ * amount of work to get.
  */
 void
 RelationGetExclusionInfo(Relation indexRelation,
@@ -5638,7 +5640,7 @@ RelationGetExclusionInfo(Relation indexRelation,
 
                /* We want the exclusion constraint owning the index */
                if ((conform->contype != CONSTRAINT_EXCLUSION &&
-                                       !(conform->contemporal && (
+                                       !(conform->conwithoutoverlaps && (
                                                        conform->contype == 
CONSTRAINT_PRIMARY
                                                        || conform->contype == 
CONSTRAINT_UNIQUE))) ||
                        conform->conindid != RelationGetRelid(indexRelation))
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 54a15cf64a..c89b6da8b2 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -6983,14 +6983,14 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int 
numTables)
                                i_conname,
                                i_condeferrable,
                                i_condeferred,
+                               i_conwithoutoverlaps,
                                i_contableoid,
                                i_conoid,
                                i_condef,
                                i_tablespace,
                                i_indreloptions,
                                i_indstatcols,
-                               i_indstatvals,
-                               i_withoutoverlaps;
+                               i_indstatvals;
 
        /*
         * We want to perform just one query against pg_index.  However, we
@@ -7072,10 +7072,10 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int 
numTables)
 
        if (fout->remoteVersion >= 170000)
                appendPQExpBufferStr(query,
-                                                        "c.conexclop IS NOT 
NULL AS withoutoverlaps ");
+                                                        "c.conwithoutoverlaps 
");
        else
                appendPQExpBufferStr(query,
-                                                        "null AS 
withoutoverlaps ");
+                                                        "NULL AS 
conwithoutoverlaps ");
 
        /*
         * The point of the messy-looking outer join is to find a constraint 
that
@@ -7143,6 +7143,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int 
numTables)
        i_conname = PQfnumber(res, "conname");
        i_condeferrable = PQfnumber(res, "condeferrable");
        i_condeferred = PQfnumber(res, "condeferred");
+       i_conwithoutoverlaps = PQfnumber(res, "conwithoutoverlaps");
        i_contableoid = PQfnumber(res, "contableoid");
        i_conoid = PQfnumber(res, "conoid");
        i_condef = PQfnumber(res, "condef");
@@ -7150,7 +7151,6 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int 
numTables)
        i_indreloptions = PQfnumber(res, "indreloptions");
        i_indstatcols = PQfnumber(res, "indstatcols");
        i_indstatvals = PQfnumber(res, "indstatvals");
-       i_withoutoverlaps = PQfnumber(res, "withoutoverlaps");
 
        indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
 
@@ -7251,9 +7251,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int 
numTables)
                                constrinfo->conindex = indxinfo[j].dobj.dumpId;
                                constrinfo->condeferrable = *(PQgetvalue(res, 
j, i_condeferrable)) == 't';
                                constrinfo->condeferred = *(PQgetvalue(res, j, 
i_condeferred)) == 't';
+                               constrinfo->conwithoutoverlaps = 
*(PQgetvalue(res, j, i_conwithoutoverlaps)) == 't';
                                constrinfo->conislocal = true;
                                constrinfo->separate = true;
-                               constrinfo->withoutoverlaps = *(PQgetvalue(res, 
j, i_withoutoverlaps)) == 't';
 
                                indxinfo[j].indexconstraint = 
constrinfo->dobj.dumpId;
                        }
@@ -16949,23 +16949,12 @@ dumpConstraint(Archive *fout, const ConstraintInfo 
*coninfo)
                                        break;
                                attname = getAttrName(indkey, tbinfo);
 
-                               if (k == 0)
-                               {
-                                       appendPQExpBuffer(q, "%s",
-                                                                               
fmtId(attname));
-                               }
-                               else if (k == indxinfo->indnkeyattrs - 1 &&
-                                               coninfo->withoutoverlaps)
-                               {
-                                       appendPQExpBuffer(q, ", %s WITHOUT 
OVERLAPS",
-                                                                         
fmtId(attname));
-                               }
-                               else
-                               {
-                                       appendPQExpBuffer(q, ", %s",
-                                                                               
fmtId(attname));
-                               }
+                               appendPQExpBuffer(q, "%s%s",
+                                                                 (k == 0) ? "" 
: ", ",
+                                                                 
fmtId(attname));
                        }
+                       if (coninfo->conwithoutoverlaps)
+                               appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
 
                        if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
                                appendPQExpBufferStr(q, ") INCLUDE (");
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index ad7cc85b8c..cbf4b5e179 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -487,9 +487,9 @@ typedef struct _constraintInfo
        DumpId          conindex;               /* identifies associated index 
if any */
        bool            condeferrable;  /* true if constraint is DEFERRABLE */
        bool            condeferred;    /* true if constraint is INITIALLY 
DEFERRED */
+       bool            conwithoutoverlaps;     /* true if the constraint is 
WITHOUT OVERLAPS */
        bool            conislocal;             /* true if constraint has local 
definition */
        bool            separate;               /* true if must dump as 
separate item */
-       bool            withoutoverlaps;        /* true if the last elem is 
WITHOUT OVERLAPS */
 } ConstraintInfo;
 
 typedef struct _procLangInfo
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index eb35d5ef60..8584a4b406 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -1015,12 +1015,11 @@
                },
        },
 
-       'ALTER TABLE ONLY test_table_tpk ADD CONSTRAINT ... PRIMARY KEY (..., 
... WITHOUT OVERLAPS)' => {
+       'CONSTRAINT PRIMARY KEY / WITHOUT OVERLAPS' => {
                create_sql  => 'CREATE TABLE dump_test.test_table_tpk (
                                                        col1 int4range,
                                                        col2 tstzrange,
-                                                       CONSTRAINT 
test_table_tpk_pkey PRIMARY KEY
-                                                               (col1, col2 
WITHOUT OVERLAPS));',
+                                                       CONSTRAINT 
test_table_tpk_pkey PRIMARY KEY (col1, col2 WITHOUT OVERLAPS));',
                regexp => qr/^
                        \QALTER TABLE ONLY dump_test.test_table_tpk\E \n^\s+
                        \QADD CONSTRAINT test_table_tpk_pkey PRIMARY KEY (col1, 
col2 WITHOUT OVERLAPS);\E
@@ -1029,21 +1028,18 @@
                        %full_runs,
                        %dump_test_schema_runs,
                        section_post_data  => 1,
-                       exclude_test_table => 1,
                },
                unlike => {
-                       only_dump_test_table     => 1,
                        exclude_dump_test_schema => 1,
                        only_dump_measurement    => 1,
                },
        },
 
-       'ALTER TABLE ONLY test_table_tuq ADD CONSTRAINT ... UNIQUE (..., ... 
WITHOUT OVERLAPS)' => {
+       'CONSTRAINT UNIQUE / WITHOUT OVERLAPS' => {
                create_sql  => 'CREATE TABLE dump_test.test_table_tuq (
                                                        col1 int4range,
                                                        col2 tstzrange,
-                                                       CONSTRAINT 
test_table_tuq_uq UNIQUE
-                                                               (col1, col2 
WITHOUT OVERLAPS));',
+                                                       CONSTRAINT 
test_table_tuq_uq UNIQUE (col1, col2 WITHOUT OVERLAPS));',
                regexp => qr/^
                        \QALTER TABLE ONLY dump_test.test_table_tuq\E \n^\s+
                        \QADD CONSTRAINT test_table_tuq_uq UNIQUE (col1, col2 
WITHOUT OVERLAPS);\E
@@ -1052,10 +1048,8 @@
                        %full_runs,
                        %dump_test_schema_runs,
                        section_post_data  => 1,
-                       exclude_test_table => 1,
                },
                unlike => {
-                       only_dump_test_table     => 1,
                        exclude_dump_test_schema => 1,
                        only_dump_measurement    => 1,
                },
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 4fbfc07460..135585411a 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -2384,10 +2384,10 @@ describeOneTableDetails(const char *schemaname,
                        else
                                appendPQExpBufferStr(&buf, ", false AS 
indisreplident");
                        appendPQExpBufferStr(&buf, ", c2.reltablespace");
-                       if (pset.sversion >= 160000)
-                               appendPQExpBufferStr(&buf, ", con.contemporal");
+                       if (pset.sversion >= 170000)
+                               appendPQExpBufferStr(&buf, ", 
con.conwithoutoverlaps");
                        else
-                               appendPQExpBufferStr(&buf, ", false AS 
contemporal");
+                               appendPQExpBufferStr(&buf, ", false AS 
conwithoutoverlaps");
                        appendPQExpBuffer(&buf,
                                                          "\nFROM 
pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n"
                                                          "  LEFT JOIN 
pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = 
i.indexrelid AND contype IN ('p','u','x'))\n"
@@ -2410,8 +2410,8 @@ describeOneTableDetails(const char *schemaname,
                                                                          
PQgetvalue(result, i, 0));
 
                                        /*
-                                        * If exclusion constraint or temporal 
PK/UNIQUE constraint,
-                                        * print the constraintdef
+                                        * If exclusion constraint or PK/UNIQUE 
constraint WITHOUT
+                                        * OVERLAPS, print the constraintdef
                                         */
                                        if (strcmp(PQgetvalue(result, i, 7), 
"x") == 0 ||
                                                        
strcmp(PQgetvalue(result, i, 12), "t") == 0)
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 1a858c3897..0fccff9c05 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -92,7 +92,7 @@ extern Oid    index_create(Relation heapRelation,
 #define        INDEX_CONSTR_CREATE_INIT_DEFERRED       (1 << 2)
 #define        INDEX_CONSTR_CREATE_UPDATE_INDEX        (1 << 3)
 #define        INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS     (1 << 4)
-#define        INDEX_CONSTR_CREATE_TEMPORAL            (1 << 5)
+#define        INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS (1 << 5)
 
 extern Oid     index_concurrently_create_copy(Relation heapRelation,
                                                                                
   Oid oldIndexId,
diff --git a/src/include/catalog/pg_constraint.h 
b/src/include/catalog/pg_constraint.h
index 98a560741d..c17b1e9d31 100644
--- a/src/include/catalog/pg_constraint.h
+++ b/src/include/catalog/pg_constraint.h
@@ -108,10 +108,10 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
        bool            connoinherit;
 
        /*
-        * For primary and foreign keys, signifies the last column is a range
-        * and should use overlaps instead of equals.
+        * For primary keys and unique constraints, signifies the last column 
uses
+        * overlaps instead of equals.
         */
-       bool            contemporal;
+       bool            conwithoutoverlaps;
 
 #ifdef CATALOG_VARLEN                  /* variable-length fields start here */
 
@@ -152,7 +152,8 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
 
        /*
         * If an exclusion constraint, the OIDs of the exclusion operators for
-        * each column of the constraint. Also set for temporal primary keys.
+        * each column of the constraint.  Also set for unique 
constraints/primary
+        * keys using WITHOUT OVERLAPS.
         */
        Oid                     conexclop[1] BKI_LOOKUP(pg_operator);
 
@@ -242,7 +243,7 @@ extern Oid  CreateConstraintEntry(const char 
*constraintName,
                                                                  bool 
conIsLocal,
                                                                  int 
conInhCount,
                                                                  bool 
conNoInherit,
-                                                                 bool 
conTemporal,
+                                                                 bool 
conWithoutOverlaps,
                                                                  bool 
is_internal);
 
 extern bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index f10886f6ca..25f55c181b 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -45,7 +45,7 @@ extern bool CheckIndexCompatible(Oid oldId,
                                                                 const char 
*accessMethodName,
                                                                 const List 
*attributeList,
                                                                 const List 
*exclusionOpNames,
-                                                                bool 
istemporal);
+                                                                bool 
isWithoutOverlaps);
 extern Oid     GetDefaultOpClass(Oid type_id, Oid am_id);
 extern Oid     ResolveOpClass(const List *opclass, Oid attrType,
                                                   const char 
*accessMethodName, Oid accessMethodId);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index ff65db2db1..098990dd16 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2589,6 +2589,7 @@ typedef struct Constraint
        bool            nulls_not_distinct; /* null treatment for UNIQUE 
constraints */
        List       *keys;                       /* String nodes naming 
referenced key
                                                                 * column(s); 
also used for NOT NULL */
+       bool            without_overlaps;       /* WITHOUT OVERLAPS specified */
        List       *including;          /* String nodes naming referenced nonkey
                                                                 * column(s) */
 
@@ -2617,9 +2618,6 @@ typedef struct Constraint
        Oid                     old_pktable_oid;        /* 
pg_constraint.confrelid of my former
                                                                         * self 
*/
 
-       /* Fields used for temporal PRIMARY KEY and FOREIGN KEY constraints: */
-       Node       *without_overlaps; /* String node naming range column */
-
        /* Fields used for constraints that allow a NOT VALID specification */
        bool            skip_validation;        /* skip validation of existing 
rows? */
        bool            initially_valid;        /* mark the new constraint as 
valid? */
@@ -3221,7 +3219,7 @@ typedef struct IndexStmt
        bool            nulls_not_distinct; /* null treatment for UNIQUE 
constraints */
        bool            primary;                /* is index a primary key? */
        bool            isconstraint;   /* is it for a pkey/unique constraint? 
*/
-       bool            istemporal;             /* is it for a temporal pkey? */
+       bool            iswithoutoverlaps;      /* is the constraint WITHOUT 
OVERLAPS? */
        bool            deferrable;             /* is the constraint 
DEFERRABLE? */
        bool            initdeferred;   /* is the constraint INITIALLY 
DEFERRED? */
        bool            transformed;    /* true when transformIndexStmt is 
finished */
diff --git a/src/test/regress/expected/without_overlaps.out 
b/src/test/regress/expected/without_overlaps.out
index 36aebc452f..e565490a38 100644
--- a/src/test/regress/expected/without_overlaps.out
+++ b/src/test/regress/expected/without_overlaps.out
@@ -11,9 +11,7 @@ CREATE TABLE temporal_rng (
        valid_at tsrange,
        CONSTRAINT temporal_rng_pk PRIMARY KEY (valid_at WITHOUT OVERLAPS)
 );
-ERROR:  syntax error at or near "WITHOUT"
-LINE 3:  CONSTRAINT temporal_rng_pk PRIMARY KEY (valid_at WITHOUT OV...
-                                                          ^
+ERROR:  constraint using WITHOUT OVERLAPS needs at least two columns
 -- PK with a range column/PERIOD that isn't there:
 CREATE TABLE temporal_rng (
        id INTEGER,
@@ -106,9 +104,7 @@ CREATE TABLE temporal_rng3 (
        valid_at tsrange,
        CONSTRAINT temporal_rng3_uq UNIQUE (valid_at WITHOUT OVERLAPS)
 );
-ERROR:  syntax error at or near "WITHOUT"
-LINE 3:  CONSTRAINT temporal_rng3_uq UNIQUE (valid_at WITHOUT OVERLA...
-                                                      ^
+ERROR:  constraint using WITHOUT OVERLAPS needs at least two columns
 -- UNIQUE with a range column/PERIOD that isn't there:
 CREATE TABLE temporal_rng3 (
        id INTEGER,
diff --git a/src/test/regress/parallel_schedule 
b/src/test/regress/parallel_schedule
index 16683148d2..b08aaae44b 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -28,7 +28,7 @@ test: strings md5 numerology point lseg line box path polygon 
circle date time t
 # geometry depends on point, lseg, line, box, path, polygon, circle
 # horology depends on date, time, timetz, timestamp, timestamptz, interval
 # ----------
-test: geometry horology tstypes regex type_sanity opr_sanity misc_sanity 
comments expressions unicode xid mvcc without_overlaps
+test: geometry horology tstypes regex type_sanity opr_sanity misc_sanity 
comments expressions unicode xid mvcc
 
 # ----------
 # Load huge amounts of data
@@ -78,7 +78,7 @@ test: brin_bloom brin_multi
 # psql depends on create_am
 # amutils depends on geometry, create_index_spgist, hash_index, brin
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge 
misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 
incremental_sort create_role
+test: create_table_like alter_generic alter_operator misc async dbsize merge 
misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 
incremental_sort create_role without_overlaps
 
 # collate.*.utf8 tests cannot be run in parallel with each other
 test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8 
collate.windows.win1252
-- 
2.42.0

Reply via email to