@@ -141,7 +141,7 @@ typedef struct AlteredTableInfo
141141List * constraints ;/* List of NewConstraint */
142142List * newvals ;/* List of NewColumnValue */
143143bool new_notnull ;/* T if we added new NOT NULL constraints */
144- bool new_changeoids ; /* T if weadded/dropped the OID column */
144+ bool rewrite ; /* T if wea rewrite is forced */
145145Oid newTableSpace ;/* new tablespace; 0 means no change */
146146/* Objects to rebuild after completing ALTER TYPE operations */
147147List * changedConstraintOids ;/* OIDs of constraints to rebuild */
@@ -336,6 +336,7 @@ static void ATPrepAlterColumnType(List **wqueue,
336336AlteredTableInfo * tab ,Relation rel ,
337337bool recurse ,bool recursing ,
338338AlterTableCmd * cmd ,LOCKMODE lockmode );
339+ static bool ATColumnChangeRequiresRewrite (Node * expr ,AttrNumber varattno );
339340static void ATExecAlterColumnType (AlteredTableInfo * tab ,Relation rel ,
340341const char * colName ,TypeName * typeName ,LOCKMODE lockmode );
341342static void ATPostAlterTypeCleanup (List * * wqueue ,AlteredTableInfo * tab ,LOCKMODE lockmode );
@@ -3218,11 +3219,34 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
32183219if (tab -> relkind == RELKIND_FOREIGN_TABLE )
32193220continue ;
32203221
3222+ /*
3223+ * If we change column data types or add/remove OIDs, the operation
3224+ * has to be propagated to tables that use this table's rowtype as a
3225+ * column type. tab->newvals will also be non-NULL in the case where
3226+ * we're adding a column with a default. We choose to forbid that
3227+ * case as well, since composite types might eventually support
3228+ * defaults.
3229+ *
3230+ * (Eventually we'll probably need to check for composite type
3231+ * dependencies even when we're just scanning the table without a
3232+ * rewrite, but at the moment a composite type does not enforce any
3233+ * constraints, so it's not necessary/appropriate to enforce them
3234+ * just during ALTER.)
3235+ */
3236+ if (tab -> newvals != NIL || tab -> rewrite )
3237+ {
3238+ Relation rel ;
3239+
3240+ rel = heap_open (tab -> relid ,NoLock );
3241+ find_composite_type_dependencies (rel -> rd_rel -> reltype ,rel ,NULL );
3242+ heap_close (rel ,NoLock );
3243+ }
3244+
32213245/*
32223246 * We only need to rewrite the table if at least one column needs to
32233247 * be recomputed, or we are adding/removing the OID column.
32243248 */
3225- if (tab -> newvals != NIL || tab -> new_changeoids )
3249+ if (tab -> rewrite )
32263250{
32273251/* Build a temporary relation and copy data */
32283252Relation OldHeap ;
@@ -3408,22 +3432,6 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
34083432hi_options = 0 ;
34093433}
34103434
3411- /*
3412- * If we change column data types or add/remove OIDs, the operation has to
3413- * be propagated to tables that use this table's rowtype as a column type.
3414- * newrel will also be non-NULL in the case where we're adding a column
3415- * with a default. We choose to forbid that case as well, since composite
3416- * types might eventually support defaults.
3417- *
3418- * (Eventually we'll probably need to check for composite type
3419- * dependencies even when we're just scanning the table without a rewrite,
3420- * but at the moment a composite type does not enforce any constraints,
3421- * so it's not necessary/appropriate to enforce them just during ALTER.)
3422- */
3423- if (newrel )
3424- find_composite_type_dependencies (oldrel -> rd_rel -> reltype ,
3425- oldrel ,NULL );
3426-
34273435/*
34283436 * Generate the constraint and default execution states
34293437 */
@@ -3490,6 +3498,15 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
34903498List * dropped_attrs = NIL ;
34913499ListCell * lc ;
34923500
3501+ if (newrel )
3502+ ereport (DEBUG1 ,
3503+ (errmsg ("rewriting table \"%s\"" ,
3504+ RelationGetRelationName (oldrel ))));
3505+ else
3506+ ereport (DEBUG1 ,
3507+ (errmsg ("verifying table \"%s\"" ,
3508+ RelationGetRelationName (oldrel ))));
3509+
34933510econtext = GetPerTupleExprContext (estate );
34943511
34953512/*
@@ -3532,7 +3549,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
35323549
35333550while ((tuple = heap_getnext (scan ,ForwardScanDirection ))!= NULL )
35343551{
3535- if (newrel )
3552+ if (tab -> rewrite )
35363553{
35373554Oid tupOid = InvalidOid ;
35383555
@@ -4330,6 +4347,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
43304347newval -> expr = defval ;
43314348
43324349tab -> newvals = lappend (tab -> newvals ,newval );
4350+ tab -> rewrite = true;
43334351}
43344352
43354353/*
@@ -4346,7 +4364,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
43464364 * table to fix that.
43474365 */
43484366if (isOid )
4349- tab -> new_changeoids = true;
4367+ tab -> rewrite = true;
43504368
43514369/*
43524370 * Add needed dependency entries for the new column.
@@ -5019,7 +5037,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
50195037tab = ATGetQueueEntry (wqueue ,rel );
50205038
50215039/* Tell Phase 3 to physically remove the OID column */
5022- tab -> new_changeoids = true;
5040+ tab -> rewrite = true;
50235041}
50245042}
50255043
@@ -5043,7 +5061,7 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
50435061/* suppress schema rights check when rebuilding existing index */
50445062check_rights = !is_rebuild ;
50455063/* skip index build if phase 3 will have to rewrite table anyway */
5046- skip_build = ( tab -> newvals != NIL ) ;
5064+ skip_build = tab -> rewrite ;
50475065/* suppress notices when rebuilding existing index */
50485066quiet = is_rebuild ;
50495067
@@ -6002,6 +6020,9 @@ validateForeignKeyConstraint(char *conname,
60026020HeapTuple tuple ;
60036021Trigger trig ;
60046022
6023+ ereport (DEBUG1 ,
6024+ (errmsg ("validating foreign key constraint \"%s\"" ,conname )));
6025+
60056026/*
60066027 * Build a trigger call structure; we'll need it either way.
60076028 */
@@ -6560,6 +6581,8 @@ ATPrepAlterColumnType(List **wqueue,
65606581newval -> expr = (Expr * )transform ;
65616582
65626583tab -> newvals = lappend (tab -> newvals ,newval );
6584+ if (ATColumnChangeRequiresRewrite (transform ,attnum ))
6585+ tab -> rewrite = true;
65636586}
65646587else if (tab -> relkind == RELKIND_FOREIGN_TABLE )
65656588{
@@ -6599,6 +6622,29 @@ ATPrepAlterColumnType(List **wqueue,
65996622ATTypedTableRecursion (wqueue ,rel ,cmd ,lockmode );
66006623}
66016624
6625+ /*
6626+ * When the data type of a column is changed, a rewrite might not be require
6627+ * if the data type is being changed to its current type, or more interestingly
6628+ * to a type to which it is binary coercible. But we must check carefully that
6629+ * the USING clause isn't trying to insert some other value.
6630+ */
6631+ static bool
6632+ ATColumnChangeRequiresRewrite (Node * expr ,AttrNumber varattno )
6633+ {
6634+ Assert (expr != NULL );
6635+
6636+ for (;;)
6637+ {
6638+ /* only one varno, so no need to check that */
6639+ if (IsA (expr ,Var )&& ((Var * )expr )-> varattno == varattno )
6640+ return false;
6641+ else if (IsA (expr ,RelabelType ))
6642+ expr = (Node * ) ((RelabelType * )expr )-> arg ;
6643+ else
6644+ return true;
6645+ }
6646+ }
6647+
66026648static void
66036649ATExecAlterColumnType (AlteredTableInfo * tab ,Relation rel ,
66046650const char * colName ,TypeName * typeName ,LOCKMODE lockmode )