@@ -389,9 +389,10 @@ static void AlterIndexNamespaces(Relation classRel, Relation rel,
389389static void AlterSeqNamespaces(Relation classRel, Relation rel,
390390 Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
391391 LOCKMODE lockmode);
392- static ObjectAddress ATExecAlterConstraint(Relation rel, ATAlterConstraint *cmdcon,
392+ static ObjectAddress ATExecAlterConstraint(List **wqueue, Relation rel,
393+ ATAlterConstraint *cmdcon,
393394 bool recurse, LOCKMODE lockmode);
394- static bool ATExecAlterConstraintInternal(ATAlterConstraint *cmdcon, Relation conrel,
395+ static bool ATExecAlterConstraintInternal(List **wqueue, ATAlterConstraint *cmdcon, Relation conrel,
395396 Relation tgrel, Relation rel, HeapTuple contuple,
396397 bool recurse, List **otherrelids, LOCKMODE lockmode);
397398static void AlterConstrTriggerDeferrability(Oid conoid, Relation tgrel, Relation rel,
@@ -5437,8 +5438,8 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab,
54375438 lockmode);
54385439 break;
54395440 case AT_AlterConstraint: /* ALTER CONSTRAINT */
5440- address = ATExecAlterConstraint(rel, castNode(ATAlterConstraint ,
5441- cmd->def),
5441+ address = ATExecAlterConstraint(wqueue, rel ,
5442+ castNode(ATAlterConstraint, cmd->def),
54425443 cmd->recurse, lockmode);
54435444 break;
54445445 case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
@@ -11813,14 +11814,14 @@ GetForeignKeyCheckTriggers(Relation trigrel,
1181311814 *
1181411815 * Update the attributes of a constraint.
1181511816 *
11816- * Currently only works for Foreign Key constraints.
11817+ * Currently only works for Foreign Key and not null constraints.
1181711818 *
1181811819 * If the constraint is modified, returns its address; otherwise, return
1181911820 * InvalidObjectAddress.
1182011821 */
1182111822static ObjectAddress
11822- ATExecAlterConstraint(Relation rel, ATAlterConstraint *cmdcon, bool recurse ,
11823- LOCKMODE lockmode)
11823+ ATExecAlterConstraint(List **wqueue, Relation rel, ATAlterConstraint *cmdcon,
11824+ bool recurse, LOCKMODE lockmode)
1182411825{
1182511826 Relation conrel;
1182611827 Relation tgrel;
@@ -11871,11 +11872,26 @@ ATExecAlterConstraint(Relation rel, ATAlterConstraint *cmdcon, bool recurse,
1187111872 cmdcon->conname, RelationGetRelationName(rel))));
1187211873
1187311874 currcon = (Form_pg_constraint) GETSTRUCT(contuple);
11874- if (currcon->contype != CONSTRAINT_FOREIGN)
11875+ if (cmdcon->alterDeferrability && currcon->contype != CONSTRAINT_FOREIGN)
1187511876 ereport(ERROR,
1187611877 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1187711878 errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
1187811879 cmdcon->conname, RelationGetRelationName(rel))));
11880+ if (cmdcon->alterInheritability &&
11881+ currcon->contype != CONSTRAINT_NOTNULL)
11882+ ereport(ERROR,
11883+ errcode(ERRCODE_WRONG_OBJECT_TYPE),
11884+ errmsg("constraint \"%s\" of relation \"%s\" is not a not-null constraint",
11885+ cmdcon->conname, RelationGetRelationName(rel)));
11886+
11887+ /* Refuse to modify inheritability of inherited constraints */
11888+ if (cmdcon->alterInheritability &&
11889+ cmdcon->noinherit && currcon->coninhcount > 0)
11890+ ereport(ERROR,
11891+ errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
11892+ errmsg("cannot alter inherited constraint \"%s\" on relation \"%s\"",
11893+ NameStr(currcon->conname),
11894+ RelationGetRelationName(rel)));
1187911895
1188011896 /*
1188111897 * If it's not the topmost constraint, raise an error.
@@ -11926,8 +11942,8 @@ ATExecAlterConstraint(Relation rel, ATAlterConstraint *cmdcon, bool recurse,
1192611942 /*
1192711943 * Do the actual catalog work, and recurse if necessary.
1192811944 */
11929- if (ATExecAlterConstraintInternal(cmdcon, conrel, tgrel, rel, contuple ,
11930- recurse, &otherrelids, lockmode))
11945+ if (ATExecAlterConstraintInternal(wqueue, cmdcon, conrel, tgrel, rel,
11946+ contuple, recurse, &otherrelids, lockmode))
1193111947 ObjectAddressSet(address, ConstraintRelationId, currcon->oid);
1193211948
1193311949 /*
@@ -11958,9 +11974,10 @@ ATExecAlterConstraint(Relation rel, ATAlterConstraint *cmdcon, bool recurse,
1195811974 * but existing releases don't do that.)
1195911975 */
1196011976static bool
11961- ATExecAlterConstraintInternal(ATAlterConstraint *cmdcon, Relation conrel,
11962- Relation tgrel, Relation rel, HeapTuple contuple,
11963- bool recurse, List **otherrelids, LOCKMODE lockmode)
11977+ ATExecAlterConstraintInternal(List **wqueue, ATAlterConstraint *cmdcon,
11978+ Relation conrel, Relation tgrel, Relation rel,
11979+ HeapTuple contuple, bool recurse,
11980+ List **otherrelids, LOCKMODE lockmode)
1196411981{
1196511982 Form_pg_constraint currcon;
1196611983 Oid refrelid = InvalidOid;
@@ -12040,14 +12057,82 @@ ATExecAlterConstraintInternal(ATAlterConstraint *cmdcon, Relation conrel,
1204012057 Relation childrel;
1204112058
1204212059 childrel = table_open(childcon->conrelid, lockmode);
12043- ATExecAlterConstraintInternal(cmdcon, conrel, tgrel, childrel, childtup ,
12044- recurse, otherrelids, lockmode);
12060+ ATExecAlterConstraintInternal(wqueue, cmdcon, conrel, tgrel, childrel,
12061+ childtup, recurse, otherrelids, lockmode);
1204512062 table_close(childrel, NoLock);
1204612063 }
1204712064
1204812065 systable_endscan(pscan);
1204912066 }
1205012067
12068+ /*
12069+ * Update the catalog for inheritability. No work if the constraint is
12070+ * already in the requested state.
12071+ */
12072+ if (cmdcon->alterInheritability &&
12073+ (cmdcon->noinherit != currcon->connoinherit))
12074+ {
12075+ AttrNumber colNum;
12076+ char *colName;
12077+ List *children;
12078+ HeapTuple copyTuple;
12079+ Form_pg_constraint copy_con;
12080+
12081+ /* The current implementation only works for NOT NULL constraints */
12082+ Assert(currcon->contype == CONSTRAINT_NOTNULL);
12083+
12084+ copyTuple = heap_copytuple(contuple);
12085+ copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
12086+ copy_con->connoinherit = cmdcon->noinherit;
12087+
12088+ CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple);
12089+ CommandCounterIncrement();
12090+ heap_freetuple(copyTuple);
12091+ changed = true;
12092+
12093+ /* Fetch the column number and name */
12094+ colNum = extractNotNullColumn(contuple);
12095+ colName = get_attname(currcon->conrelid, colNum, false);
12096+
12097+ /*
12098+ * Propagate the change to children. For SET NO INHERIT, we don't
12099+ * recursively affect children, just the immediate level.
12100+ */
12101+ children = find_inheritance_children(RelationGetRelid(rel),
12102+ lockmode);
12103+ foreach_oid(childoid, children)
12104+ {
12105+ ObjectAddress addr;
12106+
12107+ if (cmdcon->noinherit)
12108+ {
12109+ HeapTuple childtup;
12110+ Form_pg_constraint childcon;
12111+
12112+ childtup = findNotNullConstraint(childoid, colName);
12113+ if (!childtup)
12114+ elog(ERROR, "cache lookup failed for not-null constraint on column \"%s\" of relation %u",
12115+ colName, childoid);
12116+ childcon = (Form_pg_constraint) GETSTRUCT(childtup);
12117+ Assert(childcon->coninhcount > 0);
12118+ childcon->coninhcount--;
12119+ childcon->conislocal = true;
12120+ CatalogTupleUpdate(conrel, &childtup->t_self, childtup);
12121+ heap_freetuple(childtup);
12122+ }
12123+ else
12124+ {
12125+ Relation childrel = table_open(childoid, NoLock);
12126+
12127+ addr = ATExecSetNotNull(wqueue, childrel, NameStr(currcon->conname),
12128+ colName, true, true, lockmode);
12129+ if (OidIsValid(addr.objectId))
12130+ CommandCounterIncrement();
12131+ table_close(childrel, NoLock);
12132+ }
12133+ }
12134+ }
12135+
1205112136 return changed;
1205212137}
1205312138
0 commit comments