Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1d26c2d

Browse files
committed
refactor: Split tryAttachPartitionForeignKey()
Split tryAttachPartitionForeignKey() into three functions: AttachPartitionForeignKey(), RemoveInheritedConstraint(), and DropForeignKeyConstraintTriggers(), so they can be reused in some subsequent patches for the NOT ENFORCED feature. Author: Amul Sul <amul.sul@enterprisedb.com> Reviewed-by: Alexandra Wang <alexandra.wang.oss@gmail.com> Discussion: https://www.postgresql.org/message-id/flat/CAAJ_b962c5AcYW9KUt_R_ER5qs3fUGbe4az-SP-vuwPS-w-AGA%40mail.gmail.com
1 parent 64224a8 commit 1d26c2d

File tree

1 file changed

+204
-115
lines changed

1 file changed

+204
-115
lines changed

src/backend/commands/tablecmds.c

Lines changed: 204 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,14 @@ static bool tryAttachPartitionForeignKey(List **wqueue,
585585
Oid parentInsTrigger,
586586
Oid parentUpdTrigger,
587587
Relation trigrel);
588+
static void AttachPartitionForeignKey(List **wqueue, Relation partition,
589+
Oid partConstrOid, Oid parentConstrOid,
590+
Oid parentInsTrigger, Oid parentUpdTrigger,
591+
Relation trigrel);
592+
static void RemoveInheritedConstraint(Relation conrel, Relation trigrel,
593+
Oid conoid, Oid conrelid);
594+
static void DropForeignKeyConstraintTriggers(Relation trigrel, Oid conoid,
595+
Oid confrelid, Oid conrelid);
588596
static void GetForeignKeyActionTriggers(Relation trigrel,
589597
Oid conoid, Oid confrelid, Oid conrelid,
590598
Oid *deleteTriggerOid,
@@ -11467,12 +11475,6 @@ tryAttachPartitionForeignKey(List **wqueue,
1146711475
Form_pg_constraint parentConstr;
1146811476
HeapTuple partcontup;
1146911477
Form_pg_constraint partConstr;
11470-
bool queueValidation;
11471-
ScanKeyData key;
11472-
SysScanDesc scan;
11473-
HeapTuple trigtup;
11474-
Oid insertTriggerOid,
11475-
updateTriggerOid;
1147611478

1147711479
parentConstrTup = SearchSysCache1(CONSTROID,
1147811480
ObjectIdGetDatum(parentConstrOid));
@@ -11517,6 +11519,59 @@ tryAttachPartitionForeignKey(List **wqueue,
1151711519
return false;
1151811520
}
1151911521

11522+
ReleaseSysCache(parentConstrTup);
11523+
ReleaseSysCache(partcontup);
11524+
11525+
/* Looks good! Attach this constraint. */
11526+
AttachPartitionForeignKey(wqueue, partition, fk->conoid,
11527+
parentConstrOid, parentInsTrigger,
11528+
parentUpdTrigger, trigrel);
11529+
11530+
return true;
11531+
}
11532+
11533+
/*
11534+
* AttachPartitionForeignKey
11535+
*
11536+
* The subroutine for tryAttachPartitionForeignKey performs the final tasks of
11537+
* attaching the constraint, removing redundant triggers and entries from
11538+
* pg_constraint, and setting the constraint's parent.
11539+
*/
11540+
static void
11541+
AttachPartitionForeignKey(List **wqueue,
11542+
Relation partition,
11543+
Oid partConstrOid,
11544+
Oid parentConstrOid,
11545+
Oid parentInsTrigger,
11546+
Oid parentUpdTrigger,
11547+
Relation trigrel)
11548+
{
11549+
HeapTuple parentConstrTup;
11550+
Form_pg_constraint parentConstr;
11551+
HeapTuple partcontup;
11552+
Form_pg_constraint partConstr;
11553+
bool queueValidation;
11554+
Oid partConstrFrelid;
11555+
Oid partConstrRelid;
11556+
Oid insertTriggerOid,
11557+
updateTriggerOid;
11558+
11559+
/* Fetch the parent constraint tuple */
11560+
parentConstrTup = SearchSysCache1(CONSTROID,
11561+
ObjectIdGetDatum(parentConstrOid));
11562+
if (!HeapTupleIsValid(parentConstrTup))
11563+
elog(ERROR, "cache lookup failed for constraint %u", parentConstrOid);
11564+
parentConstr = (Form_pg_constraint) GETSTRUCT(parentConstrTup);
11565+
11566+
/* Fetch the child constraint tuple */
11567+
partcontup = SearchSysCache1(CONSTROID,
11568+
ObjectIdGetDatum(partConstrOid));
11569+
if (!HeapTupleIsValid(partcontup))
11570+
elog(ERROR, "cache lookup failed for constraint %u", partConstrOid);
11571+
partConstr = (Form_pg_constraint) GETSTRUCT(partcontup);
11572+
partConstrFrelid = partConstr->confrelid;
11573+
partConstrRelid = partConstr->conrelid;
11574+
1152011575
/*
1152111576
* Will we need to validate this constraint? A valid parent constraint
1152211577
* implies that all child constraints have been validated, so if this one
@@ -11528,58 +11583,23 @@ tryAttachPartitionForeignKey(List **wqueue,
1152811583
ReleaseSysCache(parentConstrTup);
1152911584

1153011585
/*
11531-
* Looks good! Attach this constraint. The action triggers in the new
11532-
* partition become redundant -- the parent table already has equivalent
11533-
* ones, and those will be able to reach the partition. Remove the ones
11534-
* in the partition. We identify them because they have our constraint
11535-
* OID, as well as being on the referenced rel.
11586+
* The action triggers in the new partition become redundant -- the parent
11587+
* table already has equivalent ones, and those will be able to reach the
11588+
* partition. Remove the ones in the partition. We identify them because
11589+
* they have our constraint OID, as well as being on the referenced rel.
1153611590
*/
11537-
ScanKeyInit(&key,
11538-
Anum_pg_trigger_tgconstraint,
11539-
BTEqualStrategyNumber, F_OIDEQ,
11540-
ObjectIdGetDatum(fk->conoid));
11541-
scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11542-
NULL, 1, &key);
11543-
while ((trigtup = systable_getnext(scan)) != NULL)
11544-
{
11545-
Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11546-
ObjectAddress trigger;
11591+
DropForeignKeyConstraintTriggers(trigrel, partConstrOid, partConstrFrelid,
11592+
partConstrRelid);
1154711593

11548-
if (trgform->tgconstrrelid != fk->conrelid)
11549-
continue;
11550-
if (trgform->tgrelid != fk->confrelid)
11551-
continue;
11552-
11553-
/*
11554-
* The constraint is originally set up to contain this trigger as an
11555-
* implementation object, so there's a dependency record that links
11556-
* the two; however, since the trigger is no longer needed, we remove
11557-
* the dependency link in order to be able to drop the trigger while
11558-
* keeping the constraint intact.
11559-
*/
11560-
deleteDependencyRecordsFor(TriggerRelationId,
11561-
trgform->oid,
11562-
false);
11563-
/* make dependency deletion visible to performDeletion */
11564-
CommandCounterIncrement();
11565-
ObjectAddressSet(trigger, TriggerRelationId,
11566-
trgform->oid);
11567-
performDeletion(&trigger, DROP_RESTRICT, 0);
11568-
/* make trigger drop visible, in case the loop iterates */
11569-
CommandCounterIncrement();
11570-
}
11571-
11572-
systable_endscan(scan);
11573-
11574-
ConstraintSetParentConstraint(fk->conoid, parentConstrOid,
11594+
ConstraintSetParentConstraint(partConstrOid, parentConstrOid,
1157511595
RelationGetRelid(partition));
1157611596

1157711597
/*
1157811598
* Like the constraint, attach partition's "check" triggers to the
1157911599
* corresponding parent triggers.
1158011600
*/
1158111601
GetForeignKeyCheckTriggers(trigrel,
11582-
fk->conoid, fk->confrelid, fk->conrelid,
11602+
partConstrOid, partConstrFrelid, partConstrRelid,
1158311603
&insertTriggerOid, &updateTriggerOid);
1158411604
Assert(OidIsValid(insertTriggerOid) && OidIsValid(parentInsTrigger));
1158511605
TriggerSetParentTrigger(trigrel, insertTriggerOid, parentInsTrigger,
@@ -11593,72 +11613,12 @@ tryAttachPartitionForeignKey(List **wqueue,
1159311613
* attaching now has extra pg_constraint rows and action triggers that are
1159411614
* no longer needed. Remove those.
1159511615
*/
11596-
if (get_rel_relkind(fk->confrelid) == RELKIND_PARTITIONED_TABLE)
11616+
if (get_rel_relkind(partConstrFrelid) == RELKIND_PARTITIONED_TABLE)
1159711617
{
1159811618
Relation pg_constraint = table_open(ConstraintRelationId, RowShareLock);
11599-
ObjectAddresses *objs;
11600-
HeapTuple consttup;
11601-
11602-
ScanKeyInit(&key,
11603-
Anum_pg_constraint_conrelid,
11604-
BTEqualStrategyNumber, F_OIDEQ,
11605-
ObjectIdGetDatum(fk->conrelid));
11606-
11607-
scan = systable_beginscan(pg_constraint,
11608-
ConstraintRelidTypidNameIndexId,
11609-
true, NULL, 1, &key);
11610-
objs = new_object_addresses();
11611-
while ((consttup = systable_getnext(scan)) != NULL)
11612-
{
11613-
Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(consttup);
11614-
11615-
if (conform->conparentid != fk->conoid)
11616-
continue;
11617-
else
11618-
{
11619-
ObjectAddress addr;
11620-
SysScanDesc scan2;
11621-
ScanKeyData key2;
11622-
int n PG_USED_FOR_ASSERTS_ONLY;
1162311619

11624-
ObjectAddressSet(addr, ConstraintRelationId, conform->oid);
11625-
add_exact_object_address(&addr, objs);
11626-
11627-
/*
11628-
* First we must delete the dependency record that binds the
11629-
* constraint records together.
11630-
*/
11631-
n = deleteDependencyRecordsForSpecific(ConstraintRelationId,
11632-
conform->oid,
11633-
DEPENDENCY_INTERNAL,
11634-
ConstraintRelationId,
11635-
fk->conoid);
11636-
Assert(n == 1); /* actually only one is expected */
11637-
11638-
/*
11639-
* Now search for the triggers for this constraint and set
11640-
* them up for deletion too
11641-
*/
11642-
ScanKeyInit(&key2,
11643-
Anum_pg_trigger_tgconstraint,
11644-
BTEqualStrategyNumber, F_OIDEQ,
11645-
ObjectIdGetDatum(conform->oid));
11646-
scan2 = systable_beginscan(trigrel, TriggerConstraintIndexId,
11647-
true, NULL, 1, &key2);
11648-
while ((trigtup = systable_getnext(scan2)) != NULL)
11649-
{
11650-
ObjectAddressSet(addr, TriggerRelationId,
11651-
((Form_pg_trigger) GETSTRUCT(trigtup))->oid);
11652-
add_exact_object_address(&addr, objs);
11653-
}
11654-
systable_endscan(scan2);
11655-
}
11656-
}
11657-
/* make the dependency deletions visible */
11658-
CommandCounterIncrement();
11659-
performMultipleDeletions(objs, DROP_RESTRICT,
11660-
PERFORM_DELETION_INTERNAL);
11661-
systable_endscan(scan);
11620+
RemoveInheritedConstraint(pg_constraint, trigrel, partConstrOid,
11621+
partConstrRelid);
1166211622

1166311623
table_close(pg_constraint, RowShareLock);
1166411624
}
@@ -11679,18 +11639,147 @@ tryAttachPartitionForeignKey(List **wqueue,
1167911639
Relation conrel;
1168011640

1168111641
conrel = table_open(ConstraintRelationId, RowExclusiveLock);
11682-
partcontup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fk->conoid));
11642+
11643+
partcontup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(partConstrOid));
1168311644
if (!HeapTupleIsValid(partcontup))
11684-
elog(ERROR, "cache lookup failed for constraint %u", fk->conoid);
11645+
elog(ERROR, "cache lookup failed for constraint %u", partConstrOid);
1168511646

1168611647
/* Use the same lock as for AT_ValidateConstraint */
1168711648
QueueFKConstraintValidation(wqueue, conrel, partition, partcontup,
1168811649
ShareUpdateExclusiveLock);
1168911650
ReleaseSysCache(partcontup);
1169011651
table_close(conrel, RowExclusiveLock);
1169111652
}
11653+
}
1169211654

11693-
return true;
11655+
/*
11656+
* RemoveInheritedConstraint
11657+
*
11658+
* Removes the constraint and its associated trigger from the specified
11659+
* relation, which inherited the given constraint.
11660+
*/
11661+
static void
11662+
RemoveInheritedConstraint(Relation conrel, Relation trigrel, Oid conoid,
11663+
Oid conrelid)
11664+
{
11665+
ObjectAddresses *objs;
11666+
HeapTuple consttup;
11667+
ScanKeyData key;
11668+
SysScanDesc scan;
11669+
HeapTuple trigtup;
11670+
11671+
ScanKeyInit(&key,
11672+
Anum_pg_constraint_conrelid,
11673+
BTEqualStrategyNumber, F_OIDEQ,
11674+
ObjectIdGetDatum(conrelid));
11675+
11676+
scan = systable_beginscan(conrel,
11677+
ConstraintRelidTypidNameIndexId,
11678+
true, NULL, 1, &key);
11679+
objs = new_object_addresses();
11680+
while ((consttup = systable_getnext(scan)) != NULL)
11681+
{
11682+
Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(consttup);
11683+
11684+
if (conform->conparentid != conoid)
11685+
continue;
11686+
else
11687+
{
11688+
ObjectAddress addr;
11689+
SysScanDesc scan2;
11690+
ScanKeyData key2;
11691+
int n PG_USED_FOR_ASSERTS_ONLY;
11692+
11693+
ObjectAddressSet(addr, ConstraintRelationId, conform->oid);
11694+
add_exact_object_address(&addr, objs);
11695+
11696+
/*
11697+
* First we must delete the dependency record that binds the
11698+
* constraint records together.
11699+
*/
11700+
n = deleteDependencyRecordsForSpecific(ConstraintRelationId,
11701+
conform->oid,
11702+
DEPENDENCY_INTERNAL,
11703+
ConstraintRelationId,
11704+
conoid);
11705+
Assert(n == 1); /* actually only one is expected */
11706+
11707+
/*
11708+
* Now search for the triggers for this constraint and set them up
11709+
* for deletion too
11710+
*/
11711+
ScanKeyInit(&key2,
11712+
Anum_pg_trigger_tgconstraint,
11713+
BTEqualStrategyNumber, F_OIDEQ,
11714+
ObjectIdGetDatum(conform->oid));
11715+
scan2 = systable_beginscan(trigrel, TriggerConstraintIndexId,
11716+
true, NULL, 1, &key2);
11717+
while ((trigtup = systable_getnext(scan2)) != NULL)
11718+
{
11719+
ObjectAddressSet(addr, TriggerRelationId,
11720+
((Form_pg_trigger) GETSTRUCT(trigtup))->oid);
11721+
add_exact_object_address(&addr, objs);
11722+
}
11723+
systable_endscan(scan2);
11724+
}
11725+
}
11726+
/* make the dependency deletions visible */
11727+
CommandCounterIncrement();
11728+
performMultipleDeletions(objs, DROP_RESTRICT,
11729+
PERFORM_DELETION_INTERNAL);
11730+
systable_endscan(scan);
11731+
}
11732+
11733+
/*
11734+
* DropForeignKeyConstraintTriggers
11735+
*
11736+
* The subroutine for tryAttachPartitionForeignKey handles the deletion of
11737+
* action triggers for the foreign key constraint.
11738+
*/
11739+
static void
11740+
DropForeignKeyConstraintTriggers(Relation trigrel, Oid conoid, Oid confrelid,
11741+
Oid conrelid)
11742+
{
11743+
ScanKeyData key;
11744+
SysScanDesc scan;
11745+
HeapTuple trigtup;
11746+
11747+
ScanKeyInit(&key,
11748+
Anum_pg_trigger_tgconstraint,
11749+
BTEqualStrategyNumber, F_OIDEQ,
11750+
ObjectIdGetDatum(conoid));
11751+
scan = systable_beginscan(trigrel, TriggerConstraintIndexId, true,
11752+
NULL, 1, &key);
11753+
while ((trigtup = systable_getnext(scan)) != NULL)
11754+
{
11755+
Form_pg_trigger trgform = (Form_pg_trigger) GETSTRUCT(trigtup);
11756+
ObjectAddress trigger;
11757+
11758+
if (trgform->tgconstrrelid != conrelid)
11759+
continue;
11760+
if (trgform->tgrelid != confrelid)
11761+
continue;
11762+
11763+
/*
11764+
* The constraint is originally set up to contain this trigger as an
11765+
* implementation object, so there's a dependency record that links
11766+
* the two; however, since the trigger is no longer needed, we remove
11767+
* the dependency link in order to be able to drop the trigger while
11768+
* keeping the constraint intact.
11769+
*/
11770+
deleteDependencyRecordsFor(TriggerRelationId,
11771+
trgform->oid,
11772+
false);
11773+
/* make dependency deletion visible to performDeletion */
11774+
CommandCounterIncrement();
11775+
ObjectAddressSet(trigger, TriggerRelationId,
11776+
trgform->oid);
11777+
performDeletion(&trigger, DROP_RESTRICT, 0);
11778+
/* make trigger drop visible, in case the loop iterates */
11779+
CommandCounterIncrement();
11780+
}
11781+
11782+
systable_endscan(scan);
1169411783
}
1169511784

1169611785
/*

0 commit comments

Comments
 (0)