@ -7899,6 +7899,7 @@ ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMOD
Form_pg_attribute attTup ;
AttrNumber attnum ;
Relation attrelation ;
Oid attrdefoid ;
ObjectAddress address ;
attrelation = table_open ( AttributeRelationId , RowExclusiveLock ) ;
@ -7936,71 +7937,44 @@ ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMOD
}
}
/*
* Mark the column as no longer generated . ( The atthasdef flag needs to
* get cleared too , but RemoveAttrDefault will handle that . )
*/
attTup - > attgenerated = ' \0 ' ;
CatalogTupleUpdate ( attrelation , & tuple - > t_self , tuple ) ;
InvokeObjectPostAlterHook ( RelationRelationId ,
RelationGetRelid ( rel ) ,
attTup - > attnum ) ;
ObjectAddressSubSet ( address , RelationRelationId ,
RelationGetRelid ( rel ) , attnum ) ;
attnum ) ;
heap_freetuple ( tuple ) ;
table_close ( attrelation , RowExclusiveLock ) ;
CommandCounterIncrement ( ) ;
RemoveAttrDefault ( RelationGetRelid ( rel ) , attnum , DROP_RESTRICT , false , false ) ;
/*
* Remove all dependencies of this ( formerly generated ) column on other
* columns in the same table . ( See StoreAttrDefault ( ) for which
* dependencies are created . ) We don ' t expect there to be dependencies
* between columns of the same table for other reasons , so it ' s okay to
* remove all of them .
* Drop the dependency records of the GENERATED expression , in particular
* its INTERNAL dependency on the column , which would otherwise cause
* dependency . c to refuse to perform the deletion .
*/
{
Relation depRel ;
ScanKeyData key [ 3 ] ;
SysScanDesc scan ;
HeapTuple tup ;
depRel = table_open ( DependRelationId , RowExclusiveLock ) ;
ScanKeyInit ( & key [ 0 ] ,
Anum_pg_depend_classid ,
BTEqualStrategyNumber , F_OIDEQ ,
ObjectIdGetDatum ( RelationRelationId ) ) ;
ScanKeyInit ( & key [ 1 ] ,
Anum_pg_depend_objid ,
BTEqualStrategyNumber , F_OIDEQ ,
ObjectIdGetDatum ( RelationGetRelid ( rel ) ) ) ;
ScanKeyInit ( & key [ 2 ] ,
Anum_pg_depend_objsubid ,
BTEqualStrategyNumber , F_INT4EQ ,
Int32GetDatum ( attnum ) ) ;
attrdefoid = GetAttrDefaultOid ( RelationGetRelid ( rel ) , attnum ) ;
if ( ! OidIsValid ( attrdefoid ) )
elog ( ERROR , " could not find attrdef tuple for relation %u attnum %d " ,
RelationGetRelid ( rel ) , attnum ) ;
( void ) deleteDependencyRecordsFor ( AttrDefaultRelationId , attrdefoid , false ) ;
scan = systable_beginscan ( depRel , DependDependerIndexId , true ,
NULL , 3 , key ) ;
while ( HeapTupleIsValid ( tup = systable_getnext ( scan ) ) )
{
Form_pg_depend depform = ( Form_pg_depend ) GETSTRUCT ( tup ) ;
if ( depform - > refclassid = = RelationRelationId & &
depform - > refobjid = = RelationGetRelid ( rel ) & &
depform - > refobjsubid ! = 0 & &
depform - > deptype = = DEPENDENCY_AUTO )
{
CatalogTupleDelete ( depRel , & tup - > t_self ) ;
}
}
systable_endscan ( scan ) ;
/* Make above changes visible */
CommandCounterIncrement ( ) ;
table_close ( depRel , RowExclusiveLock ) ;
}
/*
* Get rid of the GENERATED expression itself . We use RESTRICT here for
* safety , but at present we do not expect anything to depend on the
* default .
*/
RemoveAttrDefault ( RelationGetRelid ( rel ) , attnum , DROP_RESTRICT ,
false , false ) ;
ObjectAddressSubSet ( address , RelationRelationId ,
RelationGetRelid ( rel ) , attnum ) ;
return address ;
}
@ -12548,21 +12522,6 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
*/
Assert ( foundObject . objectSubId = = 0 ) ;
}
else if ( relKind = = RELKIND_RELATION & &
foundObject . objectSubId ! = 0 & &
get_attgenerated ( foundObject . objectId , foundObject . objectSubId ) )
{
/*
* Changing the type of a column that is used by a
* generated column is not allowed by SQL standard . It
* might be doable with some thinking and effort .
*/
ereport ( ERROR ,
( errcode ( ERRCODE_SYNTAX_ERROR ) ,
errmsg ( " cannot alter type of a column used by a generated column " ) ,
errdetail ( " Column \" %s \" is used by generated column \" %s \" . " ,
colName , get_attname ( foundObject . objectId , foundObject . objectSubId , false ) ) ) ) ;
}
else
{
/* Not expecting any other direct dependencies... */
@ -12625,13 +12584,39 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
break ;
case OCLASS_DEFAULT :
{
ObjectAddress col = GetAttrDefaultColumnAddress ( foundObject . objectId ) ;
/*
* Ignore the column ' s default expression , since we will fix
* it below .
*/
Assert ( defaultexpr ) ;
break ;
if ( col . objectId = = RelationGetRelid ( rel ) & &
col . objectSubId = = attnum )
{
/*
* Ignore the column ' s own default expression , which
* we will deal with below .
*/
Assert ( defaultexpr ) ;
}
else
{
/*
* This must be a reference from the expression of a
* generated column elsewhere in the same table .
* Changing the type of a column that is used by a
* generated column is not allowed by SQL standard , so
* just punt for now . It might be doable with some
* thinking and effort .
*/
ereport ( ERROR ,
( errcode ( ERRCODE_FEATURE_NOT_SUPPORTED ) ,
errmsg ( " cannot alter type of a column used by a generated column " ) ,
errdetail ( " Column \" %s \" is used by generated column \" %s \" . " ,
colName ,
get_attname ( col . objectId ,
col . objectSubId ,
false ) ) ) ) ;
}
break ;
}
case OCLASS_STATISTIC_EXT :
@ -12694,9 +12679,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
/*
* Now scan for dependencies of this column on other things . The only
* thing we should find is the dependency on the column datatype , which we
* want to remove , possibly a collation dependency , and dependencies on
* other columns if it is a generated column .
* things we should find are the dependency on the column datatype and
* possibly a collation dependency . Those can be removed .
*/
ScanKeyInit ( & key [ 0 ] ,
Anum_pg_depend_classid ,
@ -12723,18 +12707,13 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
foundObject . objectId = foundDep - > refobjid ;
foundObject . objectSubId = foundDep - > refobjsubid ;
if ( foundDep - > deptype ! = DEPENDENCY_NORMAL & &
foundDep - > deptype ! = DEPENDENCY_AUTO )
if ( foundDep - > deptype ! = DEPENDENCY_NORMAL )
elog ( ERROR , " found unexpected dependency type '%c' " ,
foundDep - > deptype ) ;
if ( ! ( foundDep - > refclassid = = TypeRelationId & &
foundDep - > refobjid = = attTup - > atttypid ) & &
! ( foundDep - > refclassid = = CollationRelationId & &
foundDep - > refobjid = = attTup - > attcollation ) & &
! ( foundDep - > refclassid = = RelationRelationId & &
foundDep - > refobjid = = RelationGetRelid ( rel ) & &
foundDep - > refobjsubid ! = 0 )
)
foundDep - > refobjid = = attTup - > attcollation ) )
elog ( ERROR , " found unexpected dependency for column: %s " ,
getObjectDescription ( & foundObject , false ) ) ;
@ -12850,7 +12829,25 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
*/
if ( defaultexpr )
{
/* Must make new row visible since it will be updated again */
/*
* If it ' s a GENERATED default , drop its dependency records , in
* particular its INTERNAL dependency on the column , which would
* otherwise cause dependency . c to refuse to perform the deletion .
*/
if ( attTup - > attgenerated )
{
Oid attrdefoid = GetAttrDefaultOid ( RelationGetRelid ( rel ) , attnum ) ;
if ( ! OidIsValid ( attrdefoid ) )
elog ( ERROR , " could not find attrdef tuple for relation %u attnum %d " ,
RelationGetRelid ( rel ) , attnum ) ;
( void ) deleteDependencyRecordsFor ( AttrDefaultRelationId , attrdefoid , false ) ;
}
/*
* Make updates - so - far visible , particularly the new pg_attribute row
* which will be updated again .
*/
CommandCounterIncrement ( ) ;
/*