]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix trigger drop procedure
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Sun, 10 Feb 2019 13:00:11 +0000 (10:00 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Sun, 10 Feb 2019 13:00:11 +0000 (10:00 -0300)
After commit 123cc697a8eb, we remove redundant FK action triggers during
partition ATTACH by merely deleting the catalog tuple, but that's wrong:
it should use performDeletion() instead.  Repair, and make the comments
more explicit.

Per code review from Tom Lane.

Discussion: https://postgr.es/m/18885.1549642539@sss.pgh.pa.us

src/backend/commands/tablecmds.c

index 910e5deaa3f9eee5dadbec7319d8b2edb14611b0..0f72f51d372190e015f1e4885cf3b1c03917bdb1 100644 (file)
@@ -8008,10 +8008,12 @@ CloneFkReferencing(Relation pg_constraint, Relation parentRel,
                        ReleaseSysCache(partcontup);
 
                        /*
-                        * Looks good!  Attach this constraint.  Note that the action
-                        * triggers are no longer needed, so remove them.  We identify
-                        * them because they have our constraint OID, as well as being
-                        * on the referenced rel.
+                        * Looks good!  Attach this constraint.  The action triggers in
+                        * the new partition become redundant -- the parent table already
+                        * has equivalent ones, and those will be able to reach the
+                        * partition.  Remove the ones in the partition.  We identify them
+                        * because they have our constraint OID, as well as being on the
+                        * referenced rel.
                         */
                        trigrel = heap_open(TriggerRelationId, RowExclusiveLock);
                        ScanKeyInit(&key,
@@ -8024,17 +8026,30 @@ CloneFkReferencing(Relation pg_constraint, Relation parentRel,
                        while ((trigtup = systable_getnext(scan)) != NULL)
                        {
                                Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
+                               ObjectAddress   trigger;
 
                                if (trgform->tgconstrrelid != fk->conrelid)
                                        continue;
                                if (trgform->tgrelid != fk->confrelid)
                                        continue;
 
-                               deleteDependencyRecordsForClass(TriggerRelationId,
-                                                                                               HeapTupleGetOid(trigtup),
-                                                                                               ConstraintRelationId,
-                                                                                               DEPENDENCY_INTERNAL);
-                               CatalogTupleDelete(trigrel, &trigtup->t_self);
+                               /*
+                                * The constraint is originally set up to contain this trigger
+                                * as an implementation object, so there's a dependency record
+                                * that links the two; however, since the trigger is no longer
+                                * needed, we remove the dependency link in order to be able
+                                * to drop the trigger while keeping the constraint intact.
+                                */
+                               deleteDependencyRecordsFor(TriggerRelationId,
+                                                                                  HeapTupleGetOid(trigtup),
+                                                                                  false);
+                               /* make dependency deletion visible to performDeletion */
+                               CommandCounterIncrement();
+                               ObjectAddressSet(trigger, TriggerRelationId,
+                                                                HeapTupleGetOid(trigtup));
+                               performDeletion(&trigger, DROP_RESTRICT, 0);
+                               /* make trigger drop visible, in case the loop iterates */
+                               CommandCounterIncrement();
                        }
 
                        systable_endscan(scan);