@@ -389,9 +389,10 @@ static void AlterIndexNamespaces(Relation classRel, Relation rel,
389
389
static void AlterSeqNamespaces(Relation classRel, Relation rel,
390
390
Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved,
391
391
LOCKMODE lockmode);
392
- static ObjectAddress ATExecAlterConstraint(Relation rel, ATAlterConstraint *cmdcon,
392
+ static ObjectAddress ATExecAlterConstraint(List **wqueue, Relation rel,
393
+ ATAlterConstraint *cmdcon,
393
394
bool recurse, LOCKMODE lockmode);
394
- static bool ATExecAlterConstraintInternal(ATAlterConstraint *cmdcon, Relation conrel,
395
+ static bool ATExecAlterConstraintInternal(List **wqueue, ATAlterConstraint *cmdcon, Relation conrel,
395
396
Relation tgrel, Relation rel, HeapTuple contuple,
396
397
bool recurse, List **otherrelids, LOCKMODE lockmode);
397
398
static void AlterConstrTriggerDeferrability(Oid conoid, Relation tgrel, Relation rel,
@@ -5437,8 +5438,8 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab,
5437
5438
lockmode);
5438
5439
break;
5439
5440
case AT_AlterConstraint: /* ALTER CONSTRAINT */
5440
- address = ATExecAlterConstraint(rel, castNode(ATAlterConstraint ,
5441
- cmd->def),
5441
+ address = ATExecAlterConstraint(wqueue, rel ,
5442
+ castNode(ATAlterConstraint, cmd->def),
5442
5443
cmd->recurse, lockmode);
5443
5444
break;
5444
5445
case AT_ValidateConstraint: /* VALIDATE CONSTRAINT */
@@ -11813,14 +11814,14 @@ GetForeignKeyCheckTriggers(Relation trigrel,
11813
11814
*
11814
11815
* Update the attributes of a constraint.
11815
11816
*
11816
- * Currently only works for Foreign Key constraints.
11817
+ * Currently only works for Foreign Key and not null constraints.
11817
11818
*
11818
11819
* If the constraint is modified, returns its address; otherwise, return
11819
11820
* InvalidObjectAddress.
11820
11821
*/
11821
11822
static 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)
11824
11825
{
11825
11826
Relation conrel;
11826
11827
Relation tgrel;
@@ -11871,11 +11872,26 @@ ATExecAlterConstraint(Relation rel, ATAlterConstraint *cmdcon, bool recurse,
11871
11872
cmdcon->conname, RelationGetRelationName(rel))));
11872
11873
11873
11874
currcon = (Form_pg_constraint) GETSTRUCT(contuple);
11874
- if (currcon->contype != CONSTRAINT_FOREIGN)
11875
+ if (cmdcon->alterDeferrability && currcon->contype != CONSTRAINT_FOREIGN)
11875
11876
ereport(ERROR,
11876
11877
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
11877
11878
errmsg("constraint \"%s\" of relation \"%s\" is not a foreign key constraint",
11878
11879
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)));
11879
11895
11880
11896
/*
11881
11897
* If it's not the topmost constraint, raise an error.
@@ -11926,8 +11942,8 @@ ATExecAlterConstraint(Relation rel, ATAlterConstraint *cmdcon, bool recurse,
11926
11942
/*
11927
11943
* Do the actual catalog work, and recurse if necessary.
11928
11944
*/
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))
11931
11947
ObjectAddressSet(address, ConstraintRelationId, currcon->oid);
11932
11948
11933
11949
/*
@@ -11958,9 +11974,10 @@ ATExecAlterConstraint(Relation rel, ATAlterConstraint *cmdcon, bool recurse,
11958
11974
* but existing releases don't do that.)
11959
11975
*/
11960
11976
static 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)
11964
11981
{
11965
11982
Form_pg_constraint currcon;
11966
11983
Oid refrelid = InvalidOid;
@@ -12040,14 +12057,82 @@ ATExecAlterConstraintInternal(ATAlterConstraint *cmdcon, Relation conrel,
12040
12057
Relation childrel;
12041
12058
12042
12059
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);
12045
12062
table_close(childrel, NoLock);
12046
12063
}
12047
12064
12048
12065
systable_endscan(pscan);
12049
12066
}
12050
12067
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
+
12051
12136
return changed;
12052
12137
}
12053
12138
0 commit comments