diff options
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/access/gist/gistutil.c | 43 | ||||
| -rw-r--r-- | src/backend/access/gist/gistvalidate.c | 8 | ||||
| -rw-r--r-- | src/backend/catalog/heap.c | 1 | ||||
| -rw-r--r-- | src/backend/catalog/index.c | 4 | ||||
| -rw-r--r-- | src/backend/catalog/pg_constraint.c | 60 | ||||
| -rw-r--r-- | src/backend/commands/indexcmds.c | 148 | ||||
| -rw-r--r-- | src/backend/commands/tablecmds.c | 226 | ||||
| -rw-r--r-- | src/backend/commands/trigger.c | 1 | ||||
| -rw-r--r-- | src/backend/commands/typecmds.c | 2 | ||||
| -rw-r--r-- | src/backend/executor/execIndexing.c | 2 | ||||
| -rw-r--r-- | src/backend/optimizer/util/plancat.c | 9 | ||||
| -rw-r--r-- | src/backend/parser/gram.y | 74 | ||||
| -rw-r--r-- | src/backend/parser/parse_utilcmd.c | 28 | ||||
| -rw-r--r-- | src/backend/utils/adt/ri_triggers.c | 168 | ||||
| -rw-r--r-- | src/backend/utils/adt/ruleutils.c | 19 | ||||
| -rw-r--r-- | src/backend/utils/cache/relcache.c | 18 |
16 files changed, 114 insertions, 697 deletions
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index d2d0b36d4ea..78e98d68b15 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -21,7 +21,6 @@ #include "common/pg_prng.h" #include "storage/indexfsm.h" #include "utils/float.h" -#include "utils/fmgrprotos.h" #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/snapmgr.h" @@ -1056,45 +1055,3 @@ gistGetFakeLSN(Relation rel) return GetFakeLSNForUnloggedRel(); } } - -/* - * Returns the same number that was received. - * - * This is for GiST opclasses that use the RT*StrategyNumber constants. - */ -Datum -gist_stratnum_identity(PG_FUNCTION_ARGS) -{ - StrategyNumber strat = PG_GETARG_UINT16(0); - - 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/access/gist/gistvalidate.c b/src/backend/access/gist/gistvalidate.c index 0901543a60a..36b5a85cf31 100644 --- a/src/backend/access/gist/gistvalidate.c +++ b/src/backend/access/gist/gistvalidate.c @@ -146,10 +146,6 @@ gistvalidate(Oid opclassoid) ok = check_amproc_signature(procform->amproc, VOIDOID, true, 1, 1, INTERNALOID); break; - case GIST_STRATNUM_PROC: - ok = check_amproc_signature(procform->amproc, INT2OID, true, - 1, 1, INT2OID); - break; default: ereport(INFO, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), @@ -270,8 +266,7 @@ gistvalidate(Oid opclassoid) continue; /* got it */ if (i == GIST_DISTANCE_PROC || i == GIST_FETCH_PROC || i == GIST_COMPRESS_PROC || i == GIST_DECOMPRESS_PROC || - i == GIST_OPTIONS_PROC || i == GIST_SORTSUPPORT_PROC || - i == GIST_STRATNUM_PROC) + i == GIST_OPTIONS_PROC || i == GIST_SORTSUPPORT_PROC) continue; /* optional methods */ ereport(INFO, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), @@ -343,7 +338,6 @@ gistadjustmembers(Oid opfamilyoid, case GIST_FETCH_PROC: case GIST_OPTIONS_PROC: case GIST_SORTSUPPORT_PROC: - case GIST_STRATNUM_PROC: /* Optional, so force it to be a soft family dependency */ op->ref_is_hard = false; op->ref_is_family = true; diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 08b8362d64d..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, /* conperiod */ 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 b10e458b449..3baf9231ed0 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -15,7 +15,6 @@ #include "postgres.h" #include "access/genam.h" -#include "access/gist.h" #include "access/htup_details.h" #include "access/sysattr.h" #include "access/table.h" @@ -76,7 +75,6 @@ CreateConstraintEntry(const char *constraintName, bool conIsLocal, int conInhCount, bool conNoInherit, - bool conPeriod, bool is_internal) { Relation conDesc; @@ -192,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_conperiod - 1] = BoolGetDatum(conPeriod); if (conkeyArray) values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray); @@ -1351,63 +1348,6 @@ DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, } /* - * FindFKPeriodOpers - - * - * Looks up the operator oids used for the PERIOD part of a temporal foreign key. - * The opclass should be the opclass of that PERIOD element. - * Everything else is an output: containedbyoperoid is the ContainedBy operator for - * types matching the PERIOD element. - * aggedcontainedbyoperoid is also a ContainedBy operator, - * but one whose rhs is a multirange. - * That way foreign keys can compare fkattr <@ range_agg(pkattr). - */ -void -FindFKPeriodOpers(Oid opclass, - Oid *containedbyoperoid, - Oid *aggedcontainedbyoperoid) -{ - Oid opfamily = InvalidOid; - Oid opcintype = InvalidOid; - StrategyNumber strat; - - /* Make sure we have a range or multirange. */ - if (get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype)) - { - if (opcintype != ANYRANGEOID && opcintype != ANYMULTIRANGEOID) - ereport(ERROR, - errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("invalid type for PERIOD part of foreign key"), - errdetail("Only range and multirange are supported.")); - - } - else - elog(ERROR, "cache lookup failed for opclass %u", opclass); - - /* - * Look up the ContainedBy operator whose lhs and rhs are the opclass's - * type. We use this to optimize RI checks: if the new value includes all - * of the old value, then we can treat the attribute as if it didn't - * change, and skip the RI check. - */ - strat = RTContainedByStrategyNumber; - GetOperatorFromWellKnownStrategy(opclass, - InvalidOid, - containedbyoperoid, - &strat); - - /* - * Now look up the ContainedBy operator. Its left arg must be the type of - * the column (or rather of the opclass). Its right arg must match the - * return type of the support proc. - */ - strat = RTContainedByStrategyNumber; - GetOperatorFromWellKnownStrategy(opclass, - ANYMULTIRANGEOID, - aggedcontainedbyoperoid, - &strat); -} - -/* * Determine whether a relation can be proven functionally dependent on * a set of grouping columns. If so, return true and add the pg_constraint * OIDs of the constraints needed for the proof to the *constraintDeps list. diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index d9016ef487b..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], InvalidOid, - &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 @@ -2422,88 +2384,6 @@ GetDefaultOpClass(Oid type_id, Oid am_id) } /* - * GetOperatorFromWellKnownStrategy - * - * opclass - the opclass to use - * rhstype - the type for the right-hand side, or InvalidOid to use the type of the given opclass. - * 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 rhstype, - Oid *opid, StrategyNumber *strat) -{ - Oid opfamily; - Oid opcintype; - StrategyNumber instrat = *strat; - - Assert(instrat == RTEqualStrategyNumber || instrat == RTOverlapStrategyNumber || instrat == RTContainedByStrategyNumber); - - *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(opcintype)) : - instrat == RTOverlapStrategyNumber ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) : - instrat == RTContainedByStrategyNumber ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0, - errdetail("Could not translate strategy number %d for operator class \"%s\" for access method \"%s\".", - instrat, NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname), "gist")); - } - - /* - * We parameterize rhstype so foreign keys can ask for a <@ operator - * whose rhs matches the aggregate function. For example range_agg - * returns anymultirange. - */ - if (!OidIsValid(rhstype)) - rhstype = opcintype; - *opid = get_opfamily_member(opfamily, opcintype, rhstype, *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(opcintype)) : - instrat == RTOverlapStrategyNumber ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) : - instrat == RTContainedByStrategyNumber ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0, - errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".", - NameStr(((Form_pg_opfamily) GETSTRUCT(tuple))->opfname), "gist")); - } -} - -/* * makeObjectName() * * Create a name for an implicitly created index, sequence, constraint, diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 79c9c031833..313c782cae2 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -16,7 +16,6 @@ #include "access/attmap.h" #include "access/genam.h" -#include "access/gist.h" #include "access/heapam.h" #include "access/heapam_xlog.h" #include "access/multixact.h" @@ -216,7 +215,6 @@ typedef struct NewConstraint ConstrType contype; /* CHECK or FOREIGN */ Oid refrelid; /* PK rel, if FOREIGN */ Oid refindid; /* OID of PK's index, if FOREIGN */ - bool conwithperiod; /* Whether the new FOREIGN KEY uses PERIOD */ Oid conid; /* OID of pg_constraint entry, if FOREIGN */ Node *qual; /* Check expr or CONSTR_FOREIGN Constraint */ ExprState *qualstate; /* Execution state for CHECK expr */ @@ -391,17 +389,16 @@ static int transformColumnNameList(Oid relId, List *colList, static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, - Oid *opclasses, bool *pk_has_without_overlaps); + Oid *opclasses); static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, - bool with_period, Oid *opclasses, - bool *pk_has_without_overlaps); + Oid *opclasses); static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts); static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid); static void validateForeignKeyConstraint(char *conname, Relation rel, Relation pkrel, - Oid pkindOid, Oid constraintOid, bool hasperiod); + Oid pkindOid, Oid constraintOid); static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context); @@ -512,8 +509,7 @@ static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstra Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, - Oid parentDelTrigger, Oid parentUpdTrigger, - bool with_period); + Oid parentDelTrigger, Oid parentUpdTrigger); static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols); @@ -523,9 +519,7 @@ static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, LOCKMODE lockmode, - Oid parentInsTrigger, Oid parentUpdTrigger, - bool with_period); - + Oid parentInsTrigger, Oid parentUpdTrigger); static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel, Relation partitionRel); static void CloneFkReferenced(Relation parentRel, Relation partitionRel); @@ -5924,8 +5918,7 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, validateForeignKeyConstraint(fkconstraint->conname, rel, refrel, con->refindid, - con->conid, - con->conwithperiod); + con->conid); /* * No need to mark the constraint row as validated, we did @@ -9566,8 +9559,6 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Oid ppeqoperators[INDEX_MAX_KEYS] = {0}; Oid ffeqoperators[INDEX_MAX_KEYS] = {0}; int16 fkdelsetcols[INDEX_MAX_KEYS] = {0}; - bool with_period; - bool pk_has_without_overlaps; int i; int numfks, numpks, @@ -9662,11 +9653,6 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, numfks = transformColumnNameList(RelationGetRelid(rel), fkconstraint->fk_attrs, fkattnum, fktypoid); - with_period = fkconstraint->fk_with_period || fkconstraint->pk_with_period; - if (with_period && !fkconstraint->fk_with_period) - ereport(ERROR, - errcode(ERRCODE_INVALID_FOREIGN_KEY), - errmsg("foreign key uses PERIOD on the referenced table but not the referencing table")); numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel), fkconstraint->fk_del_set_cols, @@ -9686,41 +9672,19 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid, &fkconstraint->pk_attrs, pkattnum, pktypoid, - opclasses, &pk_has_without_overlaps); - - /* If the primary key uses WITHOUT OVERLAPS, the fk must use PERIOD */ - if (pk_has_without_overlaps && !fkconstraint->fk_with_period) - ereport(ERROR, - errcode(ERRCODE_INVALID_FOREIGN_KEY), - errmsg("foreign key uses PERIOD on the referenced table but not the referencing table")); + opclasses); } else { numpks = transformColumnNameList(RelationGetRelid(pkrel), fkconstraint->pk_attrs, pkattnum, pktypoid); - - /* Since we got pk_attrs, one should be a period. */ - if (with_period && !fkconstraint->pk_with_period) - ereport(ERROR, - errcode(ERRCODE_INVALID_FOREIGN_KEY), - errmsg("foreign key uses PERIOD on the referencing table but not the referenced table")); - /* Look for an index matching the column list */ indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum, - with_period, opclasses, &pk_has_without_overlaps); + opclasses); } /* - * If the referenced primary key has WITHOUT OVERLAPS, the foreign key - * must use PERIOD. - */ - if (pk_has_without_overlaps && !with_period) - ereport(ERROR, - errcode(ERRCODE_INVALID_FOREIGN_KEY), - errmsg("foreign key must use PERIOD when referencing a primary using WITHOUT OVERLAPS")); - - /* * Now we can check permissions. */ checkFkeyPermissions(pkrel, pkattnum, numpks); @@ -9754,28 +9718,6 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, } /* - * Some actions are currently unsupported for foreign keys using PERIOD. - */ - if (fkconstraint->fk_with_period) - { - if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE || - fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL || - fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT) - ereport(ERROR, - errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("unsupported %s action for foreign key constraint using PERIOD", - "ON UPDATE")); - - if (fkconstraint->fk_del_action == FKCONSTR_ACTION_CASCADE || - fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL || - fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT) - ereport(ERROR, - errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("unsupported %s action for foreign key constraint using PERIOD", - "ON DELETE")); - } - - /* * Look up the equality operators to use in the constraint. * * Note that we have to be careful about the difference between the actual @@ -9821,56 +9763,16 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, opcintype = cla_tup->opcintype; ReleaseSysCache(cla_ht); - if (with_period) - { - StrategyNumber rtstrategy; - bool for_overlaps = with_period && i == numpks - 1; - - /* - * GiST indexes are required to support temporal foreign keys - * because they combine equals and overlaps. - */ - if (amid != GIST_AM_OID) - elog(ERROR, "only GiST indexes are supported for temporal foreign keys"); - - rtstrategy = for_overlaps ? RTOverlapStrategyNumber : RTEqualStrategyNumber; - - /* - * An opclass can use whatever strategy numbers it wants, so we - * ask the opclass what number it actually uses instead of our RT* - * constants. - */ - eqstrategy = GistTranslateStratnum(opclasses[i], rtstrategy); - if (eqstrategy == InvalidStrategy) - { - HeapTuple tuple; - - tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i])); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for operator class %u", opclasses[i]); - - ereport(ERROR, - errcode(ERRCODE_UNDEFINED_OBJECT), - for_overlaps - ? errmsg("could not identify an overlaps operator for foreign key") - : errmsg("could not identify an equality operator for foreign key"), - errdetail("Could not translate strategy number %d for operator class \"%s\" for access method \"%s\".", - rtstrategy, NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname), "gist")); - } - } - else - { - /* - * Check it's a btree; currently this can never fail since no - * other index AMs support unique indexes. If we ever did have - * other types of unique indexes, we'd need a way to determine - * which operator strategy number is equality. (We could use - * something like GistTranslateStratnum.) - */ - if (amid != BTREE_AM_OID) - elog(ERROR, "only b-tree indexes are supported for foreign keys"); - eqstrategy = BTEqualStrategyNumber; - } + /* + * Check it's a btree; currently this can never fail since no other + * index AMs support unique indexes. If we ever did have other types + * of unique indexes, we'd need a way to determine which operator + * strategy number is equality. (Is it reasonable to insist that + * every such index AM use btree's number for equality?) + */ + if (amid != BTREE_AM_OID) + elog(ERROR, "only b-tree indexes are supported for foreign keys"); + eqstrategy = BTEqualStrategyNumber; /* * There had better be a primary equality operator for the index. @@ -10021,22 +9923,6 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, } /* - * For FKs with PERIOD we need additional operators to check whether the - * referencing row's range is contained by the aggregated ranges of the - * referenced row(s). For rangetypes and multirangetypes this is - * fk.periodatt <@ range_agg(pk.periodatt). Those are the only types we - * support for now. FKs will look these up at "runtime", but we should - * make sure the lookup works here, even if we don't use the values. - */ - if (with_period) - { - Oid periodoperoid; - Oid aggedperiodoperoid; - - FindFKPeriodOpers(opclasses[numpks - 1], &periodoperoid, &aggedperiodoperoid); - } - - /* * Create all the constraint and trigger objects, recursing to partitions * as necessary. First handle the referenced side. */ @@ -10052,8 +9938,7 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, numfkdelsetcols, fkdelsetcols, old_check_ok, - InvalidOid, InvalidOid, - with_period); + InvalidOid, InvalidOid); /* Now handle the referencing side. */ addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel, @@ -10069,8 +9954,7 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, fkdelsetcols, old_check_ok, lockmode, - InvalidOid, InvalidOid, - with_period); + InvalidOid, InvalidOid); /* * Done. Close pk table, but keep lock until we've committed. @@ -10155,8 +10039,7 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, - Oid parentDelTrigger, Oid parentUpdTrigger, - bool with_period) + Oid parentDelTrigger, Oid parentUpdTrigger) { ObjectAddress address; Oid constrOid; @@ -10242,7 +10125,6 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, conislocal, /* islocal */ coninhcount, /* inhcount */ connoinherit, /* conNoInherit */ - with_period, /* conPeriod */ false); /* is_internal */ ObjectAddressSet(address, ConstraintRelationId, constrOid); @@ -10318,8 +10200,7 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, pfeqoperators, ppeqoperators, ffeqoperators, numfkdelsetcols, fkdelsetcols, old_check_ok, - deleteTriggerOid, updateTriggerOid, - with_period); + deleteTriggerOid, updateTriggerOid); /* Done -- clean up (but keep the lock) */ table_close(partRel, NoLock); @@ -10377,8 +10258,7 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, LOCKMODE lockmode, - Oid parentInsTrigger, Oid parentUpdTrigger, - bool with_period) + Oid parentInsTrigger, Oid parentUpdTrigger) { Oid insertTriggerOid, updateTriggerOid; @@ -10426,7 +10306,6 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, newcon->refrelid = RelationGetRelid(pkrel); newcon->refindid = indexOid; newcon->conid = parentConstr; - newcon->conwithperiod = fkconstraint->fk_with_period; newcon->qual = (Node *) fkconstraint; tab->constraints = lappend(tab->constraints, newcon); @@ -10544,7 +10423,6 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, false, 1, false, - with_period, /* conPeriod */ false); /* @@ -10575,8 +10453,7 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, old_check_ok, lockmode, insertTriggerOid, - updateTriggerOid, - with_period); + updateTriggerOid); table_close(partition, NoLock); } @@ -10812,8 +10689,7 @@ CloneFkReferenced(Relation parentRel, Relation partitionRel) confdelsetcols, true, deleteTriggerOid, - updateTriggerOid, - constrForm->conperiod); + updateTriggerOid); table_close(fkRel, NoLock); ReleaseSysCache(tuple); @@ -10906,7 +10782,6 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel) ListCell *lc; Oid insertTriggerOid, updateTriggerOid; - bool with_period; tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(parentConstrOid)); if (!HeapTupleIsValid(tuple)) @@ -11022,7 +10897,6 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel) fkconstraint->conname = pstrdup(NameStr(constrForm->conname)); indexOid = constrForm->conindid; - with_period = constrForm->conperiod; constrOid = CreateConstraintEntry(fkconstraint->conname, constrForm->connamespace, @@ -11054,7 +10928,6 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel) false, /* islocal */ 1, /* inhcount */ false, /* conNoInherit */ - with_period, /* conPeriod */ true); /* Set up partition dependencies for the new constraint */ @@ -11088,8 +10961,7 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel) false, /* no old check exists */ AccessExclusiveLock, insertTriggerOid, - updateTriggerOid, - with_period); + updateTriggerOid); table_close(pkrel, NoLock); } @@ -11899,8 +11771,7 @@ 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. Also return whether the index has - * WITHOUT OVERLAPS. + * 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. @@ -11911,7 +11782,7 @@ static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, - Oid *opclasses, bool *pk_has_without_overlaps) + Oid *opclasses) { List *indexoidlist; ListCell *indexoidscan; @@ -11989,8 +11860,6 @@ transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno))))); } - *pk_has_without_overlaps = indexStruct->indisexclusion; - ReleaseSysCache(indexTuple); return i; @@ -12004,16 +11873,14 @@ transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, * * Returns the OID of the unique index supporting the constraint and * populates the caller-provided 'opclasses' array with the opclasses - * associated with the index columns. Also sets whether the index - * uses WITHOUT OVERLAPS. + * associated with the index columns. * * Raises an ERROR on validation failure. */ static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, - bool with_period, Oid *opclasses, - bool *pk_has_without_overlaps) + Oid *opclasses) { Oid indexoid = InvalidOid; bool found = false; @@ -12060,12 +11927,12 @@ transformFkeyCheckAttrs(Relation pkrel, indexStruct = (Form_pg_index) GETSTRUCT(indexTuple); /* - * Must have the right number of columns; must be unique (or if - * temporal then exclusion instead) and not a partial index; forget it - * if there are any expressions, too. Invalid indexes are out as well. + * Must have the right number of columns; must be unique and not a + * partial index; forget it if there are any expressions, too. Invalid + * indexes are out as well. */ if (indexStruct->indnkeyatts == numattrs && - (with_period ? indexStruct->indisexclusion : indexStruct->indisunique) && + indexStruct->indisunique && indexStruct->indisvalid && heap_attisnull(indexTuple, Anum_pg_index_indpred, NULL) && heap_attisnull(indexTuple, Anum_pg_index_indexprs, NULL)) @@ -12103,13 +11970,6 @@ transformFkeyCheckAttrs(Relation pkrel, if (!found) break; } - /* The last attribute in the index must be the PERIOD FK part */ - if (found && with_period) - { - int16 periodattnum = attnums[numattrs - 1]; - - found = (periodattnum == indexStruct->indkey.values[numattrs - 1]); - } /* * Refuse to use a deferrable unique/primary key. This is per SQL @@ -12125,10 +11985,6 @@ transformFkeyCheckAttrs(Relation pkrel, found_deferrable = true; found = false; } - - /* We need to know whether the index has WITHOUT OVERLAPS */ - if (found) - *pk_has_without_overlaps = indexStruct->indisexclusion; } ReleaseSysCache(indexTuple); if (found) @@ -12223,8 +12079,7 @@ validateForeignKeyConstraint(char *conname, Relation rel, Relation pkrel, Oid pkindOid, - Oid constraintOid, - bool hasperiod) + Oid constraintOid) { TupleTableSlot *slot; TableScanDesc scan; @@ -12252,11 +12107,9 @@ validateForeignKeyConstraint(char *conname, /* * See if we can do it with a single LEFT JOIN query. A false result - * indicates we must proceed with the fire-the-trigger method. We can't do - * a LEFT JOIN for temporal FKs yet, but we can once we support temporal - * left joins. + * indicates we must proceed with the fire-the-trigger method. */ - if (!hasperiod && RI_Initial_Check(&trig, rel, pkrel)) + if (RI_Initial_Check(&trig, rel, pkrel)) return; /* @@ -12407,7 +12260,6 @@ createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstr fk_trigger->whenClause = NULL; fk_trigger->transitionRels = NIL; fk_trigger->constrrel = NULL; - switch (fkconstraint->fk_del_action) { case FKCONSTR_ACTION_NOACTION: @@ -12468,7 +12320,6 @@ createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstr fk_trigger->whenClause = NULL; fk_trigger->transitionRels = NIL; fk_trigger->constrrel = NULL; - switch (fkconstraint->fk_upd_action) { case FKCONSTR_ACTION_NOACTION: @@ -14245,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 35eb7180f7e..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, /* conperiod */ isInternal); /* is_internal */ } diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 2a6550de907..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, /* conperiod */ 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/executor/execIndexing.c b/src/backend/executor/execIndexing.c index 59acf67a36a..9f05b3654c1 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -210,7 +210,7 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative) * If the indexes are to be used for speculative insertion, add extra * information required by unique index entries. */ - if (speculative && ii->ii_Unique && !indexDesc->rd_index->indisexclusion) + if (speculative && ii->ii_Unique) BuildSpeculativeIndexInfo(indexDesc, ii); relationDescs[i] = indexDesc; diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 26f8de77135..a51fc34e6e0 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -815,7 +815,7 @@ infer_arbiter_indexes(PlannerInfo *root) */ if (indexOidFromConstraint == idxForm->indexrelid) { - if (idxForm->indisexclusion && onconflict->action == ONCONFLICT_UPDATE) + if (!idxForm->indisunique && onconflict->action == ONCONFLICT_UPDATE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("ON CONFLICT DO UPDATE not supported with exclusion constraints"))); @@ -840,13 +840,6 @@ infer_arbiter_indexes(PlannerInfo *root) if (!idxForm->indisunique) goto next; - /* - * So-called unique constraints with WITHOUT OVERLAPS are really - * exclusion constraints, so skip those too. - */ - if (idxForm->indisexclusion) - goto next; - /* Build BMS representation of plain (non expression) index attrs */ indexedAttrs = NULL; for (natt = 0; natt < idxForm->indnkeyatts; natt++) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index cabfba0921b..4d582950b72 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -525,15 +525,14 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); SetResetClause FunctionSetResetClause %type <node> TableElement TypedTableElement ConstraintElem DomainConstraintElem TableFuncElement -%type <node> columnDef columnOptions optionalPeriodName +%type <node> columnDef columnOptions %type <defelt> def_elem reloption_elem old_aggr_elem operator_def_elem %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> opt_column_and_period_list %type <list> rowsfrom_item rowsfrom_list opt_col_def_list -%type <boolean> opt_ordinality opt_without_overlaps +%type <boolean> opt_ordinality %type <list> ExclusionConstraintList ExclusionConstraintElem %type <list> func_arg_list func_arg_list_opt %type <node> func_arg_expr @@ -765,7 +764,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER PARALLEL PARAMETER PARSER PARTIAL PARTITION PARTITIONS PASSING PASSWORD PATH - PERIOD PLACING PLAN PLANS POLICY + PLACING PLAN PLANS POLICY POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION @@ -4194,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); @@ -4203,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; @@ -4229,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); @@ -4237,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; @@ -4283,31 +4280,21 @@ ConstraintElem: NULL, yyscanner); $$ = (Node *) n; } - | FOREIGN KEY '(' columnList optionalPeriodName ')' REFERENCES qualified_name - opt_column_and_period_list key_match key_actions ConstraintAttributeSpec + | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name + opt_column_list key_match key_actions ConstraintAttributeSpec { Constraint *n = makeNode(Constraint); n->contype = CONSTR_FOREIGN; n->location = @1; - n->pktable = $8; + n->pktable = $7; n->fk_attrs = $4; - if ($5) - { - n->fk_attrs = lappend(n->fk_attrs, $5); - n->fk_with_period = true; - } - n->pk_attrs = linitial($9); - if (lsecond($9)) - { - n->pk_attrs = lappend(n->pk_attrs, lsecond($9)); - n->pk_with_period = true; - } - n->fk_matchtype = $10; - n->fk_upd_action = ($11)->updateAction->action; - n->fk_del_action = ($11)->deleteAction->action; - n->fk_del_set_cols = ($11)->deleteAction->cols; - processCASbits($12, @12, "FOREIGN KEY", + n->pk_attrs = $8; + n->fk_matchtype = $9; + n->fk_upd_action = ($10)->updateAction->action; + n->fk_del_action = ($10)->deleteAction->action; + n->fk_del_set_cols = ($10)->deleteAction->cols; + processCASbits($11, @11, "FOREIGN KEY", &n->deferrable, &n->initdeferred, &n->skip_validation, NULL, yyscanner); @@ -4374,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; } @@ -4389,16 +4371,6 @@ columnList: | columnList ',' columnElem { $$ = lappend($1, $3); } ; -optionalPeriodName: - ',' PERIOD columnElem { $$ = $3; } - | /*EMPTY*/ { $$ = NULL; } - ; - -opt_column_and_period_list: - '(' columnList optionalPeriodName ')' { $$ = list_make2($2, $3); } - | /*EMPTY*/ { $$ = list_make2(NIL, NULL); } - ; - columnElem: ColId { $$ = (Node *) makeString($1); @@ -17793,7 +17765,6 @@ unreserved_keyword: | PASSING | PASSWORD | PATH - | PERIOD | PLAN | PLANS | POLICY @@ -18420,7 +18391,6 @@ bare_label_keyword: | PASSING | PASSWORD | PATH - | PERIOD | PLACING | PLAN | PLANS 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/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index bbc2e3e2f0a..62601a6d80c 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -30,7 +30,6 @@ #include "access/xact.h" #include "catalog/pg_collation.h" #include "catalog/pg_constraint.h" -#include "catalog/pg_proc.h" #include "commands/trigger.h" #include "executor/executor.h" #include "executor/spi.h" @@ -46,7 +45,6 @@ #include "utils/inval.h" #include "utils/lsyscache.h" #include "utils/memutils.h" -#include "utils/rangetypes.h" #include "utils/rel.h" #include "utils/rls.h" #include "utils/ruleutils.h" @@ -98,9 +96,6 @@ * * Information extracted from an FK pg_constraint entry. This is cached in * ri_constraint_cache. - * - * Note that pf/pp/ff_eq_oprs may hold the overlaps operator instead of equals - * for the PERIOD part of a temporal foreign key. */ typedef struct RI_ConstraintInfo { @@ -120,15 +115,12 @@ typedef struct RI_ConstraintInfo int16 confdelsetcols[RI_MAX_NUMKEYS]; /* attnums of cols to set on * delete */ char confmatchtype; /* foreign key's match type */ - bool hasperiod; /* if the foreign key uses PERIOD */ int nkeys; /* number of key columns */ int16 pk_attnums[RI_MAX_NUMKEYS]; /* attnums of referenced cols */ int16 fk_attnums[RI_MAX_NUMKEYS]; /* attnums of referencing cols */ Oid pf_eq_oprs[RI_MAX_NUMKEYS]; /* equality operators (PK = FK) */ Oid pp_eq_oprs[RI_MAX_NUMKEYS]; /* equality operators (PK = PK) */ Oid ff_eq_oprs[RI_MAX_NUMKEYS]; /* equality operators (FK = FK) */ - Oid period_contained_by_oper; /* anyrange <@ anyrange */ - Oid agged_period_contained_by_oper; /* fkattr <@ range_agg(pkattr) */ dlist_node valid_link; /* Link in list of valid entries */ } RI_ConstraintInfo; @@ -207,8 +199,8 @@ static void ri_BuildQueryKey(RI_QueryKey *key, int32 constr_queryno); static bool ri_KeysEqual(Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot, const RI_ConstraintInfo *riinfo, bool rel_is_pk); -static bool ri_CompareWithCast(Oid eq_opr, Oid typeid, - Datum lhs, Datum rhs); +static bool ri_AttributesEqual(Oid eq_opr, Oid typeid, + Datum oldvalue, Datum newvalue); static void ri_InitHashTables(void); static void InvalidateConstraintCacheCallBack(Datum arg, int cacheid, uint32 hashvalue); @@ -370,41 +362,14 @@ RI_FKey_check(TriggerData *trigdata) * FOR KEY SHARE OF x * The type id's for the $ parameters are those of the * corresponding FK attributes. - * - * But for temporal FKs we need to make sure - * the FK's range is completely covered. - * So we use this query instead: - * SELECT 1 - * FROM ( - * SELECT pkperiodatt AS r - * FROM [ONLY] pktable x - * WHERE pkatt1 = $1 [AND ...] - * AND pkperiodatt && $n - * FOR KEY SHARE OF x - * ) x1 - * HAVING $n <@ range_agg(x1.r) - * Note if FOR KEY SHARE ever allows GROUP BY and HAVING - * we can make this a bit simpler. * ---------- */ initStringInfo(&querybuf); pk_only = pk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY "; quoteRelationName(pkrelname, pk_rel); - if (riinfo->hasperiod) - { - quoteOneName(attname, - RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1])); - - appendStringInfo(&querybuf, - "SELECT 1 FROM (SELECT %s AS r FROM %s%s x", - attname, pk_only, pkrelname); - } - else - { - appendStringInfo(&querybuf, "SELECT 1 FROM %s%s x", - pk_only, pkrelname); - } + appendStringInfo(&querybuf, "SELECT 1 FROM %s%s x", + pk_only, pkrelname); querysep = "WHERE"; for (int i = 0; i < riinfo->nkeys; i++) { @@ -422,18 +387,6 @@ RI_FKey_check(TriggerData *trigdata) queryoids[i] = fk_type; } appendStringInfoString(&querybuf, " FOR KEY SHARE OF x"); - if (riinfo->hasperiod) - { - Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[riinfo->nkeys - 1]); - - appendStringInfoString(&querybuf, ") x1 HAVING "); - sprintf(paramname, "$%d", riinfo->nkeys); - ri_GenerateQual(&querybuf, "", - paramname, fk_type, - riinfo->agged_period_contained_by_oper, - "pg_catalog.range_agg", ANYMULTIRANGEOID); - appendStringInfoString(&querybuf, "(x1.r)"); - } /* Prepare and save the plan */ qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids, @@ -541,39 +494,14 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel, * FOR KEY SHARE OF x * The type id's for the $ parameters are those of the * PK attributes themselves. - * But for temporal FKs we need to make sure - * the FK's range is completely covered. - * So we use this query instead: - * SELECT 1 - * FROM ( - * SELECT pkperiodatt AS r - * FROM [ONLY] pktable x - * WHERE pkatt1 = $1 [AND ...] - * AND pkperiodatt && $n - * FOR KEY SHARE OF x - * ) x1 - * HAVING $n <@ range_agg(x1.r) - * Note if FOR KEY SHARE ever allows GROUP BY and HAVING - * we can make this a bit simpler. * ---------- */ initStringInfo(&querybuf); pk_only = pk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY "; quoteRelationName(pkrelname, pk_rel); - if (riinfo->hasperiod) - { - quoteOneName(attname, RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1])); - - appendStringInfo(&querybuf, - "SELECT 1 FROM (SELECT %s AS r FROM %s%s x", - attname, pk_only, pkrelname); - } - else - { - appendStringInfo(&querybuf, "SELECT 1 FROM %s%s x", - pk_only, pkrelname); - } + appendStringInfo(&querybuf, "SELECT 1 FROM %s%s x", + pk_only, pkrelname); querysep = "WHERE"; for (int i = 0; i < riinfo->nkeys; i++) { @@ -590,18 +518,6 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel, queryoids[i] = pk_type; } appendStringInfoString(&querybuf, " FOR KEY SHARE OF x"); - if (riinfo->hasperiod) - { - Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[riinfo->nkeys - 1]); - - appendStringInfoString(&querybuf, ") x1 HAVING "); - sprintf(paramname, "$%d", riinfo->nkeys); - ri_GenerateQual(&querybuf, "", - paramname, fk_type, - riinfo->agged_period_contained_by_oper, - "pg_catalog.range_agg", ANYMULTIRANGEOID); - appendStringInfoString(&querybuf, "(x1.r)"); - } /* Prepare and save the plan */ qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids, @@ -2246,7 +2162,6 @@ ri_LoadConstraintInfo(Oid constraintOid) riinfo->confupdtype = conForm->confupdtype; riinfo->confdeltype = conForm->confdeltype; riinfo->confmatchtype = conForm->confmatchtype; - riinfo->hasperiod = conForm->conperiod; DeconstructFkConstraintRow(tup, &riinfo->nkeys, @@ -2258,20 +2173,6 @@ ri_LoadConstraintInfo(Oid constraintOid) &riinfo->ndelsetcols, riinfo->confdelsetcols); - /* - * For temporal FKs, get the operators and functions we need. We ask the - * opclass of the PK element for these. This all gets cached (as does the - * generated plan), so there's no performance issue. - */ - if (riinfo->hasperiod) - { - Oid opclass = get_index_column_opclass(conForm->conindid, riinfo->nkeys); - - FindFKPeriodOpers(opclass, - &riinfo->period_contained_by_oper, - &riinfo->agged_period_contained_by_oper); - } - ReleaseSysCache(tup); /* @@ -2883,10 +2784,7 @@ ri_HashPreparedPlan(RI_QueryKey *key, SPIPlanPtr plan) /* * ri_KeysEqual - * - * Check if all key values in OLD and NEW are "equivalent": - * For normal FKs we check for equality. - * For temporal FKs we check that the PK side is a superset of its old value, - * or the FK side is a subset of its old value. + * Check if all key values in OLD and NEW are equal. * * Note: at some point we might wish to redefine this as checking for * "IS NOT DISTINCT" rather than "=", that is, allow two nulls to be @@ -2942,25 +2840,13 @@ ri_KeysEqual(Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot, } else { - Oid eq_opr; - - /* - * When comparing the PERIOD columns we can skip the check - * whenever the referencing column stayed equal or shrank, so test - * with the contained-by operator instead. - */ - if (riinfo->hasperiod && i == riinfo->nkeys - 1) - eq_opr = riinfo->period_contained_by_oper; - else - eq_opr = riinfo->ff_eq_oprs[i]; - /* * For the FK table, compare with the appropriate equality * operator. Changes that compare equal will still satisfy the * constraint after the update. */ - if (!ri_CompareWithCast(eq_opr, RIAttType(rel, attnums[i]), - newvalue, oldvalue)) + if (!ri_AttributesEqual(riinfo->ff_eq_oprs[i], RIAttType(rel, attnums[i]), + oldvalue, newvalue)) return false; } } @@ -2970,31 +2856,29 @@ ri_KeysEqual(Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot, /* - * ri_CompareWithCast - + * ri_AttributesEqual - * - * Call the appropriate comparison operator for two values. - * Normally this is equality, but for the PERIOD part of foreign keys - * it is ContainedBy, so the order of lhs vs rhs is significant. + * Call the appropriate equality comparison operator for two values. * * NB: we have already checked that neither value is null. */ static bool -ri_CompareWithCast(Oid eq_opr, Oid typeid, - Datum lhs, Datum rhs) +ri_AttributesEqual(Oid eq_opr, Oid typeid, + Datum oldvalue, Datum newvalue) { RI_CompareHashEntry *entry = ri_HashCompareOp(eq_opr, typeid); /* Do we need to cast the values? */ if (OidIsValid(entry->cast_func_finfo.fn_oid)) { - lhs = FunctionCall3(&entry->cast_func_finfo, - lhs, - Int32GetDatum(-1), /* typmod */ - BoolGetDatum(false)); /* implicit coercion */ - rhs = FunctionCall3(&entry->cast_func_finfo, - rhs, - Int32GetDatum(-1), /* typmod */ - BoolGetDatum(false)); /* implicit coercion */ + oldvalue = FunctionCall3(&entry->cast_func_finfo, + oldvalue, + Int32GetDatum(-1), /* typmod */ + BoolGetDatum(false)); /* implicit coercion */ + newvalue = FunctionCall3(&entry->cast_func_finfo, + newvalue, + Int32GetDatum(-1), /* typmod */ + BoolGetDatum(false)); /* implicit coercion */ } /* @@ -3008,16 +2892,10 @@ ri_CompareWithCast(Oid eq_opr, Oid typeid, * open), we'll just use the default collation here, which could lead to * some false negatives. All this would break if we ever allow * database-wide collations to be nondeterministic. - * - * With range/multirangetypes, the collation of the base type is stored as - * part of the rangetype (pg_range.rngcollation), and always used, so - * there is no danger of inconsistency even using a non-equals operator. - * But if we support arbitrary types with PERIOD, we should perhaps just - * always force a re-check. */ return DatumGetBool(FunctionCall2Coll(&entry->eq_opr_finfo, DEFAULT_COLLATION_OID, - lhs, rhs)); + oldvalue, newvalue)); } /* @@ -3072,7 +2950,7 @@ ri_HashCompareOp(Oid eq_opr, Oid typeid) * the cast function to get to the operator's input type. * * XXX eventually it would be good to support array-coercion cases - * here and in ri_CompareWithCast(). At the moment there is no point + * here and in ri_AttributesEqual(). At the moment there is no point * because cases involving nonidentical array types will be rejected * at constraint creation time. * diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 9a6d372414c..9618619762b 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -338,7 +338,7 @@ 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, - bool withPeriod, StringInfo buf); + StringInfo buf); static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags); static char *pg_get_indexdef_worker(Oid indexrelid, int colno, const Oid *excludeOps, @@ -2260,8 +2260,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, val = SysCacheGetAttrNotNull(CONSTROID, tup, Anum_pg_constraint_conkey); - /* If it is a temporal foreign key then it uses PERIOD. */ - decompile_column_index_array(val, conForm->conrelid, conForm->conperiod, &buf); + decompile_column_index_array(val, conForm->conrelid, &buf); /* add foreign relation name */ appendStringInfo(&buf, ") REFERENCES %s(", @@ -2272,7 +2271,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->conperiod, &buf); + decompile_column_index_array(val, conForm->confrelid, &buf); appendStringInfoChar(&buf, ')'); @@ -2358,7 +2357,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, if (!isnull) { appendStringInfoString(&buf, " ("); - decompile_column_index_array(val, conForm->conrelid, false, &buf); + decompile_column_index_array(val, conForm->conrelid, &buf); appendStringInfoChar(&buf, ')'); } @@ -2393,9 +2392,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, val = SysCacheGetAttrNotNull(CONSTROID, tup, Anum_pg_constraint_conkey); - keyatts = decompile_column_index_array(val, conForm->conrelid, false, &buf); - if (conForm->conperiod) - appendStringInfoString(&buf, " WITHOUT OVERLAPS"); + keyatts = decompile_column_index_array(val, conForm->conrelid, &buf); appendStringInfoChar(&buf, ')'); @@ -2577,7 +2574,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, */ static int decompile_column_index_array(Datum column_index_array, Oid relId, - bool withPeriod, StringInfo buf) + StringInfo buf) { Datum *keys; int nKeys; @@ -2596,9 +2593,7 @@ decompile_column_index_array(Datum column_index_array, Oid relId, if (j == 0) appendStringInfoString(buf, quote_identifier(colName)); else - appendStringInfo(buf, ", %s%s", - (withPeriod && j == nKeys - 1) ? "PERIOD " : "", - quote_identifier(colName)); + appendStringInfo(buf, ", %s", quote_identifier(colName)); } return nKeys; diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index e6072cbdd9e..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->conperiod && ( - conform->contype == CONSTRAINT_PRIMARY - || conform->contype == CONSTRAINT_UNIQUE))) || + if (conform->contype != CONSTRAINT_EXCLUSION || conform->conindid != RelationGetRelid(indexRelation)) continue; |
