diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index 3c960c9423..cfd131460d 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -446,14 +446,11 @@ static void clone_fk_constraints(Relation pg_constraint, Relation parentRel, Relation partRel, List *clone, List **cloned) { - TupleDesc tupdesc; AttrNumber *attmap; List *partFKs; List *subclone = NIL; ListCell *cell; - tupdesc = RelationGetDescr(pg_constraint); - /* * The constraint key may differ, if the columns in the partition are * different. This map is used to convert them. @@ -483,9 +480,6 @@ clone_fk_constraints(Relation pg_constraint, Relation parentRel, int nelem; ListCell *cell; int i; - ArrayType *arr; - Datum datum; - bool isnull; tuple = SearchSysCache1(CONSTROID, parentConstrOid); if (!tuple) @@ -502,93 +496,11 @@ clone_fk_constraints(Relation pg_constraint, Relation parentRel, ObjectAddressSet(parentAddr, ConstraintRelationId, parentConstrOid); - datum = fastgetattr(tuple, Anum_pg_constraint_conkey, - tupdesc, &isnull); - if (isnull) - elog(ERROR, "null conkey"); - arr = DatumGetArrayTypeP(datum); - nelem = ARR_DIMS(arr)[0]; - if (ARR_NDIM(arr) != 1 || - nelem < 1 || - nelem > INDEX_MAX_KEYS || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != INT2OID) - elog(ERROR, "conkey is not a 1-D smallint array"); - memcpy(conkey, ARR_DATA_PTR(arr), nelem * sizeof(AttrNumber)); - + DeconstructFkConstraintRow(tuple, &nelem, conkey, confkey, + conpfeqop, conppeqop, conffeqop); for (i = 0; i < nelem; i++) mapped_conkey[i] = attmap[conkey[i] - 1]; - datum = fastgetattr(tuple, Anum_pg_constraint_confkey, - tupdesc, &isnull); - if (isnull) - elog(ERROR, "null confkey"); - arr = DatumGetArrayTypeP(datum); - nelem = ARR_DIMS(arr)[0]; - if (ARR_NDIM(arr) != 1 || - nelem < 1 || - nelem > INDEX_MAX_KEYS || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != INT2OID) - elog(ERROR, "confkey is not a 1-D smallint array"); - memcpy(confkey, ARR_DATA_PTR(arr), nelem * sizeof(AttrNumber)); - - datum = fastgetattr(tuple, Anum_pg_constraint_conpfeqop, - tupdesc, &isnull); - if (isnull) - elog(ERROR, "null conpfeqop"); - arr = DatumGetArrayTypeP(datum); - nelem = ARR_DIMS(arr)[0]; - if (ARR_NDIM(arr) != 1 || - nelem < 1 || - nelem > INDEX_MAX_KEYS || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != OIDOID) - elog(ERROR, "conpfeqop is not a 1-D OID array"); - memcpy(conpfeqop, ARR_DATA_PTR(arr), nelem * sizeof(Oid)); - - datum = fastgetattr(tuple, Anum_pg_constraint_conpfeqop, - tupdesc, &isnull); - if (isnull) - elog(ERROR, "null conpfeqop"); - arr = DatumGetArrayTypeP(datum); - nelem = ARR_DIMS(arr)[0]; - if (ARR_NDIM(arr) != 1 || - nelem < 1 || - nelem > INDEX_MAX_KEYS || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != OIDOID) - elog(ERROR, "conpfeqop is not a 1-D OID array"); - memcpy(conpfeqop, ARR_DATA_PTR(arr), nelem * sizeof(Oid)); - - datum = fastgetattr(tuple, Anum_pg_constraint_conppeqop, - tupdesc, &isnull); - if (isnull) - elog(ERROR, "null conppeqop"); - arr = DatumGetArrayTypeP(datum); - nelem = ARR_DIMS(arr)[0]; - if (ARR_NDIM(arr) != 1 || - nelem < 1 || - nelem > INDEX_MAX_KEYS || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != OIDOID) - elog(ERROR, "conppeqop is not a 1-D OID array"); - memcpy(conppeqop, ARR_DATA_PTR(arr), nelem * sizeof(Oid)); - - datum = fastgetattr(tuple, Anum_pg_constraint_conffeqop, - tupdesc, &isnull); - if (isnull) - elog(ERROR, "null conffeqop"); - arr = DatumGetArrayTypeP(datum); - nelem = ARR_DIMS(arr)[0]; - if (ARR_NDIM(arr) != 1 || - nelem < 1 || - nelem > INDEX_MAX_KEYS || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != OIDOID) - elog(ERROR, "conffeqop is not a 1-D OID array"); - memcpy(conffeqop, ARR_DATA_PTR(arr), nelem * sizeof(Oid)); - /* * Before creating a new constraint, see whether any existing FKs are * fit for the purpose. If one is, attach the parent constraint to it, @@ -1530,6 +1442,115 @@ get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid) return pkattnos; } +/* + * Extract data from the pg_constraint tuple of a foreign-key constraint. + * + * All arguments save the first are output arguments; the last three of them + * can be passed as NULL if caller doesn't need them. + */ +void +DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, + AttrNumber *conkey, AttrNumber *confkey, + Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs) +{ + Oid constrId; + Datum adatum; + bool isNull; + ArrayType *arr; + int numkeys; + + constrId = ((Form_pg_constraint) GETSTRUCT(tuple))->oid; + + /* + * We expect the arrays to be 1-D arrays of the right types; verify that. + * We don't need to use deconstruct_array() since the array data is just + * going to look like a C array of values. + */ + adatum = SysCacheGetAttr(CONSTROID, tuple, + Anum_pg_constraint_conkey, &isNull); + if (isNull) + elog(ERROR, "null conkey for constraint %u", constrId); + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + if (ARR_NDIM(arr) != 1 || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != INT2OID) + elog(ERROR, "conkey is not a 1-D smallint array"); + numkeys = ARR_DIMS(arr)[0]; + if (numkeys <= 0 || numkeys > INDEX_MAX_KEYS) + elog(ERROR, "foreign key constraint cannot have %d columns", numkeys); + memcpy(conkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16)); + if ((Pointer) arr != DatumGetPointer(adatum)) + pfree(arr); /* free de-toasted copy, if any */ + + adatum = SysCacheGetAttr(CONSTROID, tuple, + Anum_pg_constraint_confkey, &isNull); + if (isNull) + elog(ERROR, "null confkey for constraint %u", constrId); + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + if (ARR_NDIM(arr) != 1 || + ARR_DIMS(arr)[0] != numkeys || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != INT2OID) + elog(ERROR, "confkey is not a 1-D smallint array"); + memcpy(confkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16)); + if ((Pointer) arr != DatumGetPointer(adatum)) + pfree(arr); /* free de-toasted copy, if any */ + + if (pf_eq_oprs) + { + adatum = SysCacheGetAttr(CONSTROID, tuple, + Anum_pg_constraint_conpfeqop, &isNull); + if (isNull) + elog(ERROR, "null conpfeqop for constraint %u", constrId); + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + /* see TryReuseForeignKey if you change the test below */ + if (ARR_NDIM(arr) != 1 || + ARR_DIMS(arr)[0] != numkeys || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != OIDOID) + elog(ERROR, "conpfeqop is not a 1-D Oid array"); + memcpy(pf_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid)); + if ((Pointer) arr != DatumGetPointer(adatum)) + pfree(arr); /* free de-toasted copy, if any */ + } + + if (pp_eq_oprs) + { + adatum = SysCacheGetAttr(CONSTROID, tuple, + Anum_pg_constraint_conppeqop, &isNull); + if (isNull) + elog(ERROR, "null conppeqop for constraint %u", constrId); + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + if (ARR_NDIM(arr) != 1 || + ARR_DIMS(arr)[0] != numkeys || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != OIDOID) + elog(ERROR, "conppeqop is not a 1-D Oid array"); + memcpy(pp_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid)); + if ((Pointer) arr != DatumGetPointer(adatum)) + pfree(arr); /* free de-toasted copy, if any */ + } + + if (ff_eq_oprs) + { + adatum = SysCacheGetAttr(CONSTROID, tuple, + Anum_pg_constraint_conffeqop, &isNull); + if (isNull) + elog(ERROR, "null conffeqop for constraint %u", constrId); + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + if (ARR_NDIM(arr) != 1 || + ARR_DIMS(arr)[0] != numkeys || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != OIDOID) + elog(ERROR, "conffeqop is not a 1-D Oid array"); + memcpy(ff_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid)); + if ((Pointer) arr != DatumGetPointer(adatum)) + pfree(arr); /* free de-toasted copy, if any */ + } + + *numfks = numkeys; +} + /* * Determine whether a relation can be proven functionally dependent on * a set of grouping columns. If so, return true and add the pg_constraint diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index e606eb342f..0c1ee8d1f6 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -2189,10 +2189,6 @@ ri_LoadConstraintInfo(Oid constraintOid) bool found; HeapTuple tup; Form_pg_constraint conForm; - Datum adatum; - bool isNull; - ArrayType *arr; - int numkeys; /* * On the first call initialize the hashtable @@ -2234,84 +2230,13 @@ ri_LoadConstraintInfo(Oid constraintOid) riinfo->confdeltype = conForm->confdeltype; riinfo->confmatchtype = conForm->confmatchtype; - /* - * We expect the arrays to be 1-D arrays of the right types; verify that. - * We don't need to use deconstruct_array() since the array data is just - * going to look like a C array of values. - */ - adatum = SysCacheGetAttr(CONSTROID, tup, - Anum_pg_constraint_conkey, &isNull); - if (isNull) - elog(ERROR, "null conkey for constraint %u", constraintOid); - arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ - if (ARR_NDIM(arr) != 1 || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != INT2OID) - elog(ERROR, "conkey is not a 1-D smallint array"); - numkeys = ARR_DIMS(arr)[0]; - if (numkeys <= 0 || numkeys > RI_MAX_NUMKEYS) - elog(ERROR, "foreign key constraint cannot have %d columns", numkeys); - riinfo->nkeys = numkeys; - memcpy(riinfo->fk_attnums, ARR_DATA_PTR(arr), numkeys * sizeof(int16)); - if ((Pointer) arr != DatumGetPointer(adatum)) - pfree(arr); /* free de-toasted copy, if any */ - - adatum = SysCacheGetAttr(CONSTROID, tup, - Anum_pg_constraint_confkey, &isNull); - if (isNull) - elog(ERROR, "null confkey for constraint %u", constraintOid); - arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ - if (ARR_NDIM(arr) != 1 || - ARR_DIMS(arr)[0] != numkeys || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != INT2OID) - elog(ERROR, "confkey is not a 1-D smallint array"); - memcpy(riinfo->pk_attnums, ARR_DATA_PTR(arr), numkeys * sizeof(int16)); - if ((Pointer) arr != DatumGetPointer(adatum)) - pfree(arr); /* free de-toasted copy, if any */ - - adatum = SysCacheGetAttr(CONSTROID, tup, - Anum_pg_constraint_conpfeqop, &isNull); - if (isNull) - elog(ERROR, "null conpfeqop for constraint %u", constraintOid); - arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ - /* see TryReuseForeignKey if you change the test below */ - if (ARR_NDIM(arr) != 1 || - ARR_DIMS(arr)[0] != numkeys || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != OIDOID) - elog(ERROR, "conpfeqop is not a 1-D Oid array"); - memcpy(riinfo->pf_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid)); - if ((Pointer) arr != DatumGetPointer(adatum)) - pfree(arr); /* free de-toasted copy, if any */ - - adatum = SysCacheGetAttr(CONSTROID, tup, - Anum_pg_constraint_conppeqop, &isNull); - if (isNull) - elog(ERROR, "null conppeqop for constraint %u", constraintOid); - arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ - if (ARR_NDIM(arr) != 1 || - ARR_DIMS(arr)[0] != numkeys || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != OIDOID) - elog(ERROR, "conppeqop is not a 1-D Oid array"); - memcpy(riinfo->pp_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid)); - if ((Pointer) arr != DatumGetPointer(adatum)) - pfree(arr); /* free de-toasted copy, if any */ - - adatum = SysCacheGetAttr(CONSTROID, tup, - Anum_pg_constraint_conffeqop, &isNull); - if (isNull) - elog(ERROR, "null conffeqop for constraint %u", constraintOid); - arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ - if (ARR_NDIM(arr) != 1 || - ARR_DIMS(arr)[0] != numkeys || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != OIDOID) - elog(ERROR, "conffeqop is not a 1-D Oid array"); - memcpy(riinfo->ff_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid)); - if ((Pointer) arr != DatumGetPointer(adatum)) - pfree(arr); /* free de-toasted copy, if any */ + DeconstructFkConstraintRow(tup, + &riinfo->nkeys, + riinfo->fk_attnums, + riinfo->pk_attnums, + riinfo->pf_eq_oprs, + riinfo->pp_eq_oprs, + riinfo->ff_eq_oprs); ReleaseSysCache(tup); diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index e3b1473e6c..7ea371a3c7 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -4125,10 +4125,6 @@ RelationGetFKeyList(Relation relation) { Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup); ForeignKeyCacheInfo *info; - Datum adatum; - bool isnull; - ArrayType *arr; - int nelem; /* consider only foreign keys */ if (constraint->contype != CONSTRAINT_FOREIGN) @@ -4139,58 +4135,11 @@ RelationGetFKeyList(Relation relation) info->conrelid = constraint->conrelid; info->confrelid = constraint->confrelid; - /* Extract data from conkey field */ - adatum = fastgetattr(htup, Anum_pg_constraint_conkey, - conrel->rd_att, &isnull); - if (isnull) - elog(ERROR, "null conkey for rel %s", - RelationGetRelationName(relation)); - - arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ - nelem = ARR_DIMS(arr)[0]; - if (ARR_NDIM(arr) != 1 || - nelem < 1 || - nelem > INDEX_MAX_KEYS || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != INT2OID) - elog(ERROR, "conkey is not a 1-D smallint array"); - - info->nkeys = nelem; - memcpy(info->conkey, ARR_DATA_PTR(arr), nelem * sizeof(AttrNumber)); - - /* Likewise for confkey */ - adatum = fastgetattr(htup, Anum_pg_constraint_confkey, - conrel->rd_att, &isnull); - if (isnull) - elog(ERROR, "null confkey for rel %s", - RelationGetRelationName(relation)); - - arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ - nelem = ARR_DIMS(arr)[0]; - if (ARR_NDIM(arr) != 1 || - nelem != info->nkeys || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != INT2OID) - elog(ERROR, "confkey is not a 1-D smallint array"); - - memcpy(info->confkey, ARR_DATA_PTR(arr), nelem * sizeof(AttrNumber)); - - /* Likewise for conpfeqop */ - adatum = fastgetattr(htup, Anum_pg_constraint_conpfeqop, - conrel->rd_att, &isnull); - if (isnull) - elog(ERROR, "null conpfeqop for rel %s", - RelationGetRelationName(relation)); - - arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ - nelem = ARR_DIMS(arr)[0]; - if (ARR_NDIM(arr) != 1 || - nelem != info->nkeys || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != OIDOID) - elog(ERROR, "conpfeqop is not a 1-D OID array"); - - memcpy(info->conpfeqop, ARR_DATA_PTR(arr), nelem * sizeof(Oid)); + DeconstructFkConstraintRow(htup, &info->nkeys, + info->conkey, + info->confkey, + info->conpfeqop, + NULL, NULL); /* Add FK's node to the result list */ result = lappend(result, info); diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h index d2eafd10df..0944dc8be7 100644 --- a/src/include/catalog/pg_constraint.h +++ b/src/include/catalog/pg_constraint.h @@ -251,6 +251,9 @@ extern Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId); extern Bitmapset *get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid); +extern void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, + AttrNumber *conkey, AttrNumber *confkey, + Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs); extern bool check_functional_grouping(Oid relid, Index varno, Index varlevelsup,