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
+ &&)</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
&&)</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