Refactor duplicate code into DeconstructFkConstraintRow
authorAlvaro Herrera <[email protected]>
Fri, 18 Jan 2019 17:40:13 +0000 (14:40 -0300)
committerAlvaro Herrera <[email protected]>
Fri, 18 Jan 2019 17:59:44 +0000 (14:59 -0300)
My commit 3de241dba86f introduced some code (in tablecmds.c) to obtain
data from a pg_constraint row for a foreign key, that already existed in
ri_triggers.c.  Split it out into its own routine in pg_constraint.c,
where it naturally belongs.

No functional code changes, only code movement.

Backpatch to pg11, because a future bugfix is simpler after this.

src/backend/catalog/pg_constraint.c
src/backend/utils/adt/ri_triggers.c
src/backend/utils/cache/relcache.c
src/include/catalog/pg_constraint.h

index 3c960c9423a549704ccd3946cc88257ccfcc0218..cfd131460d12a858c83fbd4c8cb8c0474c6ac1b5 100644 (file)
@@ -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
index e606eb342fdeb88f4a0b856ad72eb7a9ca49aa72..0c1ee8d1f6986816b83a7ea81a150b79a533073b 100644 (file)
@@ -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);
 
index e3b1473e6c9905cc2170b93cde7bacd53b14e00a..7ea371a3c712d52900a3ccef1db77444ee07aea9 100644 (file)
@@ -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);
index d2eafd10df482d58c15313651b26cecf736d2122..0944dc8be74a93f18c381ebb2422aba7d94308ae 100644 (file)
@@ -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,