diff options
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r-- | src/backend/utils/adt/ri_triggers.c | 168 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 19 |
2 files changed, 30 insertions, 157 deletions
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; |