From 1399762bebd7fb4930142cd66b5fc1e9e50cb3dc Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Wed, 15 May 2024 10:51:59 +0200 Subject: [PATCH 09/10] Revert "Add temporal PRIMARY KEY and UNIQUE constraints" This reverts commit 46a0cd4cefb4d9b462d8cc4df5e7ecdd190bea92. --- contrib/btree_gist/Makefile | 2 +- .../btree_gist/expected/without_overlaps.out | 44 -- contrib/btree_gist/meson.build | 1 - contrib/btree_gist/sql/without_overlaps.sql | 25 -- doc/src/sgml/catalogs.sgml | 10 - doc/src/sgml/gist.sgml | 14 +- doc/src/sgml/ref/create_table.sgml | 49 +-- src/backend/access/gist/gistutil.c | 29 -- src/backend/catalog/heap.c | 1 - src/backend/catalog/index.c | 4 - src/backend/catalog/pg_constraint.c | 2 - src/backend/commands/indexcmds.c | 143 +------ src/backend/commands/tablecmds.c | 6 +- src/backend/commands/trigger.c | 1 - src/backend/commands/typecmds.c | 2 - src/backend/parser/gram.y | 29 +- src/backend/parser/parse_utilcmd.c | 28 +- src/backend/utils/adt/ruleutils.c | 2 - src/backend/utils/cache/relcache.c | 18 +- src/bin/pg_dump/pg_dump.c | 16 +- src/bin/pg_dump/pg_dump.h | 2 - src/bin/pg_dump/t/002_pg_dump.pl | 36 -- src/bin/psql/describe.c | 12 +- src/include/access/gist.h | 3 - src/include/catalog/catversion.h | 2 +- src/include/catalog/index.h | 1 - src/include/catalog/pg_constraint.h | 10 +- src/include/commands/defrem.h | 6 +- src/include/nodes/parsenodes.h | 2 - .../regress/expected/without_overlaps.out | 395 ------------------ src/test/regress/parallel_schedule | 2 +- src/test/regress/sql/without_overlaps.sql | 290 ------------- 32 files changed, 54 insertions(+), 1133 deletions(-) delete mode 100644 contrib/btree_gist/expected/without_overlaps.out delete mode 100644 contrib/btree_gist/sql/without_overlaps.sql delete mode 100644 src/test/regress/expected/without_overlaps.out delete mode 100644 src/test/regress/sql/without_overlaps.sql diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile index 7ac2df26c10..9ab8548bc0e 100644 --- a/contrib/btree_gist/Makefile +++ b/contrib/btree_gist/Makefile @@ -40,7 +40,7 @@ PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes" REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \ time timetz date interval macaddr macaddr8 inet cidr text varchar char \ bytea bit varbit numeric uuid not_equal enum bool partitions \ - stratnum without_overlaps + stratnum SHLIB_LINK += $(filter -lm, $(LIBS)) diff --git a/contrib/btree_gist/expected/without_overlaps.out b/contrib/btree_gist/expected/without_overlaps.out deleted file mode 100644 index be52c522e89..00000000000 --- a/contrib/btree_gist/expected/without_overlaps.out +++ /dev/null @@ -1,44 +0,0 @@ --- Core must test WITHOUT OVERLAPS --- with an int4range + daterange, --- so here we do some simple tests --- to make sure int + daterange works too, --- since that is the expected use-case. -CREATE TABLE temporal_rng ( - id integer, - valid_at daterange, - CONSTRAINT temporal_rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -\d temporal_rng - Table "public.temporal_rng" - Column | Type | Collation | Nullable | Default -----------+-----------+-----------+----------+--------- - id | integer | | not null | - valid_at | daterange | | not null | -Indexes: - "temporal_rng_pk" PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) - -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_rng_pk'; - pg_get_constraintdef ---------------------------------------------- - PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -(1 row) - -SELECT pg_get_indexdef(conindid, 0, true) FROM pg_constraint WHERE conname = 'temporal_rng_pk'; - pg_get_indexdef -------------------------------------------------------------------------------- - CREATE UNIQUE INDEX temporal_rng_pk ON temporal_rng USING gist (id, valid_at) -(1 row) - -INSERT INTO temporal_rng VALUES - (1, '[2000-01-01,2001-01-01)'); --- same key, doesn't overlap: -INSERT INTO temporal_rng VALUES - (1, '[2001-01-01,2002-01-01)'); --- overlaps but different key: -INSERT INTO temporal_rng VALUES - (2, '[2000-01-01,2001-01-01)'); --- should fail: -INSERT INTO temporal_rng VALUES - (1, '[2000-06-01,2001-01-01)'); -ERROR: conflicting key value violates exclusion constraint "temporal_rng_pk" -DETAIL: Key (id, valid_at)=(1, [06-01-2000,01-01-2001)) conflicts with existing key (id, valid_at)=(1, [01-01-2000,01-01-2001)). diff --git a/contrib/btree_gist/meson.build b/contrib/btree_gist/meson.build index 73b1bbf52a6..a44ce905e59 100644 --- a/contrib/btree_gist/meson.build +++ b/contrib/btree_gist/meson.build @@ -91,7 +91,6 @@ tests += { 'bool', 'partitions', 'stratnum', - 'without_overlaps', ], }, } diff --git a/contrib/btree_gist/sql/without_overlaps.sql b/contrib/btree_gist/sql/without_overlaps.sql deleted file mode 100644 index 433c609ab22..00000000000 --- a/contrib/btree_gist/sql/without_overlaps.sql +++ /dev/null @@ -1,25 +0,0 @@ --- Core must test WITHOUT OVERLAPS --- with an int4range + daterange, --- so here we do some simple tests --- to make sure int + daterange works too, --- since that is the expected use-case. -CREATE TABLE temporal_rng ( - id integer, - valid_at daterange, - CONSTRAINT temporal_rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -\d temporal_rng -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_rng_pk'; -SELECT pg_get_indexdef(conindid, 0, true) FROM pg_constraint WHERE conname = 'temporal_rng_pk'; - -INSERT INTO temporal_rng VALUES - (1, '[2000-01-01,2001-01-01)'); --- same key, doesn't overlap: -INSERT INTO temporal_rng VALUES - (1, '[2001-01-01,2002-01-01)'); --- overlaps but different key: -INSERT INTO temporal_rng VALUES - (2, '[2000-01-01,2001-01-01)'); --- should fail: -INSERT INTO temporal_rng VALUES - (1, '[2000-06-01,2001-01-01)'); diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 3e945c0590f..15f6255d865 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -2729,16 +2729,6 @@ <structname>pg_constraint</structname> Columns - - - conwithoutoverlaps bool - - - This constraint is defined with WITHOUT OVERLAPS - (for primary keys and unique constraints). - - - conkey int2[] diff --git a/doc/src/sgml/gist.sgml b/doc/src/sgml/gist.sgml index dcf9433fa78..f789824c83b 100644 --- a/doc/src/sgml/gist.sgml +++ b/doc/src/sgml/gist.sgml @@ -292,8 +292,7 @@ Extensibility The optional twelfth method stratnum is used to translate well-known RT*StrategyNumbers (from src/include/access/stratnum.h) into strategy numbers - used by the operator class. This lets the core code look up operators for - temporal constraint indexes. + used by the operator class. @@ -1180,17 +1179,6 @@ Extensibility operator class has no matching strategy. - - This is used for temporal index constraints (i.e., PRIMARY - KEY and UNIQUE). If the operator class - provides this function and it returns results for - RTEqualStrategyNumber, it can be used in the - non-WITHOUT OVERLAPS part(s) of an index constraint. - If it returns results for RTOverlapStrategyNumber, - the operator class can be used in the WITHOUT - OVERLAPS part of an index constraint. - - The SQL declaration of the function must look like this: diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index a77303af776..f19306e7760 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -77,8 +77,8 @@ [ CONSTRAINT constraint_name ] { CHECK ( expression ) [ NO INHERIT ] | - UNIQUE [ NULLS [ NOT ] DISTINCT ] ( column_name [, ... ] [, column_name WITHOUT OVERLAPS ] ) index_parameters | - PRIMARY KEY ( column_name [, ... ] [, column_name WITHOUT OVERLAPS ] ) index_parameters | + UNIQUE [ NULLS [ NOT ] DISTINCT ] ( column_name [, ... ] ) index_parameters | + PRIMARY KEY ( column_name [, ... ] ) index_parameters | EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] ) index_parameters [ WHERE ( predicate ) ] | FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE Parameters UNIQUE [ NULLS [ NOT ] DISTINCT ] (column constraint) - UNIQUE [ NULLS [ NOT ] DISTINCT ] ( column_name [, ... ] [, column_name WITHOUT OVERLAPS ] ) + UNIQUE [ NULLS [ NOT ] DISTINCT ] ( column_name [, ... ] ) INCLUDE ( column_name [, ...]) (table constraint) @@ -978,30 +978,6 @@ Parameters of these columns. - - If the WITHOUT OVERLAPS 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 - WITHOUT OVERLAPS 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 EXCLUDE constraint - rather than a UNIQUE constraint. So for example - UNIQUE (id, valid_at WITHOUT OVERLAPS) behaves like - EXCLUDE USING GIST (id WITH =, valid_at WITH - &&). The WITHOUT OVERLAPS column - must have a range or multirange type. (Technically, any type is allowed - whose default GiST opclass includes an overlaps operator. See the - stratnum support function under for details.) The non-WITHOUT - OVERLAPS 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 extension (which is the expected way to use this - feature). - - For the purpose of a unique constraint, null values are not considered equal, unless NULLS NOT DISTINCT is @@ -1023,11 +999,9 @@ Parameters - Adding a unique constraint will automatically create a unique B-tree - index on the column or group of columns used in the constraint. But if - the constraint includes a WITHOUT OVERLAPS clause, it - will use a GiST index. The created index has the same name as the unique - constraint. + Adding a unique constraint will automatically create a unique btree + index on the column or group of columns used in the constraint. The + created index has the same name as the unique constraint. @@ -1045,7 +1019,7 @@ Parameters PRIMARY KEY (column constraint) - PRIMARY KEY ( column_name [, ... ] [, column_name WITHOUT OVERLAPS ] ) + PRIMARY KEY ( column_name [, ... ] ) INCLUDE ( column_name [, ...]) (table constraint) @@ -1078,11 +1052,10 @@ Parameters - As with a UNIQUE constraint, adding a - PRIMARY KEY constraint will automatically create a - unique B-tree index, or GiST if WITHOUT OVERLAPS was - specified, on the column or group of columns used in the constraint. - That index has the same name as the primary key constraint. + Adding a PRIMARY KEY constraint will automatically + create a unique btree index on the column or group of columns used in + the constraint. That index has the same name as the primary key + constraint. diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index d2d0b36d4ea..8686735f234 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -1069,32 +1069,3 @@ gist_stratnum_identity(PG_FUNCTION_ARGS) PG_RETURN_UINT16(strat); } - -/* - * Returns the opclass's private stratnum used for the given strategy. - * - * Calls the opclass's GIST_STRATNUM_PROC support function, if any, - * and returns the result. - * Returns InvalidStrategy if the function is not defined. - */ -StrategyNumber -GistTranslateStratnum(Oid opclass, StrategyNumber strat) -{ - Oid opfamily; - Oid opcintype; - Oid funcid; - Datum result; - - /* Look up the opclass family and input datatype. */ - if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype)) - return InvalidStrategy; - - /* Check whether the function is provided. */ - funcid = get_opfamily_proc(opfamily, opcintype, opcintype, GIST_STRATNUM_PROC); - if (!OidIsValid(funcid)) - return InvalidStrategy; - - /* Ask the translation function */ - result = OidFunctionCall1Coll(funcid, InvalidOid, UInt16GetDatum(strat)); - return DatumGetUInt16(result); -} diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 91d27a36798..a122bbffce7 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -2155,7 +2155,6 @@ StoreRelCheck(Relation rel, const char *ccname, Node *expr, is_local, /* conislocal */ inhcount, /* coninhcount */ is_no_inherit, /* connoinherit */ - false, /* conwithoutoverlaps */ is_internal); /* internally constructed? */ pfree(ccbin); diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 5a8568c55c9..55fdde4b242 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -1873,7 +1873,6 @@ 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_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 */ @@ -1897,13 +1896,11 @@ index_constraint_create(Relation heapRelation, bool mark_as_primary; bool islocal; bool noinherit; - 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_without_overlaps = (constr_flags & INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS) != 0; /* constraint creation support doesn't work while bootstrapping */ Assert(!IsBootstrapProcessingMode()); @@ -1980,7 +1977,6 @@ index_constraint_create(Relation heapRelation, islocal, inhcount, noinherit, - is_without_overlaps, is_internal); /* diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index 88284fafe89..3baf9231ed0 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -75,7 +75,6 @@ CreateConstraintEntry(const char *constraintName, bool conIsLocal, int conInhCount, bool conNoInherit, - bool conWithoutOverlaps, bool is_internal) { Relation conDesc; @@ -191,7 +190,6 @@ 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_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 7b20d103c86..309389e20d2 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -16,7 +16,6 @@ #include "postgres.h" #include "access/amapi.h" -#include "access/gist.h" #include "access/heapam.h" #include "access/htup_details.h" #include "access/reloptions.h" @@ -88,7 +87,6 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid accessMethodId, bool amcanorder, bool isconstraint, - bool iswithoutoverlaps, Oid ddl_userid, int ddl_sec_context, int *ddl_save_nestlevel); @@ -147,7 +145,6 @@ typedef struct ReindexErrorInfo * to index on. * 'exclusionOpNames': list of names of exclusion-constraint operators, * or NIL if not an exclusion constraint. - * '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 @@ -177,8 +174,7 @@ bool CheckIndexCompatible(Oid oldId, const char *accessMethodName, const List *attributeList, - const List *exclusionOpNames, - bool isWithoutOverlaps) + const List *exclusionOpNames) { bool isconstraint; Oid *typeIds; @@ -253,8 +249,8 @@ CheckIndexCompatible(Oid oldId, coloptions, attributeList, exclusionOpNames, relationId, accessMethodName, accessMethodId, - amcanorder, isconstraint, isWithoutOverlaps, InvalidOid, - 0, NULL); + amcanorder, isconstraint, InvalidOid, 0, NULL); + /* Get the soon-obsolete pg_index tuple. */ tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(oldId)); @@ -564,7 +560,6 @@ DefineIndex(Oid tableId, bool amcanorder; bool amissummarizing; amoptions_function amoptions; - bool exclusion; bool partitioned; bool safe_index; Datum reloptions; @@ -685,12 +680,6 @@ DefineIndex(Oid tableId, namespaceId = RelationGetNamespace(rel); - /* - * It has exclusion constraint behavior if it's an EXCLUDE constraint or a - * temporal PRIMARY KEY/UNIQUE constraint - */ - exclusion = stmt->excludeOpNames || stmt->iswithoutoverlaps; - /* Ensure that it makes sense to index this kind of relation */ switch (rel->rd_rel->relkind) { @@ -859,7 +848,7 @@ DefineIndex(Oid tableId, pgstat_progress_update_param(PROGRESS_CREATEIDX_ACCESS_METHOD_OID, accessMethodId); - if (stmt->unique && !stmt->iswithoutoverlaps && !amRoutine->amcanunique) + if (stmt->unique && !amRoutine->amcanunique) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("access method \"%s\" does not support unique indexes", @@ -874,7 +863,7 @@ DefineIndex(Oid tableId, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("access method \"%s\" does not support multicolumn indexes", accessMethodName))); - if (exclusion && amRoutine->amgettuple == NULL) + if (stmt->excludeOpNames && amRoutine->amgettuple == NULL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("access method \"%s\" does not support exclusion constraints", @@ -927,9 +916,8 @@ DefineIndex(Oid tableId, coloptions, allIndexParams, stmt->excludeOpNames, tableId, accessMethodName, accessMethodId, - amcanorder, stmt->isconstraint, stmt->iswithoutoverlaps, - root_save_userid, root_save_sec_context, - &root_save_nestlevel); + amcanorder, stmt->isconstraint, root_save_userid, + root_save_sec_context, &root_save_nestlevel); /* * Extra checks when creating a PRIMARY KEY index. @@ -947,7 +935,7 @@ DefineIndex(Oid tableId, * We could lift this limitation if we had global indexes, but those have * their own problems, so this is a useful feature combination. */ - if (partitioned && (stmt->unique || exclusion)) + if (partitioned && (stmt->unique || stmt->excludeOpNames)) { PartitionKey key = RelationGetPartitionKey(rel); const char *constraint_type; @@ -1001,10 +989,10 @@ DefineIndex(Oid tableId, * associated with index columns, too. We know what to do with * btree opclasses; if there are ever any other index types that * support unique indexes, this logic will need extension. But if - * we have an exclusion constraint (or a temporal PK), it already - * knows the operators, so we don't have to infer them. + * we have an exclusion constraint, it already knows the + * operators, so we don't have to infer them. */ - if (stmt->unique && !stmt->iswithoutoverlaps && accessMethodId != BTREE_AM_OID) + if (stmt->unique && accessMethodId != BTREE_AM_OID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot match partition key to an index using access method \"%s\"", @@ -1043,12 +1031,12 @@ DefineIndex(Oid tableId, { Oid idx_eqop = InvalidOid; - if (stmt->unique && !stmt->iswithoutoverlaps) + if (stmt->unique) idx_eqop = get_opfamily_member(idx_opfamily, idx_opcintype, idx_opcintype, BTEqualStrategyNumber); - else if (exclusion) + else if (stmt->excludeOpNames) idx_eqop = indexInfo->ii_ExclusionOps[j]; Assert(idx_eqop); @@ -1057,7 +1045,7 @@ DefineIndex(Oid tableId, found = true; break; } - else if (exclusion) + else if (stmt->excludeOpNames) { /* * We found a match, but it's not an equality @@ -1201,8 +1189,6 @@ DefineIndex(Oid tableId, constr_flags |= INDEX_CONSTR_CREATE_DEFERRABLE; if (stmt->initdeferred) constr_flags |= INDEX_CONSTR_CREATE_INIT_DEFERRED; - if (stmt->iswithoutoverlaps) - constr_flags |= INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS; indexRelationId = index_create(rel, indexRelationName, indexRelationId, parentIndexId, @@ -1868,7 +1854,6 @@ ComputeIndexAttrs(IndexInfo *indexInfo, Oid accessMethodId, bool amcanorder, bool isconstraint, - bool iswithoutoverlaps, Oid ddl_userid, int ddl_sec_context, int *ddl_save_nestlevel) @@ -1892,14 +1877,6 @@ ComputeIndexAttrs(IndexInfo *indexInfo, else nextExclOp = NULL; - /* exclusionOpNames can be non-NIL if we are creating a partition */ - if (iswithoutoverlaps && exclusionOpNames == NIL) - { - indexInfo->ii_ExclusionOps = palloc_array(Oid, nkeycols); - indexInfo->ii_ExclusionProcs = palloc_array(Oid, nkeycols); - indexInfo->ii_ExclusionStrats = palloc_array(uint16, nkeycols); - } - if (OidIsValid(ddl_userid)) GetUserIdAndSecContext(&save_userid, &save_sec_context); @@ -2176,21 +2153,6 @@ ComputeIndexAttrs(IndexInfo *indexInfo, indexInfo->ii_ExclusionStrats[attn] = strat; nextExclOp = lnext(exclusionOpNames, nextExclOp); } - else if (iswithoutoverlaps) - { - StrategyNumber strat; - Oid opid; - - if (attn == nkeycols - 1) - strat = RTOverlapStrategyNumber; - else - strat = RTEqualStrategyNumber; - GetOperatorFromWellKnownStrategy(opclassOids[attn], atttype, - &opid, &strat); - indexInfo->ii_ExclusionOps[attn] = opid; - indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid); - indexInfo->ii_ExclusionStrats[attn] = strat; - } /* * Set up the per-column options (indoption field). For now, this is @@ -2421,83 +2383,6 @@ GetDefaultOpClass(Oid type_id, Oid am_id) return InvalidOid; } -/* - * GetOperatorFromWellKnownStrategy - * - * opclass - the opclass to use - * atttype - the type to ask about - * opid - holds the operator we found - * strat - holds the input and output strategy number - * - * Finds an operator from a "well-known" strategy number. This is used for - * temporal index constraints (and other temporal features) to look up - * equality and overlaps operators, since the strategy numbers for non-btree - * indexams need not follow any fixed scheme. We ask an opclass support - * function to translate from the well-known number to the internal value. If - * the function isn't defined or it gives no result, we return - * InvalidStrategy. - */ -void -GetOperatorFromWellKnownStrategy(Oid opclass, Oid atttype, - Oid *opid, StrategyNumber *strat) -{ - Oid opfamily; - Oid opcintype; - StrategyNumber instrat = *strat; - - Assert(instrat == RTEqualStrategyNumber || instrat == RTOverlapStrategyNumber); - - *opid = InvalidOid; - - if (get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype)) - { - /* - * Ask the opclass to translate to its internal stratnum - * - * For now we only need GiST support, but this could support other - * indexams if we wanted. - */ - *strat = GistTranslateStratnum(opclass, instrat); - if (*strat == InvalidStrategy) - { - HeapTuple tuple; - - tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for operator class %u", opclass); - - ereport(ERROR, - errcode(ERRCODE_UNDEFINED_OBJECT), - instrat == RTEqualStrategyNumber ? - errmsg("could not identify an equality operator for type %s", format_type_be(atttype)) : - errmsg("could not identify an overlaps operator for type %s", format_type_be(atttype)), - errdetail("Could not translate strategy number %d for operator class \"%s\" for access method \"%s\".", - instrat, NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname), "gist")); - - ReleaseSysCache(tuple); - } - - *opid = get_opfamily_member(opfamily, opcintype, opcintype, *strat); - } - - if (!OidIsValid(*opid)) - { - HeapTuple tuple; - - tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamily)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for operator family %u", opfamily); - - ereport(ERROR, - errcode(ERRCODE_UNDEFINED_OBJECT), - instrat == RTEqualStrategyNumber ? - errmsg("could not identify an equality operator for type %s", format_type_be(atttype)) : - errmsg("could not identify an overlaps operator for type %s", format_type_be(atttype)), - errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".", - NameStr(((Form_pg_opfamily) GETSTRUCT(tuple))->opfname), "gist")); - } -} - /* * makeObjectName() * diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index b88a4aaa617..313c782cae2 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -10125,7 +10125,6 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, conislocal, /* islocal */ coninhcount, /* inhcount */ connoinherit, /* conNoInherit */ - false, /* conWithoutOverlaps */ false); /* is_internal */ ObjectAddressSet(address, ConstraintRelationId, constrOid); @@ -10424,7 +10423,6 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, false, 1, false, - false, /* conWithoutOverlaps */ false); /* @@ -10930,7 +10928,6 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel) false, /* islocal */ 1, /* inhcount */ false, /* conNoInherit */ - false, /* conWithoutOverlaps */ true); /* Set up partition dependencies for the new constraint */ @@ -14099,8 +14096,7 @@ TryReuseIndex(Oid oldId, IndexStmt *stmt) if (CheckIndexCompatible(oldId, stmt->accessMethod, stmt->indexParams, - stmt->excludeOpNames, - stmt->iswithoutoverlaps)) + stmt->excludeOpNames)) { Relation irel = index_open(oldId, NoLock); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 3d35b64a57d..95de402fa65 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -834,7 +834,6 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, true, /* islocal */ 0, /* inhcount */ true, /* noinherit */ - false, /* conwithoutoverlaps */ isInternal); /* is_internal */ } diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index fc9eebd29b2..2a1e7133356 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -3621,7 +3621,6 @@ domainAddCheckConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, true, /* is local */ 0, /* inhcount */ false, /* connoinherit */ - false, /* conwithoutoverlaps */ false); /* is_internal */ if (constrAddr) ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid); @@ -3728,7 +3727,6 @@ domainAddNotNullConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, true, /* is local */ 0, /* inhcount */ false, /* connoinherit */ - false, /* conperiod */ false); /* is_internal */ if (constrAddr) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index ee5292109f8..4d582950b72 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -532,7 +532,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); columnref in_expr having_clause func_table xmltable array_expr OptWhereClause operator_def_arg %type rowsfrom_item rowsfrom_list opt_col_def_list -%type opt_ordinality opt_without_overlaps +%type opt_ordinality %type ExclusionConstraintList ExclusionConstraintElem %type func_arg_list func_arg_list_opt %type func_arg_expr @@ -4193,7 +4193,7 @@ ConstraintElem: n->initially_valid = !n->skip_validation; $$ = (Node *) n; } - | UNIQUE opt_unique_null_treatment '(' columnList opt_without_overlaps ')' opt_c_include opt_definition OptConsTableSpace + | UNIQUE opt_unique_null_treatment '(' columnList ')' opt_c_include opt_definition OptConsTableSpace ConstraintAttributeSpec { Constraint *n = makeNode(Constraint); @@ -4202,12 +4202,11 @@ ConstraintElem: n->location = @1; n->nulls_not_distinct = !$2; n->keys = $4; - n->without_overlaps = $5; - n->including = $7; - n->options = $8; + n->including = $6; + n->options = $7; n->indexname = NULL; - n->indexspace = $9; - processCASbits($10, @10, "UNIQUE", + n->indexspace = $8; + processCASbits($9, @9, "UNIQUE", &n->deferrable, &n->initdeferred, NULL, NULL, yyscanner); $$ = (Node *) n; @@ -4228,7 +4227,7 @@ ConstraintElem: NULL, yyscanner); $$ = (Node *) n; } - | PRIMARY KEY '(' columnList opt_without_overlaps ')' opt_c_include opt_definition OptConsTableSpace + | PRIMARY KEY '(' columnList ')' opt_c_include opt_definition OptConsTableSpace ConstraintAttributeSpec { Constraint *n = makeNode(Constraint); @@ -4236,12 +4235,11 @@ ConstraintElem: n->contype = CONSTR_PRIMARY; n->location = @1; n->keys = $4; - n->without_overlaps = $5; - n->including = $7; - n->options = $8; + n->including = $6; + n->options = $7; n->indexname = NULL; - n->indexspace = $9; - processCASbits($10, @10, "PRIMARY KEY", + n->indexspace = $8; + processCASbits($9, @9, "PRIMARY KEY", &n->deferrable, &n->initdeferred, NULL, NULL, yyscanner); $$ = (Node *) n; @@ -4363,11 +4361,6 @@ opt_no_inherit: NO INHERIT { $$ = true; } | /* EMPTY */ { $$ = false; } ; -opt_without_overlaps: - WITHOUT OVERLAPS { $$ = true; } - | /*EMPTY*/ { $$ = false; } - ; - opt_column_list: '(' columnList ')' { $$ = $2; } | /*EMPTY*/ { $$ = NIL; } diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index b692d251522..639cfa443e2 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -1562,7 +1562,6 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, index->unique = idxrec->indisunique; index->nulls_not_distinct = idxrec->indnullsnotdistinct; index->primary = idxrec->indisprimary; - index->iswithoutoverlaps = (idxrec->indisprimary || idxrec->indisunique) && idxrec->indisexclusion; index->transformed = true; /* don't need transformIndexStmt */ index->concurrent = false; index->if_not_exists = false; @@ -1612,9 +1611,7 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, int nElems; int i; - Assert(conrec->contype == CONSTRAINT_EXCLUSION || - (index->iswithoutoverlaps && - (conrec->contype == CONSTRAINT_PRIMARY || conrec->contype == CONSTRAINT_UNIQUE))); + Assert(conrec->contype == CONSTRAINT_EXCLUSION); /* Extract operator OIDs from the pg_constraint tuple */ datum = SysCacheGetAttrNotNull(CONSTROID, ht_constr, Anum_pg_constraint_conexclop); @@ -2156,7 +2153,6 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) } index->nulls_not_distinct = constraint->nulls_not_distinct; index->isconstraint = true; - index->iswithoutoverlaps = constraint->without_overlaps; index->deferrable = constraint->deferrable; index->initdeferred = constraint->initdeferred; @@ -2249,11 +2245,6 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) errmsg("index \"%s\" is not valid", index_name), parser_errposition(cxt->pstate, constraint->location))); - /* - * Today we forbid non-unique indexes, but we could permit GiST - * indexes whose last entry is a range type and use that to create a - * WITHOUT OVERLAPS constraint (i.e. a temporal constraint). - */ if (!index_form->indisunique) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -2542,23 +2533,6 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) notnullcmds = lappend(notnullcmds, notnullcmd); } } - - if (constraint->without_overlaps) - { - /* - * This enforces that there is at least 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")); - - /* WITHOUT OVERLAPS requires a GiST index */ - index->accessMethod = "gist"; - } - } /* diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 926d3d5834d..9618619762b 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -2393,8 +2393,6 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, Anum_pg_constraint_conkey); keyatts = decompile_column_index_array(val, conForm->conrelid, &buf); - if (conForm->conwithoutoverlaps) - appendStringInfoString(&buf, " WITHOUT OVERLAPS"); appendStringInfoChar(&buf, ')'); diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 01b2b701756..cc9b0c6524f 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -5540,14 +5540,11 @@ 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 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. + * This should be called only for an index that is known to have an + * associated exclusion 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. */ void RelationGetExclusionInfo(Relation indexRelation, @@ -5611,10 +5608,7 @@ RelationGetExclusionInfo(Relation indexRelation, int nelem; /* We want the exclusion constraint owning the index */ - if ((conform->contype != CONSTRAINT_EXCLUSION && - !(conform->conwithoutoverlaps && ( - conform->contype == CONSTRAINT_PRIMARY - || conform->contype == CONSTRAINT_UNIQUE))) || + if (conform->contype != CONSTRAINT_EXCLUSION || conform->conindid != RelationGetRelid(indexRelation)) continue; diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 10409011eb2..1c7c0e8e880 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -7344,7 +7344,6 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) i_conname, i_condeferrable, i_condeferred, - i_conwithoutoverlaps, i_contableoid, i_conoid, i_condef, @@ -7426,17 +7425,10 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) if (fout->remoteVersion >= 150000) appendPQExpBufferStr(query, - "i.indnullsnotdistinct, "); + "i.indnullsnotdistinct "); else appendPQExpBufferStr(query, - "false AS indnullsnotdistinct, "); - - if (fout->remoteVersion >= 170000) - appendPQExpBufferStr(query, - "c.conwithoutoverlaps "); - else - appendPQExpBufferStr(query, - "NULL AS conwithoutoverlaps "); + "false AS indnullsnotdistinct "); /* * The point of the messy-looking outer join is to find a constraint that @@ -7504,7 +7496,6 @@ 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"); @@ -7612,7 +7603,6 @@ 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; @@ -17058,8 +17048,6 @@ dumpConstraint(Archive *fout, const ConstraintInfo *coninfo) (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 e8db47f93d2..865823868f1 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -474,8 +474,6 @@ 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 */ } ConstraintInfo; diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index beed8db4d10..d3dd8784d64 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -1004,42 +1004,6 @@ }, }, - '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));', - 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 - /xm, - like => { - %full_runs, %dump_test_schema_runs, section_post_data => 1, - }, - unlike => { - exclude_dump_test_schema => 1, - only_dump_measurement => 1, - }, - }, - - '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));', - 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 - /xm, - like => { - %full_runs, %dump_test_schema_runs, section_post_data => 1, - }, - unlike => { - exclude_dump_test_schema => 1, - only_dump_measurement => 1, - }, - }, - 'ALTER TABLE (partitioned) ADD CONSTRAINT ... FOREIGN KEY' => { create_order => 4, create_sql => 'CREATE TABLE dump_test.test_table_fk ( diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 8856079a290..f67bf0b8925 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -2383,10 +2383,6 @@ describeOneTableDetails(const char *schemaname, else appendPQExpBufferStr(&buf, ", false AS indisreplident"); appendPQExpBufferStr(&buf, ", c2.reltablespace"); - if (pset.sversion >= 170000) - appendPQExpBufferStr(&buf, ", con.conwithoutoverlaps"); - else - 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" @@ -2408,12 +2404,8 @@ describeOneTableDetails(const char *schemaname, printfPQExpBuffer(&buf, " \"%s\"", PQgetvalue(result, i, 0)); - /* - * 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) + /* If exclusion constraint, print the constraintdef */ + if (strcmp(PQgetvalue(result, i, 7), "x") == 0) { appendPQExpBuffer(&buf, " %s", PQgetvalue(result, i, 6)); diff --git a/src/include/access/gist.h b/src/include/access/gist.h index 22dd04c1418..e7ced18a5ba 100644 --- a/src/include/access/gist.h +++ b/src/include/access/gist.h @@ -17,7 +17,6 @@ #define GIST_H #include "access/itup.h" -#include "access/stratnum.h" #include "access/transam.h" #include "access/xlog.h" #include "access/xlogdefs.h" @@ -247,6 +246,4 @@ typedef struct do { (e).key = (k); (e).rel = (r); (e).page = (pg); \ (e).offset = (o); (e).leafkey = (l); } while (0) -extern StrategyNumber GistTranslateStratnum(Oid opclass, StrategyNumber strat); - #endif /* GIST_H */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 1f45f5c8deb..d54ac7f0058 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202405151 +#define CATALOG_VERSION_NO 202405152 #endif diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index 2dea96f47c3..7d434f8e653 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -93,7 +93,6 @@ 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_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 af588719601..7a8017f15b5 100644 --- a/src/include/catalog/pg_constraint.h +++ b/src/include/catalog/pg_constraint.h @@ -107,12 +107,6 @@ CATALOG(pg_constraint,2606,ConstraintRelationId) /* Has a local definition and cannot be inherited */ bool connoinherit; - /* - * For primary keys and unique constraints, signifies the last column uses - * overlaps instead of equals. - */ - bool conwithoutoverlaps; - #ifdef CATALOG_VARLEN /* variable-length fields start here */ /* @@ -152,8 +146,7 @@ CATALOG(pg_constraint,2606,ConstraintRelationId) /* * If an exclusion constraint, the OIDs of the exclusion operators for - * each column of the constraint. Also set for unique constraints/primary - * keys using WITHOUT OVERLAPS. + * each column of the constraint */ Oid conexclop[1] BKI_LOOKUP(pg_operator); @@ -245,7 +238,6 @@ extern Oid CreateConstraintEntry(const char *constraintName, bool conIsLocal, int conInhCount, bool conNoInherit, - 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 0c53d67d3ee..29c511e3196 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -14,7 +14,6 @@ #ifndef DEFREM_H #define DEFREM_H -#include "access/stratnum.h" #include "catalog/objectaddress.h" #include "nodes/params.h" #include "parser/parse_node.h" @@ -45,13 +44,10 @@ extern char *ChooseRelationName(const char *name1, const char *name2, extern bool CheckIndexCompatible(Oid oldId, const char *accessMethodName, const List *attributeList, - const List *exclusionOpNames, - bool isWithoutOverlaps); + const List *exclusionOpNames); extern Oid GetDefaultOpClass(Oid type_id, Oid am_id); extern Oid ResolveOpClass(const List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId); -extern void GetOperatorFromWellKnownStrategy(Oid opclass, Oid atttype, - Oid *opid, StrategyNumber *strat); /* commands/functioncmds.c */ extern ObjectAddress CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index fe51a308aa7..ddfed02db22 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2750,7 +2750,6 @@ typedef struct Constraint bool nulls_not_distinct; /* null treatment for UNIQUE constraints */ List *keys; /* String nodes naming referenced key * column(s); for UNIQUE/PK/NOT NULL */ - bool without_overlaps; /* WITHOUT OVERLAPS specified */ List *including; /* String nodes naming referenced nonkey * column(s); for UNIQUE/PK */ List *exclusions; /* list of (IndexElem, operator name) pairs; @@ -3374,7 +3373,6 @@ 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 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 deleted file mode 100644 index 726e94102bf..00000000000 --- a/src/test/regress/expected/without_overlaps.out +++ /dev/null @@ -1,395 +0,0 @@ --- Tests for WITHOUT OVERLAPS. --- --- We leave behind several tables to test pg_dump etc: --- temporal_rng, temporal_rng2, --- temporal_fk_rng2rng. --- --- test input parser --- --- PK with no columns just WITHOUT OVERLAPS: -CREATE TABLE temporal_rng ( - valid_at tsrange, - CONSTRAINT temporal_rng_pk PRIMARY KEY (valid_at WITHOUT OVERLAPS) -); -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, - CONSTRAINT temporal_rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -ERROR: column "valid_at" named in key does not exist -LINE 3: CONSTRAINT temporal_rng_pk PRIMARY KEY (id, valid_at WITHOU... - ^ --- PK with a non-range column: -CREATE TABLE temporal_rng ( - id int4range, - valid_at TEXT, - CONSTRAINT temporal_rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -ERROR: data type text has no default operator class for access method "gist" -HINT: You must specify an operator class for the index or define a default operator class for the data type. --- PK with one column plus a range: -CREATE TABLE temporal_rng ( - -- Since we can't depend on having btree_gist here, - -- use an int4range instead of an int. - -- (The rangetypes regression test uses the same trick.) - id int4range, - valid_at tsrange, - CONSTRAINT temporal_rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -\d temporal_rng - Table "public.temporal_rng" - Column | Type | Collation | Nullable | Default -----------+-----------+-----------+----------+--------- - id | int4range | | not null | - valid_at | tsrange | | not null | -Indexes: - "temporal_rng_pk" PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) - -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_rng_pk'; - pg_get_constraintdef ---------------------------------------------- - PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -(1 row) - -SELECT pg_get_indexdef(conindid, 0, true) FROM pg_constraint WHERE conname = 'temporal_rng_pk'; - pg_get_indexdef -------------------------------------------------------------------------------- - CREATE UNIQUE INDEX temporal_rng_pk ON temporal_rng USING gist (id, valid_at) -(1 row) - --- PK with two columns plus a range: --- We don't drop this table because tests below also need multiple scalar columns. -CREATE TABLE temporal_rng2 ( - id1 int4range, - id2 int4range, - valid_at tsrange, - CONSTRAINT temporal_rng2_pk PRIMARY KEY (id1, id2, valid_at WITHOUT OVERLAPS) -); -\d temporal_rng2 - Table "public.temporal_rng2" - Column | Type | Collation | Nullable | Default -----------+-----------+-----------+----------+--------- - id1 | int4range | | not null | - id2 | int4range | | not null | - valid_at | tsrange | | not null | -Indexes: - "temporal_rng2_pk" PRIMARY KEY (id1, id2, valid_at WITHOUT OVERLAPS) - -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_rng2_pk'; - pg_get_constraintdef ---------------------------------------------------- - PRIMARY KEY (id1, id2, valid_at WITHOUT OVERLAPS) -(1 row) - -SELECT pg_get_indexdef(conindid, 0, true) FROM pg_constraint WHERE conname = 'temporal_rng2_pk'; - pg_get_indexdef ---------------------------------------------------------------------------------------- - CREATE UNIQUE INDEX temporal_rng2_pk ON temporal_rng2 USING gist (id1, id2, valid_at) -(1 row) - --- PK with a custom range type: -CREATE TYPE textrange2 AS range (subtype=text, collation="C"); -CREATE TABLE temporal_rng3 ( - id int4range, - valid_at textrange2, - CONSTRAINT temporal_rng3_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -ALTER TABLE temporal_rng3 DROP CONSTRAINT temporal_rng3_pk; -DROP TABLE temporal_rng3; -DROP TYPE textrange2; --- PK with a multirange: -CREATE TABLE temporal_mltrng ( - id int4range, - valid_at tsmultirange, - CONSTRAINT temporal_mltrng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -\d temporal_mltrng - Table "public.temporal_mltrng" - Column | Type | Collation | Nullable | Default -----------+--------------+-----------+----------+--------- - id | int4range | | not null | - valid_at | tsmultirange | | not null | -Indexes: - "temporal_mltrng_pk" PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) - --- UNIQUE with no columns just WITHOUT OVERLAPS: -CREATE TABLE temporal_rng3 ( - valid_at tsrange, - CONSTRAINT temporal_rng3_uq UNIQUE (valid_at WITHOUT OVERLAPS) -); -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, - CONSTRAINT temporal_rng3_uq UNIQUE (id, valid_at WITHOUT OVERLAPS) -); -ERROR: column "valid_at" named in key does not exist -LINE 3: CONSTRAINT temporal_rng3_uq UNIQUE (id, valid_at WITHOUT OV... - ^ --- UNIQUE with a non-range column: -CREATE TABLE temporal_rng3 ( - id int4range, - valid_at TEXT, - CONSTRAINT temporal_rng3_uq UNIQUE (id, valid_at WITHOUT OVERLAPS) -); -ERROR: data type text has no default operator class for access method "gist" -HINT: You must specify an operator class for the index or define a default operator class for the data type. --- UNIQUE with one column plus a range: -CREATE TABLE temporal_rng3 ( - id int4range, - valid_at tsrange, - CONSTRAINT temporal_rng3_uq UNIQUE (id, valid_at WITHOUT OVERLAPS) -); -\d temporal_rng3 - Table "public.temporal_rng3" - Column | Type | Collation | Nullable | Default -----------+-----------+-----------+----------+--------- - id | int4range | | | - valid_at | tsrange | | | -Indexes: - "temporal_rng3_uq" UNIQUE (id, valid_at WITHOUT OVERLAPS) - -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_rng3_uq'; - pg_get_constraintdef ----------------------------------------- - UNIQUE (id, valid_at WITHOUT OVERLAPS) -(1 row) - -SELECT pg_get_indexdef(conindid, 0, true) FROM pg_constraint WHERE conname = 'temporal_rng3_uq'; - pg_get_indexdef ---------------------------------------------------------------------------------- - CREATE UNIQUE INDEX temporal_rng3_uq ON temporal_rng3 USING gist (id, valid_at) -(1 row) - -DROP TABLE temporal_rng3; --- UNIQUE with two columns plus a range: -CREATE TABLE temporal_rng3 ( - id1 int4range, - id2 int4range, - valid_at tsrange, - CONSTRAINT temporal_rng3_uq UNIQUE (id1, id2, valid_at WITHOUT OVERLAPS) -); -\d temporal_rng3 - Table "public.temporal_rng3" - Column | Type | Collation | Nullable | Default -----------+-----------+-----------+----------+--------- - id1 | int4range | | | - id2 | int4range | | | - valid_at | tsrange | | | -Indexes: - "temporal_rng3_uq" UNIQUE (id1, id2, valid_at WITHOUT OVERLAPS) - -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_rng3_uq'; - pg_get_constraintdef ----------------------------------------------- - UNIQUE (id1, id2, valid_at WITHOUT OVERLAPS) -(1 row) - -SELECT pg_get_indexdef(conindid, 0, true) FROM pg_constraint WHERE conname = 'temporal_rng3_uq'; - pg_get_indexdef ---------------------------------------------------------------------------------------- - CREATE UNIQUE INDEX temporal_rng3_uq ON temporal_rng3 USING gist (id1, id2, valid_at) -(1 row) - -DROP TABLE temporal_rng3; --- UNIQUE with a custom range type: -CREATE TYPE textrange2 AS range (subtype=text, collation="C"); -CREATE TABLE temporal_rng3 ( - id int4range, - valid_at textrange2, - CONSTRAINT temporal_rng3_uq UNIQUE (id, valid_at WITHOUT OVERLAPS) -); -ALTER TABLE temporal_rng3 DROP CONSTRAINT temporal_rng3_uq; -DROP TABLE temporal_rng3; -DROP TYPE textrange2; --- --- test ALTER TABLE ADD CONSTRAINT --- -DROP TABLE temporal_rng; -CREATE TABLE temporal_rng ( - id int4range, - valid_at tsrange -); -ALTER TABLE temporal_rng - ADD CONSTRAINT temporal_rng_pk - PRIMARY KEY (id, valid_at WITHOUT OVERLAPS); --- PK with USING INDEX (not possible): -CREATE TABLE temporal3 ( - id int4range, - valid_at tsrange -); -CREATE INDEX idx_temporal3_uq ON temporal3 USING gist (id, valid_at); -ALTER TABLE temporal3 - ADD CONSTRAINT temporal3_pk - PRIMARY KEY USING INDEX idx_temporal3_uq; -ERROR: "idx_temporal3_uq" is not a unique index -LINE 2: ADD CONSTRAINT temporal3_pk - ^ -DETAIL: Cannot create a primary key or unique constraint using such an index. -DROP TABLE temporal3; --- UNIQUE with USING INDEX (not possible): -CREATE TABLE temporal3 ( - id int4range, - valid_at tsrange -); -CREATE INDEX idx_temporal3_uq ON temporal3 USING gist (id, valid_at); -ALTER TABLE temporal3 - ADD CONSTRAINT temporal3_uq - UNIQUE USING INDEX idx_temporal3_uq; -ERROR: "idx_temporal3_uq" is not a unique index -LINE 2: ADD CONSTRAINT temporal3_uq - ^ -DETAIL: Cannot create a primary key or unique constraint using such an index. -DROP TABLE temporal3; --- UNIQUE with USING [UNIQUE] INDEX (possible but not a temporal constraint): -CREATE TABLE temporal3 ( - id int4range, - valid_at tsrange -); -CREATE UNIQUE INDEX idx_temporal3_uq ON temporal3 (id, valid_at); -ALTER TABLE temporal3 - ADD CONSTRAINT temporal3_uq - UNIQUE USING INDEX idx_temporal3_uq; -NOTICE: ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index "idx_temporal3_uq" to "temporal3_uq" -DROP TABLE temporal3; --- Add range column and the PK at the same time -CREATE TABLE temporal3 ( - id int4range -); -ALTER TABLE temporal3 - ADD COLUMN valid_at tsrange, - ADD CONSTRAINT temporal3_pk - PRIMARY KEY (id, valid_at WITHOUT OVERLAPS); -DROP TABLE temporal3; --- Add range column and UNIQUE constraint at the same time -CREATE TABLE temporal3 ( - id int4range -); -ALTER TABLE temporal3 - ADD COLUMN valid_at tsrange, - ADD CONSTRAINT temporal3_uq - UNIQUE (id, valid_at WITHOUT OVERLAPS); -DROP TABLE temporal3; --- --- test PK inserts --- --- okay: -INSERT INTO temporal_rng VALUES ('[1,1]', tsrange('2018-01-02', '2018-02-03')); -INSERT INTO temporal_rng VALUES ('[1,1]', tsrange('2018-03-03', '2018-04-04')); -INSERT INTO temporal_rng VALUES ('[2,2]', tsrange('2018-01-01', '2018-01-05')); -INSERT INTO temporal_rng VALUES ('[3,3]', tsrange('2018-01-01', NULL)); --- should fail: -INSERT INTO temporal_rng VALUES ('[1,1]', tsrange('2018-01-01', '2018-01-05')); -ERROR: conflicting key value violates exclusion constraint "temporal_rng_pk" -DETAIL: Key (id, valid_at)=([1,2), ["Mon Jan 01 00:00:00 2018","Fri Jan 05 00:00:00 2018")) conflicts with existing key (id, valid_at)=([1,2), ["Tue Jan 02 00:00:00 2018","Sat Feb 03 00:00:00 2018")). -INSERT INTO temporal_rng VALUES (NULL, tsrange('2018-01-01', '2018-01-05')); -ERROR: null value in column "id" of relation "temporal_rng" violates not-null constraint -DETAIL: Failing row contains (null, ["Mon Jan 01 00:00:00 2018","Fri Jan 05 00:00:00 2018")). -INSERT INTO temporal_rng VALUES ('[3,3]', NULL); -ERROR: null value in column "valid_at" of relation "temporal_rng" violates not-null constraint -DETAIL: Failing row contains ([3,4), null). --- --- test a range with both a PK and a UNIQUE constraint --- -CREATE TABLE temporal3 ( - id int4range, - valid_at daterange, - id2 int8range, - name TEXT, - CONSTRAINT temporal3_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS), - CONSTRAINT temporal3_uniq UNIQUE (id2, valid_at WITHOUT OVERLAPS) -); -INSERT INTO temporal3 (id, valid_at, id2, name) - VALUES - ('[1,1]', daterange('2000-01-01', '2010-01-01'), '[7,7]', 'foo'), - ('[2,2]', daterange('2000-01-01', '2010-01-01'), '[9,9]', 'bar') -; -DROP TABLE temporal3; --- --- test changing the PK's dependencies --- -CREATE TABLE temporal3 ( - id int4range, - valid_at tsrange, - CONSTRAINT temporal3_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -ALTER TABLE temporal3 ALTER COLUMN valid_at DROP NOT NULL; -ERROR: column "valid_at" is in a primary key -ALTER TABLE temporal3 ALTER COLUMN valid_at TYPE tstzrange USING tstzrange(lower(valid_at), upper(valid_at)); -ALTER TABLE temporal3 RENAME COLUMN valid_at TO valid_thru; -ALTER TABLE temporal3 DROP COLUMN valid_thru; -DROP TABLE temporal3; --- --- test PARTITION BY for ranges --- --- temporal PRIMARY KEY: -CREATE TABLE temporal_partitioned ( - id int4range, - valid_at daterange, - name text, - CONSTRAINT temporal_paritioned_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -) PARTITION BY LIST (id); -CREATE TABLE tp1 PARTITION OF temporal_partitioned FOR VALUES IN ('[1,1]', '[2,2]'); -CREATE TABLE tp2 PARTITION OF temporal_partitioned FOR VALUES IN ('[3,3]', '[4,4]'); -INSERT INTO temporal_partitioned VALUES - ('[1,1]', daterange('2000-01-01', '2000-02-01'), 'one'), - ('[1,1]', daterange('2000-02-01', '2000-03-01'), 'one'), - ('[3,3]', daterange('2000-01-01', '2010-01-01'), 'three'); -SELECT * FROM temporal_partitioned ORDER BY id, valid_at; - id | valid_at | name --------+-------------------------+------- - [1,2) | [01-01-2000,02-01-2000) | one - [1,2) | [02-01-2000,03-01-2000) | one - [3,4) | [01-01-2000,01-01-2010) | three -(3 rows) - -SELECT * FROM tp1 ORDER BY id, valid_at; - id | valid_at | name --------+-------------------------+------ - [1,2) | [01-01-2000,02-01-2000) | one - [1,2) | [02-01-2000,03-01-2000) | one -(2 rows) - -SELECT * FROM tp2 ORDER BY id, valid_at; - id | valid_at | name --------+-------------------------+------- - [3,4) | [01-01-2000,01-01-2010) | three -(1 row) - -DROP TABLE temporal_partitioned; --- temporal UNIQUE: -CREATE TABLE temporal_partitioned ( - id int4range, - valid_at daterange, - name text, - CONSTRAINT temporal_paritioned_uq UNIQUE (id, valid_at WITHOUT OVERLAPS) -) PARTITION BY LIST (id); -CREATE TABLE tp1 PARTITION OF temporal_partitioned FOR VALUES IN ('[1,1]', '[2,2]'); -CREATE TABLE tp2 PARTITION OF temporal_partitioned FOR VALUES IN ('[3,3]', '[4,4]'); -INSERT INTO temporal_partitioned VALUES - ('[1,1]', daterange('2000-01-01', '2000-02-01'), 'one'), - ('[1,1]', daterange('2000-02-01', '2000-03-01'), 'one'), - ('[3,3]', daterange('2000-01-01', '2010-01-01'), 'three'); -SELECT * FROM temporal_partitioned ORDER BY id, valid_at; - id | valid_at | name --------+-------------------------+------- - [1,2) | [01-01-2000,02-01-2000) | one - [1,2) | [02-01-2000,03-01-2000) | one - [3,4) | [01-01-2000,01-01-2010) | three -(3 rows) - -SELECT * FROM tp1 ORDER BY id, valid_at; - id | valid_at | name --------+-------------------------+------ - [1,2) | [01-01-2000,02-01-2000) | one - [1,2) | [02-01-2000,03-01-2000) | one -(2 rows) - -SELECT * FROM tp2 ORDER BY id, valid_at; - id | valid_at | name --------+-------------------------+------- - [3,4) | [01-01-2000,01-01-2010) | three -(1 row) - -DROP TABLE temporal_partitioned; diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 675c5676171..969ced994f4 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -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.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps +test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8 collate.windows.win1252 diff --git a/src/test/regress/sql/without_overlaps.sql b/src/test/regress/sql/without_overlaps.sql deleted file mode 100644 index c8e8ab994a0..00000000000 --- a/src/test/regress/sql/without_overlaps.sql +++ /dev/null @@ -1,290 +0,0 @@ --- Tests for WITHOUT OVERLAPS. --- --- We leave behind several tables to test pg_dump etc: --- temporal_rng, temporal_rng2, --- temporal_fk_rng2rng. - --- --- test input parser --- - --- PK with no columns just WITHOUT OVERLAPS: - -CREATE TABLE temporal_rng ( - valid_at tsrange, - CONSTRAINT temporal_rng_pk PRIMARY KEY (valid_at WITHOUT OVERLAPS) -); - --- PK with a range column/PERIOD that isn't there: - -CREATE TABLE temporal_rng ( - id INTEGER, - CONSTRAINT temporal_rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); - --- PK with a non-range column: - -CREATE TABLE temporal_rng ( - id int4range, - valid_at TEXT, - CONSTRAINT temporal_rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); - --- PK with one column plus a range: - -CREATE TABLE temporal_rng ( - -- Since we can't depend on having btree_gist here, - -- use an int4range instead of an int. - -- (The rangetypes regression test uses the same trick.) - id int4range, - valid_at tsrange, - CONSTRAINT temporal_rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -\d temporal_rng -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_rng_pk'; -SELECT pg_get_indexdef(conindid, 0, true) FROM pg_constraint WHERE conname = 'temporal_rng_pk'; - --- PK with two columns plus a range: --- We don't drop this table because tests below also need multiple scalar columns. -CREATE TABLE temporal_rng2 ( - id1 int4range, - id2 int4range, - valid_at tsrange, - CONSTRAINT temporal_rng2_pk PRIMARY KEY (id1, id2, valid_at WITHOUT OVERLAPS) -); -\d temporal_rng2 -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_rng2_pk'; -SELECT pg_get_indexdef(conindid, 0, true) FROM pg_constraint WHERE conname = 'temporal_rng2_pk'; - - --- PK with a custom range type: -CREATE TYPE textrange2 AS range (subtype=text, collation="C"); -CREATE TABLE temporal_rng3 ( - id int4range, - valid_at textrange2, - CONSTRAINT temporal_rng3_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -ALTER TABLE temporal_rng3 DROP CONSTRAINT temporal_rng3_pk; -DROP TABLE temporal_rng3; -DROP TYPE textrange2; - --- PK with a multirange: -CREATE TABLE temporal_mltrng ( - id int4range, - valid_at tsmultirange, - CONSTRAINT temporal_mltrng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -\d temporal_mltrng - --- UNIQUE with no columns just WITHOUT OVERLAPS: - -CREATE TABLE temporal_rng3 ( - valid_at tsrange, - CONSTRAINT temporal_rng3_uq UNIQUE (valid_at WITHOUT OVERLAPS) -); - --- UNIQUE with a range column/PERIOD that isn't there: - -CREATE TABLE temporal_rng3 ( - id INTEGER, - CONSTRAINT temporal_rng3_uq UNIQUE (id, valid_at WITHOUT OVERLAPS) -); - --- UNIQUE with a non-range column: - -CREATE TABLE temporal_rng3 ( - id int4range, - valid_at TEXT, - CONSTRAINT temporal_rng3_uq UNIQUE (id, valid_at WITHOUT OVERLAPS) -); - --- UNIQUE with one column plus a range: - -CREATE TABLE temporal_rng3 ( - id int4range, - valid_at tsrange, - CONSTRAINT temporal_rng3_uq UNIQUE (id, valid_at WITHOUT OVERLAPS) -); -\d temporal_rng3 -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_rng3_uq'; -SELECT pg_get_indexdef(conindid, 0, true) FROM pg_constraint WHERE conname = 'temporal_rng3_uq'; -DROP TABLE temporal_rng3; - --- UNIQUE with two columns plus a range: -CREATE TABLE temporal_rng3 ( - id1 int4range, - id2 int4range, - valid_at tsrange, - CONSTRAINT temporal_rng3_uq UNIQUE (id1, id2, valid_at WITHOUT OVERLAPS) -); -\d temporal_rng3 -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'temporal_rng3_uq'; -SELECT pg_get_indexdef(conindid, 0, true) FROM pg_constraint WHERE conname = 'temporal_rng3_uq'; -DROP TABLE temporal_rng3; - --- UNIQUE with a custom range type: -CREATE TYPE textrange2 AS range (subtype=text, collation="C"); -CREATE TABLE temporal_rng3 ( - id int4range, - valid_at textrange2, - CONSTRAINT temporal_rng3_uq UNIQUE (id, valid_at WITHOUT OVERLAPS) -); -ALTER TABLE temporal_rng3 DROP CONSTRAINT temporal_rng3_uq; -DROP TABLE temporal_rng3; -DROP TYPE textrange2; - --- --- test ALTER TABLE ADD CONSTRAINT --- - -DROP TABLE temporal_rng; -CREATE TABLE temporal_rng ( - id int4range, - valid_at tsrange -); -ALTER TABLE temporal_rng - ADD CONSTRAINT temporal_rng_pk - PRIMARY KEY (id, valid_at WITHOUT OVERLAPS); - --- PK with USING INDEX (not possible): -CREATE TABLE temporal3 ( - id int4range, - valid_at tsrange -); -CREATE INDEX idx_temporal3_uq ON temporal3 USING gist (id, valid_at); -ALTER TABLE temporal3 - ADD CONSTRAINT temporal3_pk - PRIMARY KEY USING INDEX idx_temporal3_uq; -DROP TABLE temporal3; - --- UNIQUE with USING INDEX (not possible): -CREATE TABLE temporal3 ( - id int4range, - valid_at tsrange -); -CREATE INDEX idx_temporal3_uq ON temporal3 USING gist (id, valid_at); -ALTER TABLE temporal3 - ADD CONSTRAINT temporal3_uq - UNIQUE USING INDEX idx_temporal3_uq; -DROP TABLE temporal3; - --- UNIQUE with USING [UNIQUE] INDEX (possible but not a temporal constraint): -CREATE TABLE temporal3 ( - id int4range, - valid_at tsrange -); -CREATE UNIQUE INDEX idx_temporal3_uq ON temporal3 (id, valid_at); -ALTER TABLE temporal3 - ADD CONSTRAINT temporal3_uq - UNIQUE USING INDEX idx_temporal3_uq; -DROP TABLE temporal3; - --- Add range column and the PK at the same time -CREATE TABLE temporal3 ( - id int4range -); -ALTER TABLE temporal3 - ADD COLUMN valid_at tsrange, - ADD CONSTRAINT temporal3_pk - PRIMARY KEY (id, valid_at WITHOUT OVERLAPS); -DROP TABLE temporal3; - --- Add range column and UNIQUE constraint at the same time -CREATE TABLE temporal3 ( - id int4range -); -ALTER TABLE temporal3 - ADD COLUMN valid_at tsrange, - ADD CONSTRAINT temporal3_uq - UNIQUE (id, valid_at WITHOUT OVERLAPS); -DROP TABLE temporal3; - --- --- test PK inserts --- - --- okay: -INSERT INTO temporal_rng VALUES ('[1,1]', tsrange('2018-01-02', '2018-02-03')); -INSERT INTO temporal_rng VALUES ('[1,1]', tsrange('2018-03-03', '2018-04-04')); -INSERT INTO temporal_rng VALUES ('[2,2]', tsrange('2018-01-01', '2018-01-05')); -INSERT INTO temporal_rng VALUES ('[3,3]', tsrange('2018-01-01', NULL)); - --- should fail: -INSERT INTO temporal_rng VALUES ('[1,1]', tsrange('2018-01-01', '2018-01-05')); -INSERT INTO temporal_rng VALUES (NULL, tsrange('2018-01-01', '2018-01-05')); -INSERT INTO temporal_rng VALUES ('[3,3]', NULL); - --- --- test a range with both a PK and a UNIQUE constraint --- - -CREATE TABLE temporal3 ( - id int4range, - valid_at daterange, - id2 int8range, - name TEXT, - CONSTRAINT temporal3_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS), - CONSTRAINT temporal3_uniq UNIQUE (id2, valid_at WITHOUT OVERLAPS) -); -INSERT INTO temporal3 (id, valid_at, id2, name) - VALUES - ('[1,1]', daterange('2000-01-01', '2010-01-01'), '[7,7]', 'foo'), - ('[2,2]', daterange('2000-01-01', '2010-01-01'), '[9,9]', 'bar') -; -DROP TABLE temporal3; - --- --- test changing the PK's dependencies --- - -CREATE TABLE temporal3 ( - id int4range, - valid_at tsrange, - CONSTRAINT temporal3_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); - -ALTER TABLE temporal3 ALTER COLUMN valid_at DROP NOT NULL; -ALTER TABLE temporal3 ALTER COLUMN valid_at TYPE tstzrange USING tstzrange(lower(valid_at), upper(valid_at)); -ALTER TABLE temporal3 RENAME COLUMN valid_at TO valid_thru; -ALTER TABLE temporal3 DROP COLUMN valid_thru; -DROP TABLE temporal3; - --- --- test PARTITION BY for ranges --- - --- temporal PRIMARY KEY: -CREATE TABLE temporal_partitioned ( - id int4range, - valid_at daterange, - name text, - CONSTRAINT temporal_paritioned_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -) PARTITION BY LIST (id); -CREATE TABLE tp1 PARTITION OF temporal_partitioned FOR VALUES IN ('[1,1]', '[2,2]'); -CREATE TABLE tp2 PARTITION OF temporal_partitioned FOR VALUES IN ('[3,3]', '[4,4]'); -INSERT INTO temporal_partitioned VALUES - ('[1,1]', daterange('2000-01-01', '2000-02-01'), 'one'), - ('[1,1]', daterange('2000-02-01', '2000-03-01'), 'one'), - ('[3,3]', daterange('2000-01-01', '2010-01-01'), 'three'); -SELECT * FROM temporal_partitioned ORDER BY id, valid_at; -SELECT * FROM tp1 ORDER BY id, valid_at; -SELECT * FROM tp2 ORDER BY id, valid_at; -DROP TABLE temporal_partitioned; - --- temporal UNIQUE: -CREATE TABLE temporal_partitioned ( - id int4range, - valid_at daterange, - name text, - CONSTRAINT temporal_paritioned_uq UNIQUE (id, valid_at WITHOUT OVERLAPS) -) PARTITION BY LIST (id); -CREATE TABLE tp1 PARTITION OF temporal_partitioned FOR VALUES IN ('[1,1]', '[2,2]'); -CREATE TABLE tp2 PARTITION OF temporal_partitioned FOR VALUES IN ('[3,3]', '[4,4]'); -INSERT INTO temporal_partitioned VALUES - ('[1,1]', daterange('2000-01-01', '2000-02-01'), 'one'), - ('[1,1]', daterange('2000-02-01', '2000-03-01'), 'one'), - ('[3,3]', daterange('2000-01-01', '2010-01-01'), 'three'); -SELECT * FROM temporal_partitioned ORDER BY id, valid_at; -SELECT * FROM tp1 ORDER BY id, valid_at; -SELECT * FROM tp2 ORDER BY id, valid_at; -DROP TABLE temporal_partitioned; -- 2.44.0