@ -149,6 +149,7 @@ typedef enum AlterTablePass
AT_PASS_ALTER_TYPE , /* ALTER COLUMN TYPE */
AT_PASS_ALTER_TYPE , /* ALTER COLUMN TYPE */
AT_PASS_ADD_COL , /* ADD COLUMN */
AT_PASS_ADD_COL , /* ADD COLUMN */
AT_PASS_SET_EXPRESSION , /* ALTER SET EXPRESSION */
AT_PASS_SET_EXPRESSION , /* ALTER SET EXPRESSION */
AT_PASS_OLD_COL_ATTRS , /* re-install attnotnull */
AT_PASS_OLD_INDEX , /* re-add existing indexes */
AT_PASS_OLD_INDEX , /* re-add existing indexes */
AT_PASS_OLD_CONSTR , /* re-add existing constraints */
AT_PASS_OLD_CONSTR , /* re-add existing constraints */
/* We could support a RENAME COLUMN pass here, but not currently used */
/* We could support a RENAME COLUMN pass here, but not currently used */
@ -7662,17 +7663,23 @@ ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
}
}
/*
/*
* Find the constraint that makes this column NOT NULL .
* Find the constraint that makes this column NOT NULL , and drop it if we
* see one . dropconstraint_internal ( ) will do necessary consistency
* checking . If there isn ' t one , there are two possibilities : either the
* column is marked attnotnull because it ' s part of the primary key , and
* then we just throw an appropriate error ; or it ' s a leftover marking
* that we can remove . However , before doing the latter , to avoid
* breaking consistency any further , prevent this if the column is part of
* the replica identity .
*/
*/
conTup = findNotNullConstraint ( RelationGetRelid ( rel ) , colName ) ;
conTup = findNotNullConstraint ( RelationGetRelid ( rel ) , colName ) ;
if ( conTup = = NULL )
if ( conTup = = NULL )
{
{
Bitmapset * pkcols ;
Bitmapset * pkcols ;
Bitmapset * ircols ;
/*
/*
* There ' s no not - null constraint , so throw an error . If the column
* If the column is in a primary key , throw a specific error message .
* is in a primary key , we can throw a specific error . Otherwise ,
* this is unexpected .
*/
*/
pkcols = RelationGetIndexAttrBitmap ( rel , INDEX_ATTR_BITMAP_PRIMARY_KEY ) ;
pkcols = RelationGetIndexAttrBitmap ( rel , INDEX_ATTR_BITMAP_PRIMARY_KEY ) ;
if ( bms_is_member ( attnum - FirstLowInvalidHeapAttributeNumber ,
if ( bms_is_member ( attnum - FirstLowInvalidHeapAttributeNumber ,
@ -7681,16 +7688,27 @@ ATExecDropNotNull(Relation rel, const char *colName, bool recurse,
errcode ( ERRCODE_INVALID_TABLE_DEFINITION ) ,
errcode ( ERRCODE_INVALID_TABLE_DEFINITION ) ,
errmsg ( " column \" %s \" is in a primary key " , colName ) ) ;
errmsg ( " column \" %s \" is in a primary key " , colName ) ) ;
/* this shouldn't happen */
/* Also throw an error if the column is in the replica identity */
elog ( ERROR , " could not find not-null constraint on column \" %s \" , relation \" %s \" " ,
ircols = RelationGetIndexAttrBitmap ( rel , INDEX_ATTR_BITMAP_IDENTITY_KEY ) ;
colName , RelationGetRelationName ( rel ) ) ;
if ( bms_is_member ( attnum - FirstLowInvalidHeapAttributeNumber , ircols ) )
}
ereport ( ERROR ,
errcode ( ERRCODE_INVALID_TABLE_DEFINITION ) ,
errmsg ( " column \" %s \" is in index used as replica identity " ,
get_attname ( RelationGetRelid ( rel ) , attnum , false ) ) ) ;
/* Otherwise, just remove the attnotnull marking and do nothing else. */
attTup - > attnotnull = false ;
CatalogTupleUpdate ( attr_rel , & tuple - > t_self , tuple ) ;
}
else
{
/* The normal case: we have a pg_constraint row, remove it */
readyRels = NIL ;
readyRels = NIL ;
dropconstraint_internal ( rel , conTup , DROP_RESTRICT , recurse , false ,
dropconstraint_internal ( rel , conTup , DROP_RESTRICT , recurse , false ,
false , & readyRels , lockmode ) ;
false , & readyRels , lockmode ) ;
heap_freetuple ( conTup ) ;
heap_freetuple ( conTup ) ;
}
InvokeObjectPostAlterHook ( RelationRelationId ,
InvokeObjectPostAlterHook ( RelationRelationId ,
RelationGetRelid ( rel ) , attnum ) ;
RelationGetRelid ( rel ) , attnum ) ;
@ -12927,12 +12945,11 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha
Form_pg_constraint con ;
Form_pg_constraint con ;
ObjectAddress conobj ;
ObjectAddress conobj ;
List * children ;
List * children ;
ListCell * child ;
bool is_no_inherit_constraint = false ;
bool is_no_inherit_constraint = false ;
bool dropping_pk = false ;
char * constrName ;
char * constrName ;
List * unconstrained_cols = NIL ;
List * unconstrained_cols = NIL ;
char * colname ;
char * colname = NULL ;
bool dropping_pk = false ;
if ( list_member_oid ( * readyRels , RelationGetRelid ( rel ) ) )
if ( list_member_oid ( * readyRels , RelationGetRelid ( rel ) ) )
return InvalidObjectAddress ;
return InvalidObjectAddress ;
@ -12989,10 +13006,12 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha
*/
*/
if ( con - > contype = = CONSTRAINT_NOTNULL )
if ( con - > contype = = CONSTRAINT_NOTNULL )
{
{
AttrNumber colnum = extractNotNullColumn ( constraintTup ) ;
AttrNumber colnum ;
if ( colnum ! = InvalidAttrNumber )
colnum = extractNotNullColumn ( constraintTup ) ;
unconstrained_cols = list_make1_int ( colnum ) ;
unconstrained_cols = list_make1_int ( colnum ) ;
colname = NameStr ( TupleDescAttr ( RelationGetDescr ( rel ) ,
colnum - 1 ) - > attname ) ;
}
}
else if ( con - > contype = = CONSTRAINT_PRIMARY )
else if ( con - > contype = = CONSTRAINT_PRIMARY )
{
{
@ -13048,18 +13067,16 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha
performDeletion ( & conobj , behavior , 0 ) ;
performDeletion ( & conobj , behavior , 0 ) ;
/*
/*
* If this was a NOT NULL or the primary key , the constrained columns must
* If this was a NOT NULL or the primary key , verify that we still have
* have had pg_attribute . attnotnull set . See if we need to reset it , and
* constraints to support GENERATED AS IDENTITY or the replica identity .
* do so .
*/
*/
if ( unconstrained_cols )
if ( unconstrained_cols ! = NIL )
{
{
Relation attrel ;
Relation attrel ;
Bitmapset * pkcols ;
Bitmapset * pkcols ;
Bitmapset * ircols ;
Bitmapset * ircols ;
ListCell * lc ;
/* Make the above deletion visible */
/* Make implicit attnotnull changes visible */
CommandCounterIncrement ( ) ;
CommandCounterIncrement ( ) ;
attrel = table_open ( AttributeRelationId , RowExclusiveLock ) ;
attrel = table_open ( AttributeRelationId , RowExclusiveLock ) ;
@ -13073,33 +13090,31 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha
INDEX_ATTR_BITMAP_PRIMARY_KEY ) ;
INDEX_ATTR_BITMAP_PRIMARY_KEY ) ;
ircols = RelationGetIndexAttrBitmap ( rel , INDEX_ATTR_BITMAP_IDENTITY_KEY ) ;
ircols = RelationGetIndexAttrBitmap ( rel , INDEX_ATTR_BITMAP_IDENTITY_KEY ) ;
foreach ( lc , unconstrained_cols )
foreach_int ( attnum , unconstrained_cols )
{
{
AttrNumber attnum = lfirst_int ( lc ) ;
HeapTuple atttup ;
HeapTuple atttup ;
HeapTuple contup ;
HeapTuple contup ;
Form_pg_attribute attForm ;
Form_pg_attribute attForm ;
char attidentity ;
/*
/*
* Obtain pg_attribute tuple and verify conditions on it . We use
* Obtain pg_attribute tuple and verify conditions on it .
* a copy we can scribble on .
*/
*/
atttup = SearchSysCacheCopy AttNum ( RelationGetRelid ( rel ) , attnum ) ;
atttup = SearchSysCacheAttNum ( RelationGetRelid ( rel ) , attnum ) ;
if ( ! HeapTupleIsValid ( atttup ) )
if ( ! HeapTupleIsValid ( atttup ) )
elog ( ERROR , " cache lookup failed for attribute %d of relation %u " ,
elog ( ERROR , " cache lookup failed for attribute %d of relation %u " ,
attnum , RelationGetRelid ( rel ) ) ;
attnum , RelationGetRelid ( rel ) ) ;
attForm = ( Form_pg_attribute ) GETSTRUCT ( atttup ) ;
attForm = ( Form_pg_attribute ) GETSTRUCT ( atttup ) ;
attidentity = attForm - > attidentity ;
ReleaseSysCache ( atttup ) ;
/*
/*
* Since the above deletion has been made visible , we can now
* Since the above deletion has been made visible , we can now
* search for any remaining constraints on this column ( or these
* search for any remaining constraints on this column ( or these
* columns , in the case we ' re dropping a multicol primary key . )
* columns , in the case we ' re dropping a multicol primary key . )
* Then , verify whether any further NOT NULL or primary key
* Then , verify whether any further NOT NULL or primary key
* exists , and reset attnotnull if none .
* exists : if none and this is a generated identity column or the
*
* replica identity , abort the whole thing .
* However , if this is a generated identity column , abort the
* whole thing with a specific error message , because the
* constraint is required in that case .
*/
*/
contup = findNotNullConstraintAttnum ( RelationGetRelid ( rel ) , attnum ) ;
contup = findNotNullConstraintAttnum ( RelationGetRelid ( rel ) , attnum ) ;
if ( contup | |
if ( contup | |
@ -13111,7 +13126,7 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha
* It ' s not valid to drop the not - null constraint for a GENERATED
* It ' s not valid to drop the not - null constraint for a GENERATED
* AS IDENTITY column .
* AS IDENTITY column .
*/
*/
if ( attForm - > attidentity )
if ( attidentity ! = ' \0 ' )
ereport ( ERROR ,
ereport ( ERROR ,
errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errmsg ( " column \" %s \" of relation \" %s \" is an identity column " ,
errmsg ( " column \" %s \" of relation \" %s \" is an identity column " ,
@ -13123,18 +13138,11 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha
* It ' s not valid to drop the not - null constraint for a column in
* It ' s not valid to drop the not - null constraint for a column in
* the replica identity index , either . ( FULL is not affected . )
* the replica identity index , either . ( FULL is not affected . )
*/
*/
if ( bms_is_member ( lfirst_int ( lc ) - FirstLowInvalidHeapAttributeNumber , ircols ) )
if ( bms_is_member ( attnum - FirstLowInvalidHeapAttributeNumber , ircols ) )
ereport ( ERROR ,
ereport ( ERROR ,
errcode ( ERRCODE_INVALID_TABLE_DEFINITION ) ,
errcode ( ERRCODE_INVALID_TABLE_DEFINITION ) ,
errmsg ( " column \" %s \" is in index used as replica identity " ,
errmsg ( " column \" %s \" is in index used as replica identity " ,
get_attname ( RelationGetRelid ( rel ) , lfirst_int ( lc ) , false ) ) ) ;
get_attname ( RelationGetRelid ( rel ) , attnum , false ) ) ) ;
/* Reset attnotnull */
if ( attForm - > attnotnull )
{
attForm - > attnotnull = false ;
CatalogTupleUpdate ( attrel , & atttup - > t_self , atttup ) ;
}
}
}
table_close ( attrel , RowExclusiveLock ) ;
table_close ( attrel , RowExclusiveLock ) ;
}
}
@ -13173,16 +13181,8 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha
errmsg ( " cannot remove constraint from only the partitioned table when partitions exist " ) ,
errmsg ( " cannot remove constraint from only the partitioned table when partitions exist " ) ,
errhint ( " Do not specify the ONLY keyword. " ) ) ) ;
errhint ( " Do not specify the ONLY keyword. " ) ) ) ;
/* For not-null constraints we recurse by column name */
foreach_oid ( childrelid , children )
if ( con - > contype = = CONSTRAINT_NOTNULL )
colname = NameStr ( TupleDescAttr ( RelationGetDescr ( rel ) ,
linitial_int ( unconstrained_cols ) - 1 ) - > attname ) ;
else
colname = NULL ; /* keep compiler quiet */
foreach ( child , children )
{
{
Oid childrelid = lfirst_oid ( child ) ;
Relation childrel ;
Relation childrel ;
HeapTuple tuple ;
HeapTuple tuple ;
Form_pg_constraint childcon ;
Form_pg_constraint childcon ;
@ -13195,8 +13195,8 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha
CheckTableNotInUse ( childrel , " ALTER TABLE " ) ;
CheckTableNotInUse ( childrel , " ALTER TABLE " ) ;
/*
/*
* We search for not - null constraint by column number , and other
* We search for not - null constraints by column name , and others by
* constraints by name .
* constraint name .
*/
*/
if ( con - > contype = = CONSTRAINT_NOTNULL )
if ( con - > contype = = CONSTRAINT_NOTNULL )
{
{
@ -13304,7 +13304,6 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha
rel - > rd_rel - > relhassubclass )
rel - > rd_rel - > relhassubclass )
{
{
List * colnames = NIL ;
List * colnames = NIL ;
ListCell * lc ;
List * pkready = NIL ;
List * pkready = NIL ;
/*
/*
@ -13317,15 +13316,14 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha
* Find out the list of column names to process . Fortunately , we
* Find out the list of column names to process . Fortunately , we
* already have the list of column numbers .
* already have the list of column numbers .
*/
*/
foreach ( lc , unconstrained_cols )
foreach_int ( attnum , unconstrained_cols )
{
{
colnames = lappend ( colnames , get_attname ( RelationGetRelid ( rel ) ,
colnames = lappend ( colnames , get_attname ( RelationGetRelid ( rel ) ,
lfirst_int ( lc ) , false ) ) ;
attnum , false ) ) ;
}
}
foreach ( child , children )
foreach_oid ( childreli d , children )
{
{
Oid childrelid = lfirst_oid ( child ) ;
Relation childrel ;
Relation childrel ;
if ( list_member_oid ( pkready , childrelid ) )
if ( list_member_oid ( pkready , childrelid ) )
@ -13335,10 +13333,9 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha
childrel = table_open ( childrelid , NoLock ) ;
childrel = table_open ( childrelid , NoLock ) ;
CheckTableNotInUse ( childrel , " ALTER TABLE " ) ;
CheckTableNotInUse ( childrel , " ALTER TABLE " ) ;
foreach ( l c, colnames )
foreach_ptr ( char , colName , colnames )
{
{
HeapTuple contup ;
HeapTuple contup ;
char * colName = lfirst ( lc ) ;
contup = findNotNullConstraint ( childrelid , colName ) ;
contup = findNotNullConstraint ( childrelid , colName ) ;
if ( contup = = NULL )
if ( contup = = NULL )
@ -14677,12 +14674,16 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
else if ( cmd - > subtype = = AT_SetAttNotNull )
else if ( cmd - > subtype = = AT_SetAttNotNull )
{
{
/*
/*
* The parser will create AT_AttSetNotNull subcommands for
* We see this subtype when a primary key is created
* columns of PRIMARY KEY indexes / constraints , but we need
* internally , for example when it is replaced with a new
* not do anything with them here , because the columns '
* constraint ( say because one of the columns changes
* NOT NULL marks will already have been propagated into
* type ) ; in this case we need to reinstate attnotnull ,
* the new table definition .
* because it was removed because of the drop of the old
* PK . Schedule this subcommand to an upcoming AT pass .
*/
*/
cmd - > subtype = AT_SetAttNotNull ;
tab - > subcmds [ AT_PASS_OLD_COL_ATTRS ] =
lappend ( tab - > subcmds [ AT_PASS_OLD_COL_ATTRS ] , cmd ) ;
}
}
else
else
elog ( ERROR , " unexpected statement subtype: %d " ,
elog ( ERROR , " unexpected statement subtype: %d " ,