Commit 65377e0b authored by Robert Haas's avatar Robert Haas

Tighten ALTER FOREIGN TABLE .. SET DATA TYPE checks.

If the foreign table's rowtype is being used as the type of a column in
another table, we can't just up and change its data type.  This was
already checked for composite types and ordinary tables, but we
previously failed to enforce it for foreign tables.
parent 51dbc87d
...@@ -3391,8 +3391,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode) ...@@ -3391,8 +3391,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
*/ */
if (newrel) if (newrel)
find_composite_type_dependencies(oldrel->rd_rel->reltype, find_composite_type_dependencies(oldrel->rd_rel->reltype,
RelationGetRelationName(oldrel), oldrel->rd_rel->relkind,
NULL); RelationGetRelationName(oldrel));
/* /*
* Generate the constraint and default execution states * Generate the constraint and default execution states
...@@ -3860,9 +3860,8 @@ ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, ...@@ -3860,9 +3860,8 @@ ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
* to reject the ALTER. (How safe is this really?) * to reject the ALTER. (How safe is this really?)
*/ */
void void
find_composite_type_dependencies(Oid typeOid, find_composite_type_dependencies(Oid typeOid, char origRelkind,
const char *origTblName, const char *origRelname)
const char *origTypeName)
{ {
Relation depRel; Relation depRel;
ScanKeyData key[2]; ScanKeyData key[2];
...@@ -3905,20 +3904,19 @@ find_composite_type_dependencies(Oid typeOid, ...@@ -3905,20 +3904,19 @@ find_composite_type_dependencies(Oid typeOid,
if (rel->rd_rel->relkind == RELKIND_RELATION) if (rel->rd_rel->relkind == RELKIND_RELATION)
{ {
if (origTblName) const char *msg;
ereport(ERROR, if (origRelkind == RELKIND_COMPOSITE_TYPE)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), msg = gettext_noop("cannot alter type \"%s\" because column \"%s\".\"%s\" uses it");
errmsg("cannot alter table \"%s\" because column \"%s\".\"%s\" uses its rowtype", else if (origRelkind == RELKIND_FOREIGN_TABLE)
origTblName, msg = gettext_noop("cannot alter foreign table \"%s\" because column \"%s\".\"%s\" uses its rowtype");
RelationGetRelationName(rel),
NameStr(att->attname))));
else else
ereport(ERROR, msg = gettext_noop("cannot alter table \"%s\" because column \"%s\".\"%s\" uses its rowtype");
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ereport(ERROR,
errmsg("cannot alter type \"%s\" because column \"%s\".\"%s\" uses it", (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
origTypeName, errmsg(msg,
RelationGetRelationName(rel), origRelname,
NameStr(att->attname)))); RelationGetRelationName(rel),
NameStr(att->attname))));
} }
else if (OidIsValid(rel->rd_rel->reltype)) else if (OidIsValid(rel->rd_rel->reltype))
{ {
...@@ -3927,7 +3925,7 @@ find_composite_type_dependencies(Oid typeOid, ...@@ -3927,7 +3925,7 @@ find_composite_type_dependencies(Oid typeOid,
* recursively check for indirect dependencies via its rowtype. * recursively check for indirect dependencies via its rowtype.
*/ */
find_composite_type_dependencies(rel->rd_rel->reltype, find_composite_type_dependencies(rel->rd_rel->reltype,
origTblName, origTypeName); origRelkind, origRelname);
} }
relation_close(rel, AccessShareLock); relation_close(rel, AccessShareLock);
...@@ -3943,7 +3941,7 @@ find_composite_type_dependencies(Oid typeOid, ...@@ -3943,7 +3941,7 @@ find_composite_type_dependencies(Oid typeOid,
*/ */
arrayOid = get_array_type(typeOid); arrayOid = get_array_type(typeOid);
if (OidIsValid(arrayOid)) if (OidIsValid(arrayOid))
find_composite_type_dependencies(arrayOid, origTblName, origTypeName); find_composite_type_dependencies(arrayOid, origRelkind, origRelname);
} }
...@@ -6444,14 +6442,15 @@ ATPrepAlterColumnType(List **wqueue, ...@@ -6444,14 +6442,15 @@ ATPrepAlterColumnType(List **wqueue,
errmsg("ALTER TYPE USING is not supported on foreign tables"))); errmsg("ALTER TYPE USING is not supported on foreign tables")));
} }
if (tab->relkind == RELKIND_COMPOSITE_TYPE) if (tab->relkind == RELKIND_COMPOSITE_TYPE
|| tab->relkind == RELKIND_FOREIGN_TABLE)
{ {
/* /*
* For composite types, do this check now. Tables will check * For composite types, do this check now. Tables will check
* it later when the table is being rewritten. * it later when the table is being rewritten.
*/ */
find_composite_type_dependencies(rel->rd_rel->reltype, find_composite_type_dependencies(rel->rd_rel->reltype,
NULL, rel->rd_rel->relkind,
RelationGetRelationName(rel)); RelationGetRelationName(rel));
} }
......
...@@ -2183,7 +2183,7 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode) ...@@ -2183,7 +2183,7 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
*/ */
if (OidIsValid(rel->rd_rel->reltype)) if (OidIsValid(rel->rd_rel->reltype))
find_composite_type_dependencies(rel->rd_rel->reltype, find_composite_type_dependencies(rel->rd_rel->reltype,
NULL, RELKIND_COMPOSITE_TYPE,
format_type_be(domainOid)); format_type_be(domainOid));
/* Otherwise we can ignore views, composite types, etc */ /* Otherwise we can ignore views, composite types, etc */
......
...@@ -53,8 +53,7 @@ extern void RenameRelationInternal(Oid myrelid, ...@@ -53,8 +53,7 @@ extern void RenameRelationInternal(Oid myrelid,
Oid namespaceId); Oid namespaceId);
extern void find_composite_type_dependencies(Oid typeOid, extern void find_composite_type_dependencies(Oid typeOid,
const char *origTblName, char origRelkind, const char *origRelname);
const char *origTypeName);
extern AttrNumber *varattnos_map(TupleDesc olddesc, TupleDesc newdesc); extern AttrNumber *varattnos_map(TupleDesc olddesc, TupleDesc newdesc);
extern AttrNumber *varattnos_map_schema(TupleDesc old, List *schema); extern AttrNumber *varattnos_map_schema(TupleDesc old, List *schema);
......
...@@ -692,7 +692,12 @@ ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) using '0'; -- ERROR ...@@ -692,7 +692,12 @@ ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) using '0'; -- ERROR
ERROR: ALTER TYPE USING is not supported on foreign tables ERROR: ALTER TYPE USING is not supported on foreign tables
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10); ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE text; ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE text;
ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c9_check CHECK (c9 < 0); -- can't change the column type if it's used elsewhere
CREATE TABLE use_ft1_column_type (x ft1);
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE integer; -- ERROR
ERROR: cannot alter foreign table "ft1" because column "use_ft1_column_type"."x" uses its rowtype
DROP TABLE use_ft1_column_type;
ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c9_check CHECK (c9 < 0); -- ERROR
ERROR: "ft1" is not a table ERROR: "ft1" is not a table
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT no_const; -- ERROR ALTER FOREIGN TABLE ft1 DROP CONSTRAINT no_const; -- ERROR
ERROR: "ft1" is not a table ERROR: "ft1" is not a table
......
...@@ -293,7 +293,11 @@ ALTER FOREIGN TABLE ft1 ALTER COLUMN c7 DROP NOT NULL; ...@@ -293,7 +293,11 @@ ALTER FOREIGN TABLE ft1 ALTER COLUMN c7 DROP NOT NULL;
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) using '0'; -- ERROR ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) using '0'; -- ERROR
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10); ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE text; ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE text;
ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c9_check CHECK (c9 < 0); -- can't change the column type if it's used elsewhere
CREATE TABLE use_ft1_column_type (x ft1);
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE integer; -- ERROR
DROP TABLE use_ft1_column_type;
ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c9_check CHECK (c9 < 0); -- ERROR
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT no_const; -- ERROR ALTER FOREIGN TABLE ft1 DROP CONSTRAINT no_const; -- ERROR
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT IF EXISTS no_const; ALTER FOREIGN TABLE ft1 DROP CONSTRAINT IF EXISTS no_const;
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c1_check; ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c1_check;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment