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

Commit 80d7f99

Browse files
committed
Add ATAlterConstraint struct for ALTER .. CONSTRAINT
Replace the use of Constraint with a new ATAlterConstraint struct, which allows us to pass additional information. No functionality is added by this commit. This is necessary for future work that allows altering constraints in other ways. I (Álvaro) took the liberty of restructuring the code for ALTER CONSTRAINT beyond what Amul did. The original coding before Amul's patch was unnecessarily baroque, and this change makes things simpler by removing one level of subroutine. Also, partly remove the assumption that only partitioned tables are relevant (by passing sensible 'recurse' arguments) and no longer ignore whether ONLY was specified. I say 'partly' because the current coding only walks down via the 'conparentid' relationship, which is only used for partitioned tables; but future patches could handle ONLY or not for other types of constraint changes for legacy inheritance trees too. Author: Amul Sul <sulamul@gmail.com> Author: Álvaro Herrera <alvherre@alvh.no-ip.org> Discussion: https://postgr.es/m/CAAJ_b94bfgPV-8Mw_HwSBeheVwaK9=5s+7+KbBj_NpwXQFgDGg@mail.gmail.com
1 parent e983ee9 commit 80d7f99

File tree

4 files changed

+103
-106
lines changed

4 files changed

+103
-106
lines changed

src/backend/commands/tablecmds.c

+82-97
Original file line numberDiff line numberDiff line change
@@ -389,17 +389,14 @@ static void AlterIndexNamespaces(Relation classRel, Relation rel,
389389
static void AlterSeqNamespaces(Relation classRel, Relation rel,
390390
Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
391391
LOCKMODE lockmode);
392-
static ObjectAddress ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd,
393-
bool recurse, bool recursing, LOCKMODE lockmode);
394-
static bool ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
395-
Relation rel, HeapTuple contuple, List **otherrelids,
396-
LOCKMODE lockmode);
392+
static ObjectAddress ATExecAlterConstraint(Relation rel, ATAlterConstraint *cmdcon,
393+
bool recurse, LOCKMODE lockmode);
394+
static bool ATExecAlterConstraintInternal(ATAlterConstraint *cmdcon, Relation conrel,
395+
Relation tgrel, Relation rel, HeapTuple contuple,
396+
bool recurse, List **otherrelids, LOCKMODE lockmode);
397397
static void AlterConstrTriggerDeferrability(Oid conoid, Relation tgrel, Relation rel,
398398
bool deferrable, bool initdeferred,
399399
List **otherrelids);
400-
static void ATExecAlterChildConstr(Constraint *cmdcon, Relation conrel, Relation tgrel,
401-
Relation rel, HeapTuple contuple, List **otherrelids,
402-
LOCKMODE lockmode);
403400
static ObjectAddress ATExecValidateConstraint(List **wqueue,
404401
Relation rel, char *constrName,
405402
bool recurse, bool recursing, LOCKMODE lockmode);
@@ -5170,6 +5167,8 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
51705167
ATSimplePermissions(cmd->subtype, rel,
51715168
ATT_TABLE | ATT_PARTITIONED_TABLE);
51725169
/* Recursion occurs during execution phase */
5170+
if (recurse)
5171+
cmd->recurse = true;
51735172
pass = AT_PASS_MISC;
51745173
break;
51755174
case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
@@ -5450,7 +5449,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab,
54505449
lockmode);
54515450
break;
54525451
case AT_AlterConstraint: /* ALTER CONSTRAINT */
5453-
address = ATExecAlterConstraint(rel, cmd, false, false, lockmode);
5452+
address = ATExecAlterConstraint(rel, castNode(ATAlterConstraint,
5453+
cmd->def),
5454+
cmd->recurse, lockmode);
54545455
break;
54555456
case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
54565457
address = ATExecValidateConstraint(wqueue, rel, cmd->name, cmd->recurse,
@@ -11801,10 +11802,9 @@ GetForeignKeyCheckTriggers(Relation trigrel,
1180111802
* InvalidObjectAddress.
1180211803
*/
1180311804
static ObjectAddress
11804-
ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse,
11805-
bool recursing, LOCKMODE lockmode)
11805+
ATExecAlterConstraint(Relation rel, ATAlterConstraint *cmdcon, bool recurse,
11806+
LOCKMODE lockmode)
1180611807
{
11807-
Constraint *cmdcon;
1180811808
Relation conrel;
1180911809
Relation tgrel;
1181011810
SysScanDesc scan;
@@ -11813,9 +11813,17 @@ ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse,
1181311813
Form_pg_constraint currcon;
1181411814
ObjectAddress address;
1181511815
List *otherrelids = NIL;
11816-
ListCell *lc;
1181711816

11818-
cmdcon = castNode(Constraint, cmd->def);
11817+
/*
11818+
* Disallow altering ONLY a partitioned table, as it would make no sense.
11819+
* This is okay for legacy inheritance.
11820+
*/
11821+
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
11822+
ereport(ERROR,
11823+
errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11824+
errmsg("constraint must be altered in child tables too"),
11825+
errhint("Do not specify the ONLY keyword."));
11826+
1181911827

1182011828
conrel = table_open(ConstraintRelationId, RowExclusiveLock);
1182111829
tgrel = table_open(TriggerRelationId, RowExclusiveLock);
@@ -11896,28 +11904,22 @@ ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse,
1189611904
errhint("You may alter the constraint it derives from instead.")));
1189711905
}
1189811906

11907+
address = InvalidObjectAddress;
11908+
1189911909
/*
11900-
* Do the actual catalog work. We can skip changing if already in the
11901-
* desired state, but not if a partitioned table: partitions need to be
11902-
* processed regardless, in case they had the constraint locally changed.
11910+
* Do the actual catalog work, and recurse if necessary.
1190311911
*/
11904-
address = InvalidObjectAddress;
11905-
if (currcon->condeferrable != cmdcon->deferrable ||
11906-
currcon->condeferred != cmdcon->initdeferred ||
11907-
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11908-
{
11909-
if (ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, rel, contuple,
11910-
&otherrelids, lockmode))
11911-
ObjectAddressSet(address, ConstraintRelationId, currcon->oid);
11912-
}
11912+
if (ATExecAlterConstraintInternal(cmdcon, conrel, tgrel, rel, contuple,
11913+
recurse, &otherrelids, lockmode))
11914+
ObjectAddressSet(address, ConstraintRelationId, currcon->oid);
1191311915

1191411916
/*
11915-
* ATExecAlterConstrRecurse already invalidated relcache for the relations
11916-
* having the constraint itself; here we also invalidate for relations
11917-
* that have any triggers that are part of the constraint.
11917+
* ATExecAlterConstraintInternal already invalidated relcache for the
11918+
* relations having the constraint itself; here we also invalidate for
11919+
* relations that have any triggers that are part of the constraint.
1191811920
*/
11919-
foreach(lc, otherrelids)
11920-
CacheInvalidateRelcacheByRelid(lfirst_oid(lc));
11921+
foreach_oid(relid, otherrelids)
11922+
CacheInvalidateRelcacheByRelid(relid);
1192111923

1192211924
systable_endscan(scan);
1192311925

@@ -11939,30 +11941,30 @@ ATExecAlterConstraint(Relation rel, AlterTableCmd *cmd, bool recurse,
1193911941
* but existing releases don't do that.)
1194011942
*/
1194111943
static bool
11942-
ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
11943-
Relation rel, HeapTuple contuple, List **otherrelids,
11944-
LOCKMODE lockmode)
11944+
ATExecAlterConstraintInternal(ATAlterConstraint *cmdcon, Relation conrel,
11945+
Relation tgrel, Relation rel, HeapTuple contuple,
11946+
bool recurse, List **otherrelids, LOCKMODE lockmode)
1194511947
{
1194611948
Form_pg_constraint currcon;
11947-
Oid conoid;
11948-
Oid refrelid;
11949+
Oid refrelid = InvalidOid;
1194911950
bool changed = false;
1195011951

1195111952
/* since this function recurses, it could be driven to stack overflow */
1195211953
check_stack_depth();
1195311954

1195411955
currcon = (Form_pg_constraint) GETSTRUCT(contuple);
11955-
conoid = currcon->oid;
11956-
refrelid = currcon->confrelid;
11956+
if (currcon->contype == CONSTRAINT_FOREIGN)
11957+
refrelid = currcon->confrelid;
1195711958

1195811959
/*
1195911960
* Update pg_constraint with the flags from cmdcon.
1196011961
*
1196111962
* If called to modify a constraint that's already in the desired state,
1196211963
* silently do nothing.
1196311964
*/
11964-
if (currcon->condeferrable != cmdcon->deferrable ||
11965-
currcon->condeferred != cmdcon->initdeferred)
11965+
if (cmdcon->alterDeferrability &&
11966+
(currcon->condeferrable != cmdcon->deferrable ||
11967+
currcon->condeferred != cmdcon->initdeferred))
1196611968
{
1196711969
HeapTuple copyTuple;
1196811970
Form_pg_constraint copy_con;
@@ -11973,8 +11975,7 @@ ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
1197311975
copy_con->condeferred = cmdcon->initdeferred;
1197411976
CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
1197511977

11976-
InvokeObjectPostAlterHook(ConstraintRelationId,
11977-
conoid, 0);
11978+
InvokeObjectPostAlterHook(ConstraintRelationId, currcon->oid, 0);
1197811979

1197911980
heap_freetuple(copyTuple);
1198011981
changed = true;
@@ -11986,32 +11987,59 @@ ATExecAlterConstrRecurse(Constraint *cmdcon, Relation conrel, Relation tgrel,
1198611987
* Now we need to update the multiple entries in pg_trigger that
1198711988
* implement the constraint.
1198811989
*/
11989-
AlterConstrTriggerDeferrability(conoid, tgrel, rel, cmdcon->deferrable,
11990+
AlterConstrTriggerDeferrability(currcon->oid, tgrel, rel,
11991+
cmdcon->deferrable,
1199011992
cmdcon->initdeferred, otherrelids);
1199111993
}
1199211994

1199311995
/*
1199411996
* If the table at either end of the constraint is partitioned, we need to
11995-
* recurse and handle every constraint that is a child of this one.
11997+
* handle every constraint that is a child of this one.
1199611998
*
11997-
* (This assumes that the recurse flag is forcibly set for partitioned
11998-
* tables, and not set for legacy inheritance, though we don't check for
11999-
* that here.)
11999+
* Note that this doesn't handle recursion the normal way, viz. by
12000+
* scanning the list of child relations and recursing; instead it uses the
12001+
* conparentid relationships. This may need to be reconsidered.
1200012002
*/
12001-
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
12002-
get_rel_relkind(refrelid) == RELKIND_PARTITIONED_TABLE)
12003-
ATExecAlterChildConstr(cmdcon, conrel, tgrel, rel, contuple,
12004-
otherrelids, lockmode);
12003+
if (recurse && changed &&
12004+
(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
12005+
(OidIsValid(refrelid) &&
12006+
get_rel_relkind(refrelid) == RELKIND_PARTITIONED_TABLE)))
12007+
{
12008+
ScanKeyData pkey;
12009+
SysScanDesc pscan;
12010+
HeapTuple childtup;
12011+
12012+
ScanKeyInit(&pkey,
12013+
Anum_pg_constraint_conparentid,
12014+
BTEqualStrategyNumber, F_OIDEQ,
12015+
ObjectIdGetDatum(currcon->oid));
12016+
12017+
pscan = systable_beginscan(conrel, ConstraintParentIndexId,
12018+
true, NULL, 1, &pkey);
12019+
12020+
while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
12021+
{
12022+
Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
12023+
Relation childrel;
12024+
12025+
childrel = table_open(childcon->conrelid, lockmode);
12026+
ATExecAlterConstraintInternal(cmdcon, conrel, tgrel, childrel, childtup,
12027+
recurse, otherrelids, lockmode);
12028+
table_close(childrel, NoLock);
12029+
}
12030+
12031+
systable_endscan(pscan);
12032+
}
1200512033

1200612034
return changed;
1200712035
}
1200812036

1200912037
/*
12010-
* A subroutine of ATExecAlterConstrRecurse that updated constraint trigger's
12011-
* deferrability.
12038+
* A subroutine of ATExecAlterConstrDeferrability that updated constraint
12039+
* trigger's deferrability.
1201212040
*
1201312041
* The arguments to this function have the same meaning as the arguments to
12014-
* ATExecAlterConstrRecurse.
12042+
* ATExecAlterConstrDeferrability.
1201512043
*/
1201612044
static void
1201712045
AlterConstrTriggerDeferrability(Oid conoid, Relation tgrel, Relation rel,
@@ -12071,49 +12099,6 @@ AlterConstrTriggerDeferrability(Oid conoid, Relation tgrel, Relation rel,
1207112099
systable_endscan(tgscan);
1207212100
}
1207312101

12074-
/*
12075-
* Invokes ATExecAlterConstrRecurse for each constraint that is a child of the
12076-
* specified constraint.
12077-
*
12078-
* The arguments to this function have the same meaning as the arguments to
12079-
* ATExecAlterConstrRecurse.
12080-
*/
12081-
static void
12082-
ATExecAlterChildConstr(Constraint *cmdcon, Relation conrel, Relation tgrel,
12083-
Relation rel, HeapTuple contuple, List **otherrelids,
12084-
LOCKMODE lockmode)
12085-
{
12086-
Form_pg_constraint currcon;
12087-
Oid conoid;
12088-
ScanKeyData pkey;
12089-
SysScanDesc pscan;
12090-
HeapTuple childtup;
12091-
12092-
currcon = (Form_pg_constraint) GETSTRUCT(contuple);
12093-
conoid = currcon->oid;
12094-
12095-
ScanKeyInit(&pkey,
12096-
Anum_pg_constraint_conparentid,
12097-
BTEqualStrategyNumber, F_OIDEQ,
12098-
ObjectIdGetDatum(conoid));
12099-
12100-
pscan = systable_beginscan(conrel, ConstraintParentIndexId,
12101-
true, NULL, 1, &pkey);
12102-
12103-
while (HeapTupleIsValid(childtup = systable_getnext(pscan)))
12104-
{
12105-
Form_pg_constraint childcon = (Form_pg_constraint) GETSTRUCT(childtup);
12106-
Relation childrel;
12107-
12108-
childrel = table_open(childcon->conrelid, lockmode);
12109-
ATExecAlterConstrRecurse(cmdcon, conrel, tgrel, childrel, childtup,
12110-
otherrelids, lockmode);
12111-
table_close(childrel, NoLock);
12112-
}
12113-
12114-
systable_endscan(pscan);
12115-
}
12116-
1211712102
/*
1211812103
* ALTER TABLE VALIDATE CONSTRAINT
1211912104
*

src/backend/parser/gram.y

+2-2
Original file line numberDiff line numberDiff line change
@@ -2657,12 +2657,12 @@ alter_table_cmd:
26572657
| ALTER CONSTRAINT name ConstraintAttributeSpec
26582658
{
26592659
AlterTableCmd *n = makeNode(AlterTableCmd);
2660-
Constraint *c = makeNode(Constraint);
2660+
ATAlterConstraint *c = makeNode(ATAlterConstraint);
26612661

26622662
n->subtype = AT_AlterConstraint;
26632663
n->def = (Node *) c;
2664-
c->contype = CONSTR_FOREIGN; /* others not supported, yet */
26652664
c->conname = $3;
2665+
c->alterDeferrability = true;
26662666
processCASbits($4, @4, "ALTER CONSTRAINT statement",
26672667
&c->deferrable,
26682668
&c->initdeferred,

src/include/nodes/parsenodes.h

+18-7
Original file line numberDiff line numberDiff line change
@@ -2469,13 +2469,6 @@ typedef enum AlterTableType
24692469
AT_ReAddStatistics, /* internal to commands/tablecmds.c */
24702470
} AlterTableType;
24712471

2472-
typedef struct ReplicaIdentityStmt
2473-
{
2474-
NodeTag type;
2475-
char identity_type;
2476-
char *name;
2477-
} ReplicaIdentityStmt;
2478-
24792472
typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
24802473
{
24812474
NodeTag type;
@@ -2492,6 +2485,24 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
24922485
bool recurse; /* exec-time recursion */
24932486
} AlterTableCmd;
24942487

2488+
/* Ad-hoc node for AT_AlterConstraint */
2489+
typedef struct ATAlterConstraint
2490+
{
2491+
NodeTag type;
2492+
char *conname; /* Constraint name */
2493+
bool alterDeferrability; /* changing deferrability properties? */
2494+
bool deferrable; /* DEFERRABLE? */
2495+
bool initdeferred; /* INITIALLY DEFERRED? */
2496+
} ATAlterConstraint;
2497+
2498+
/* Ad-hoc node for AT_ReplicaIdentity */
2499+
typedef struct ReplicaIdentityStmt
2500+
{
2501+
NodeTag type;
2502+
char identity_type;
2503+
char *name;
2504+
} ReplicaIdentityStmt;
2505+
24952506

24962507
/* ----------------------
24972508
* Alter Collation

src/tools/pgindent/typedefs.list

+1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ ArrayType
157157
AsyncQueueControl
158158
AsyncQueueEntry
159159
AsyncRequest
160+
ATAlterConstraint
160161
AttInMetadata
161162
AttStatsSlot
162163
AttoptCacheEntry

0 commit comments

Comments
 (0)