@ -141,7 +141,7 @@ typedef struct AlteredTableInfo
List * constraints ; /* List of NewConstraint */
List * newvals ; /* List of NewColumnValue */
bool new_notnull ; /* T if we added new NOT NULL constraints */
bool new_changeoids ; /* T if we added/dropped the OID column */
bool rewrite ; /* T if we a rewrite is forced */
Oid newTableSpace ; /* new tablespace; 0 means no change */
/* Objects to rebuild after completing ALTER TYPE operations */
List * changedConstraintOids ; /* OIDs of constraints to rebuild */
@ -336,6 +336,7 @@ static void ATPrepAlterColumnType(List **wqueue,
AlteredTableInfo * tab , Relation rel ,
bool recurse , bool recursing ,
AlterTableCmd * cmd , LOCKMODE lockmode ) ;
static bool ATColumnChangeRequiresRewrite ( Node * expr , AttrNumber varattno ) ;
static void ATExecAlterColumnType ( AlteredTableInfo * tab , Relation rel ,
const char * colName , TypeName * typeName , LOCKMODE lockmode ) ;
static void ATPostAlterTypeCleanup ( List * * wqueue , AlteredTableInfo * tab , LOCKMODE lockmode ) ;
@ -3218,11 +3219,34 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
if ( tab - > relkind = = RELKIND_FOREIGN_TABLE )
continue ;
/*
* If we change column data types or add / remove OIDs , the operation
* has to be propagated to tables that use this table ' s rowtype as a
* column type . tab - > newvals will also be non - NULL in the case where
* we ' re adding a column with a default . We choose to forbid that
* case as well , since composite types might eventually support
* defaults .
*
* ( Eventually we ' ll probably need to check for composite type
* dependencies even when we ' re just scanning the table without a
* rewrite , but at the moment a composite type does not enforce any
* constraints , so it ' s not necessary / appropriate to enforce them
* just during ALTER . )
*/
if ( tab - > newvals ! = NIL | | tab - > rewrite )
{
Relation rel ;
rel = heap_open ( tab - > relid , NoLock ) ;
find_composite_type_dependencies ( rel - > rd_rel - > reltype , rel , NULL ) ;
heap_close ( rel , NoLock ) ;
}
/*
* We only need to rewrite the table if at least one column needs to
* be recomputed , or we are adding / removing the OID column .
*/
if ( tab - > newvals ! = NIL | | tab - > new_changeoids )
if ( tab - > rewrite )
{
/* Build a temporary relation and copy data */
Relation OldHeap ;
@ -3408,22 +3432,6 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
hi_options = 0 ;
}
/*
* If we change column data types or add / remove OIDs , the operation has to
* be propagated to tables that use this table ' s rowtype as a column type .
* newrel will also be non - NULL in the case where we ' re adding a column
* with a default . We choose to forbid that case as well , since composite
* types might eventually support defaults .
*
* ( Eventually we ' ll probably need to check for composite type
* dependencies even when we ' re just scanning the table without a rewrite ,
* but at the moment a composite type does not enforce any constraints ,
* so it ' s not necessary / appropriate to enforce them just during ALTER . )
*/
if ( newrel )
find_composite_type_dependencies ( oldrel - > rd_rel - > reltype ,
oldrel , NULL ) ;
/*
* Generate the constraint and default execution states
*/
@ -3490,6 +3498,15 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
List * dropped_attrs = NIL ;
ListCell * lc ;
if ( newrel )
ereport ( DEBUG1 ,
( errmsg ( " rewriting table \" %s \" " ,
RelationGetRelationName ( oldrel ) ) ) ) ;
else
ereport ( DEBUG1 ,
( errmsg ( " verifying table \" %s \" " ,
RelationGetRelationName ( oldrel ) ) ) ) ;
econtext = GetPerTupleExprContext ( estate ) ;
/*
@ -3532,7 +3549,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
while ( ( tuple = heap_getnext ( scan , ForwardScanDirection ) ) ! = NULL )
{
if ( n ewrel )
if ( tab - > r ewrit e)
{
Oid tupOid = InvalidOid ;
@ -4330,6 +4347,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
newval - > expr = defval ;
tab - > newvals = lappend ( tab - > newvals , newval ) ;
tab - > rewrite = true ;
}
/*
@ -4346,7 +4364,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
* table to fix that .
*/
if ( isOid )
tab - > new_changeoids = true ;
tab - > rewrite = true ;
/*
* Add needed dependency entries for the new column .
@ -5019,7 +5037,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
tab = ATGetQueueEntry ( wqueue , rel ) ;
/* Tell Phase 3 to physically remove the OID column */
tab - > new_changeoids = true ;
tab - > rewrite = true ;
}
}
@ -5043,7 +5061,7 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
/* suppress schema rights check when rebuilding existing index */
check_rights = ! is_rebuild ;
/* skip index build if phase 3 will have to rewrite table anyway */
skip_build = ( tab - > newvals ! = NIL ) ;
skip_build = tab - > rewrite ;
/* suppress notices when rebuilding existing index */
quiet = is_rebuild ;
@ -6002,6 +6020,9 @@ validateForeignKeyConstraint(char *conname,
HeapTuple tuple ;
Trigger trig ;
ereport ( DEBUG1 ,
( errmsg ( " validating foreign key constraint \" %s \" " , conname ) ) ) ;
/*
* Build a trigger call structure ; we ' ll need it either way .
*/
@ -6560,6 +6581,8 @@ ATPrepAlterColumnType(List **wqueue,
newval - > expr = ( Expr * ) transform ;
tab - > newvals = lappend ( tab - > newvals , newval ) ;
if ( ATColumnChangeRequiresRewrite ( transform , attnum ) )
tab - > rewrite = true ;
}
else if ( tab - > relkind = = RELKIND_FOREIGN_TABLE )
{
@ -6599,6 +6622,29 @@ ATPrepAlterColumnType(List **wqueue,
ATTypedTableRecursion ( wqueue , rel , cmd , lockmode ) ;
}
/*
* When the data type of a column is changed , a rewrite might not be require
* if the data type is being changed to its current type , or more interestingly
* to a type to which it is binary coercible . But we must check carefully that
* the USING clause isn ' t trying to insert some other value .
*/
static bool
ATColumnChangeRequiresRewrite ( Node * expr , AttrNumber varattno )
{
Assert ( expr ! = NULL ) ;
for ( ; ; )
{
/* only one varno, so no need to check that */
if ( IsA ( expr , Var ) & & ( ( Var * ) expr ) - > varattno = = varattno )
return false ;
else if ( IsA ( expr , RelabelType ) )
expr = ( Node * ) ( ( RelabelType * ) expr ) - > arg ;
else
return true ;
}
}
static void
ATExecAlterColumnType ( AlteredTableInfo * tab , Relation rel ,
const char * colName , TypeName * typeName , LOCKMODE lockmode )