On Sat, Feb 5, 2011 at 7:44 PM, Noah Misch <n...@leadboat.com> wrote:
>> But this is a little unsatisfying, for two reasons.  First, the error
>> message will be subtly wrong: we can make it complain about a table or
>> a type, but not a foreign table.  At a quick look, it likes the right
>> fix might be to replace the second and third arguments to
>> find_composite_type_dependencies() with a Relation.
>
> Seems like a clear improvement.

That didn't quite work, because there's a caller in typecmds.c that
doesn't have the relation handy.  So I made it take a relkind and a
name, which works fine.

>> Second, I wonder
>> if we shouldn't refactor things so that all the checks fire in
>> ATRewriteTables() rather than doing them in different places.  Seems
>> like that might be cleaner.
>
> Offhand, this seems reasonable, too.  I assumed there was some good reason it
> couldn't be done there for non-tables, but nothing comes to mind.

Actually, thinking about this more, I'm thinking if we're going to
change anything, it seems we ought to go the other way.  If we ever
actually did support recursing into wherever the composite type
dependencies take us, we'd want to detect that before phase 3 and add
work-queue items for each table that we needed to futz with.

The attached patch takes this approach.  It's very slightly more code,
but it reduces the amount of spooky action at a distance.  The
existing coding is basically relying on the assumption that operations
which require finding composite type dependencies also require a table
rewrite.  That was probably true at one point in time, but it's not
really quite right.  It already requires compensating code foreign
tables and composite types (which can require this treatment even
though there's nothing to rewrite) and your proposed changes to avoid
table rewrites in cases where a type is changed to a compatible type
would break it in the opposite direction (the check would still be
needed even if the parent table doesn't need a rewrite, because the
rowtype could be indexed in some fashion that depends on the type of
the column being changed).

Comments?

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 6a17399..83f8be0 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3378,23 +3378,6 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 	}
 
 	/*
-	 * 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->rd_rel->relkind,
-										 RelationGetRelationName(oldrel));
-
-	/*
 	 * Generate the constraint and default execution states
 	 */
 
@@ -4055,7 +4038,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
 	Oid			typeOid;
 	int32		typmod;
 	Form_pg_type tform;
-	Expr	   *defval;
+	Expr	   *defval = NULL;
 
 	attrdesc = heap_open(AttributeRelationId, RowExclusiveLock);
 
@@ -4304,6 +4287,20 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
 		tab->new_changeoids = true;
 
 	/*
+	 * If we're adding an OID column, the operation has to be propagated to
+	 * tables that use this table's rowtype as a column type.  But we don't
+	 * currently have the infrastructure for that, so just throw an error.
+	 * We also forbid the case where we're adding a column with a default, since
+	 * composite types might eventually support defaults, and ALTER TABLE ..
+	 * ADD COLUMN .. DEFAULT would be expected to initialize the newly added
+	 * column to the default in each instantiation of the rowtype.
+	 */
+	if (isOid || defval)
+		find_composite_type_dependencies(rel->rd_rel->reltype,
+										 rel->rd_rel->relkind,
+										 RelationGetRelationName(rel));
+
+	/*
 	 * Add needed dependency entries for the new column.
 	 */
 	add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
@@ -4975,6 +4972,16 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
 
 		/* Tell Phase 3 to physically remove the OID column */
 		tab->new_changeoids = true;
+
+		/*
+		 * The OID removal operation needs to be propagated to tables that use
+		 * this table's rowtype as a column type.  But we don't currently have
+		 * the infrastructure for that, so just throw an error if it would be
+		 * required.
+		 */
+		find_composite_type_dependencies(rel->rd_rel->reltype,
+										 rel->rd_rel->relkind,
+										 RelationGetRelationName(rel));
 	}
 }
 
@@ -6442,17 +6449,15 @@ ATPrepAlterColumnType(List **wqueue,
 					 errmsg("ALTER TYPE USING is not supported on foreign tables")));
 	}
 
-	if (tab->relkind == RELKIND_COMPOSITE_TYPE
-		|| tab->relkind == RELKIND_FOREIGN_TABLE)
-	{
-		/*
-		 * For composite types, do this check now.  Tables will check
-		 * it later when the table is being rewritten.
-		 */
-		find_composite_type_dependencies(rel->rd_rel->reltype,
-										 rel->rd_rel->relkind,
-										 RelationGetRelationName(rel));
-	}
+	/*
+	 * If we change column data types, the operation has to be propagated to
+	 * tables that use this table's rowtype as a column type.  But we don't
+	 * currently have the infrastructure for that, so just throw an error
+	 * if it would be required.
+	 */
+	find_composite_type_dependencies(rel->rd_rel->reltype,
+									 rel->rd_rel->relkind,
+									 RelationGetRelationName(rel));
 
 	ReleaseSysCache(tuple);
 
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to