refactor: split ATExecAlterConstrRecurse()
authorPeter Eisentraut <[email protected]>
Thu, 16 Jan 2025 12:22:01 +0000 (13:22 +0100)
committerPeter Eisentraut <[email protected]>
Thu, 16 Jan 2025 12:24:11 +0000 (13:24 +0100)
This splits out a couple of subroutines from
ATExecAlterConstrRecurse().  This makes the main function a bit
smaller, and a future patch (NOT ENFORCED foreign-key constraints)
will also want to call some of the pieces separately.

Author: Amul Sul <[email protected]>
Reviewed-by: jian he <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/CAAJ_b962c5AcYW9KUt_R_ER5qs3fUGbe4az-SP-vuwPS-w-AGA%40mail.gmail.com

src/backend/commands/tablecmds.c

index d02d564883ae2a00366855098df2a52b38f7b1f5..c42a740ccef845b7d85b796d83610fd7011d4b86 100644 (file)
@@ -394,6 +394,12 @@ static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
 static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
                                     Relation rel, HeapTuple contuple, List **otherrelids,
                                     LOCKMODE lockmode);
+static void AlterConstrTriggerDeferrability(Oid conoid, Relation tgrel, Relation rel,
+                                           bool deferrable, bool initdeferred,
+                                           List **otherrelids);
+static void ATExecAlterChildConstr(Constraint *cmdcon, Relation conrel, Relation tgrel,
+                                  Relation rel, HeapTuple contuple, List **otherrelids,
+                                  LOCKMODE lockmode);
 static ObjectAddress ATExecValidateConstraint(List **wqueue,
                                              Relation rel, char *constrName,
                                              bool recurse, bool recursing, LOCKMODE lockmode);
@@ -11861,9 +11867,6 @@ ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
    {
        HeapTuple   copyTuple;
        Form_pg_constraint copy_con;
-       HeapTuple   tgtuple;
-       ScanKeyData tgkey;
-       SysScanDesc tgscan;
 
        copyTuple = heap_copytuple(contuple);
        copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
@@ -11884,53 +11887,8 @@ ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
         * Now we need to update the multiple entries in pg_trigger that
         * implement the constraint.
         */
-       ScanKeyInit(&tgkey,
-                   Anum_pg_trigger_tgconstraint,
-                   BTEqualStrategyNumber, F_OIDEQ,
-                   ObjectIdGetDatum(conoid));
-       tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
-                                   NULL, 1, &tgkey);
-       while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
-       {
-           Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple);
-           Form_pg_trigger copy_tg;
-           HeapTuple   tgCopyTuple;
-
-           /*
-            * Remember OIDs of other relation(s) involved in FK constraint.
-            * (Note: it's likely that we could skip forcing a relcache inval
-            * for other rels that don't have a trigger whose properties
-            * change, but let's be conservative.)
-            */
-           if (tgform->tgrelid != RelationGetRelid(rel))
-               *otherrelids = list_append_unique_oid(*otherrelids,
-                                                     tgform->tgrelid);
-
-           /*
-            * Update deferrability of RI_FKey_noaction_del,
-            * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd
-            * triggers, but not others; see createForeignKeyActionTriggers
-            * and CreateFKCheckTrigger.
-            */
-           if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL &&
-               tgform->tgfoid != F_RI_FKEY_NOACTION_UPD &&
-               tgform->tgfoid != F_RI_FKEY_CHECK_INS &&
-               tgform->tgfoid != F_RI_FKEY_CHECK_UPD)
-               continue;
-
-           tgCopyTuple = heap_copytuple(tgtuple);
-           copy_tg = (Form_pg_trigger) GETSTRUCT(tgCopyTuple);
-
-           copy_tg->tgdeferrable = cmdcon->deferrable;
-           copy_tg->tginitdeferred = cmdcon->initdeferred;
-           CatalogTupleUpdate(tgrel, &tgCopyTuple->t_self, tgCopyTuple);
-
-           InvokeObjectPostAlterHook(TriggerRelationId, tgform->oid, 0);
-
-           heap_freetuple(tgCopyTuple);
-       }
-
-       systable_endscan(tgscan);
+       AlterConstrTriggerDeferrability(conoid, tgrel, rel, cmdcon->deferrable,
+                                       cmdcon->initdeferred, otherrelids);
    }
 
    /*
@@ -11943,34 +11901,118 @@ ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
     */
    if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
        get_rel_relkind(refrelid) == RELKIND_PARTITIONED_TABLE)
+       ATExecAlterChildConstr(cmdcon, conrel, tgrel, rel, contuple,
+                              otherrelids, lockmode);
+
+   return changed;
+}
+
+/*
+ * A subroutine of ATExecAlterConstrRecurse that updated constraint trigger's
+ * deferrability.
+ *
+ * The arguments to this function have the same meaning as the arguments to
+ * ATExecAlterConstrRecurse.
+ */
+static void
+AlterConstrTriggerDeferrability(Oid conoid, Relation tgrel, Relation rel,
+                               bool deferrable, bool initdeferred,
+                               List **otherrelids)
+{
+   HeapTuple   tgtuple;
+   ScanKeyData tgkey;
+   SysScanDesc tgscan;
+
+   ScanKeyInit(&tgkey,
+               Anum_pg_trigger_tgconstraint,
+               BTEqualStrategyNumber, F_OIDEQ,
+               ObjectIdGetDatum(conoid));
+   tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
+                               NULL, 1, &tgkey);
+   while (HeapTupleIsValid(tgtuple = systable_getnext(tgscan)))
    {
-       ScanKeyData pkey;
-       SysScanDesc pscan;
-       HeapTuple   childtup;
+       Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple);
+       Form_pg_trigger copy_tg;
+       HeapTuple   tgCopyTuple;
 
-       ScanKeyInit(&pkey,
-                   Anum_pg_constraint_conparentid,
-                   BTEqualStrategyNumber, F_OIDEQ,
-                   ObjectIdGetDatum(conoid));
+       /*
+        * Remember OIDs of other relation(s) involved in FK constraint.
+        * (Note: it's likely that we could skip forcing a relcache inval for
+        * other rels that don't have a trigger whose properties change, but
+        * let's be conservative.)
+        */
+       if (tgform->tgrelid != RelationGetRelid(rel))
+           *otherrelids = list_append_unique_oid(*otherrelids,
+                                                 tgform->tgrelid);
 
-       pscan = systable_beginscan(conrel, ConstraintParentIndexId,
-                                  true, NULL, 1, &pkey);
+       /*
+        * Update enable status and deferrability of RI_FKey_noaction_del,
+        * RI_FKey_noaction_upd, RI_FKey_check_ins and RI_FKey_check_upd
+        * triggers, but not others; see createForeignKeyActionTriggers and
+        * CreateFKCheckTrigger.
+        */
+       if (tgform->tgfoid != F_RI_FKEY_NOACTION_DEL &&
+           tgform->tgfoid != F_RI_FKEY_NOACTION_UPD &&
+           tgform->tgfoid != F_RI_FKEY_CHECK_INS &&
+           tgform->tgfoid != F_RI_FKEY_CHECK_UPD)
+           continue;
 
-       while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
-       {
-           Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
-           Relation    childrel;
+       tgCopyTuple = heap_copytuple(tgtuple);
+       copy_tg = (Form_pg_trigger) GETSTRUCT(tgCopyTuple);
 
-           childrel = table_open(childcon->conrelid, lockmode);
-           ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, childrel, childtup,
-                                    otherrelids, lockmode);
-           table_close(childrel, NoLock);
-       }
+       copy_tg->tgdeferrable = deferrable;
+       copy_tg->tginitdeferred = initdeferred;
+       CatalogTupleUpdate(tgrel, &tgCopyTuple->t_self, tgCopyTuple);
+
+       InvokeObjectPostAlterHook(TriggerRelationId, tgform->oid, 0);
 
-       systable_endscan(pscan);
+       heap_freetuple(tgCopyTuple);
    }
 
-   return changed;
+   systable_endscan(tgscan);
+}
+
+/*
+ * Invokes ATExecAlterConstrRecurse for each constraint that is a child of the
+ * specified constraint.
+ *
+ * The arguments to this function have the same meaning as the arguments to
+ * ATExecAlterConstrRecurse.
+ */
+static void
+ATExecAlterChildConstr(Constraint *cmdcon, Relation conrel, Relation tgrel,
+                      Relation rel, HeapTuple contuple, List **otherrelids,
+                      LOCKMODE lockmode)
+{
+   Form_pg_constraint currcon;
+   Oid         conoid;
+   ScanKeyData pkey;
+   SysScanDesc pscan;
+   HeapTuple   childtup;
+
+   currcon = (Form_pg_constraint) GETSTRUCT(contuple);
+   conoid = currcon->oid;
+
+   ScanKeyInit(&pkey,
+               Anum_pg_constraint_conparentid,
+               BTEqualStrategyNumber, F_OIDEQ,
+               ObjectIdGetDatum(conoid));
+
+   pscan = systable_beginscan(conrel, ConstraintParentIndexId,
+                              true, NULL, 1, &pkey);
+
+   while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
+   {
+       Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
+       Relation    childrel;
+
+       childrel = table_open(childcon->conrelid, lockmode);
+       ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, childrel, childtup,
+                                otherrelids, lockmode);
+       table_close(childrel, NoLock);
+   }
+
+   systable_endscan(pscan);
 }
 
 /*