Skip to content

Commit 65377e0

Browse files
committed
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.
1 parent 51dbc87 commit 65377e0

File tree

5 files changed

+34
-27
lines changed

5 files changed

+34
-27
lines changed

src/backend/commands/tablecmds.c

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3391,8 +3391,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
33913391
*/
33923392
if (newrel)
33933393
find_composite_type_dependencies(oldrel->rd_rel->reltype,
3394-
RelationGetRelationName(oldrel),
3395-
NULL);
3394+
oldrel->rd_rel->relkind,
3395+
RelationGetRelationName(oldrel));
33963396

33973397
/*
33983398
* Generate the constraint and default execution states
@@ -3860,9 +3860,8 @@ ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
38603860
* to reject the ALTER. (How safe is this really?)
38613861
*/
38623862
void
3863-
find_composite_type_dependencies(Oid typeOid,
3864-
const char *origTblName,
3865-
const char *origTypeName)
3863+
find_composite_type_dependencies(Oid typeOid, char origRelkind,
3864+
const char *origRelname)
38663865
{
38673866
Relation depRel;
38683867
ScanKeyData key[2];
@@ -3905,20 +3904,19 @@ find_composite_type_dependencies(Oid typeOid,
39053904

39063905
if (rel->rd_rel->relkind == RELKIND_RELATION)
39073906
{
3908-
if (origTblName)
3909-
ereport(ERROR,
3910-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3911-
errmsg("cannot alter table \"%s\" because column \"%s\".\"%s\" uses its rowtype",
3912-
origTblName,
3913-
RelationGetRelationName(rel),
3914-
NameStr(att->attname))));
3907+
const char *msg;
3908+
if (origRelkind == RELKIND_COMPOSITE_TYPE)
3909+
msg = gettext_noop("cannot alter type \"%s\" because column \"%s\".\"%s\" uses it");
3910+
else if (origRelkind == RELKIND_FOREIGN_TABLE)
3911+
msg = gettext_noop("cannot alter foreign table \"%s\" because column \"%s\".\"%s\" uses its rowtype");
39153912
else
3916-
ereport(ERROR,
3917-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3918-
errmsg("cannot alter type \"%s\" because column \"%s\".\"%s\" uses it",
3919-
origTypeName,
3920-
RelationGetRelationName(rel),
3921-
NameStr(att->attname))));
3913+
msg = gettext_noop("cannot alter table \"%s\" because column \"%s\".\"%s\" uses its rowtype");
3914+
ereport(ERROR,
3915+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3916+
errmsg(msg,
3917+
origRelname,
3918+
RelationGetRelationName(rel),
3919+
NameStr(att->attname))));
39223920
}
39233921
else if (OidIsValid(rel->rd_rel->reltype))
39243922
{
@@ -3927,7 +3925,7 @@ find_composite_type_dependencies(Oid typeOid,
39273925
* recursively check for indirect dependencies via its rowtype.
39283926
*/
39293927
find_composite_type_dependencies(rel->rd_rel->reltype,
3930-
origTblName, origTypeName);
3928+
origRelkind, origRelname);
39313929
}
39323930

39333931
relation_close(rel, AccessShareLock);
@@ -3943,7 +3941,7 @@ find_composite_type_dependencies(Oid typeOid,
39433941
*/
39443942
arrayOid = get_array_type(typeOid);
39453943
if (OidIsValid(arrayOid))
3946-
find_composite_type_dependencies(arrayOid, origTblName, origTypeName);
3944+
find_composite_type_dependencies(arrayOid, origRelkind, origRelname);
39473945
}
39483946

39493947

@@ -6444,14 +6442,15 @@ ATPrepAlterColumnType(List **wqueue,
64446442
errmsg("ALTER TYPE USING is not supported on foreign tables")));
64456443
}
64466444

6447-
if (tab->relkind == RELKIND_COMPOSITE_TYPE)
6445+
if (tab->relkind == RELKIND_COMPOSITE_TYPE
6446+
|| tab->relkind == RELKIND_FOREIGN_TABLE)
64486447
{
64496448
/*
64506449
* For composite types, do this check now. Tables will check
64516450
* it later when the table is being rewritten.
64526451
*/
64536452
find_composite_type_dependencies(rel->rd_rel->reltype,
6454-
NULL,
6453+
rel->rd_rel->relkind,
64556454
RelationGetRelationName(rel));
64566455
}
64576456

src/backend/commands/typecmds.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2183,7 +2183,7 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
21832183
*/
21842184
if (OidIsValid(rel->rd_rel->reltype))
21852185
find_composite_type_dependencies(rel->rd_rel->reltype,
2186-
NULL,
2186+
RELKIND_COMPOSITE_TYPE,
21872187
format_type_be(domainOid));
21882188

21892189
/* Otherwise we can ignore views, composite types, etc */

src/include/commands/tablecmds.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ extern void RenameRelationInternal(Oid myrelid,
5353
Oid namespaceId);
5454

5555
extern void find_composite_type_dependencies(Oid typeOid,
56-
const char *origTblName,
57-
const char *origTypeName);
56+
char origRelkind, const char *origRelname);
5857

5958
extern AttrNumber *varattnos_map(TupleDesc olddesc, TupleDesc newdesc);
6059
extern AttrNumber *varattnos_map_schema(TupleDesc old, List *schema);

src/test/regress/expected/foreign_data.out

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,12 @@ ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) using '0'; -- ERROR
692692
ERROR: ALTER TYPE USING is not supported on foreign tables
693693
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
694694
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE text;
695-
ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c9_check CHECK (c9 < 0);
695+
-- can't change the column type if it's used elsewhere
696+
CREATE TABLE use_ft1_column_type (x ft1);
697+
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE integer; -- ERROR
698+
ERROR: cannot alter foreign table "ft1" because column "use_ft1_column_type"."x" uses its rowtype
699+
DROP TABLE use_ft1_column_type;
700+
ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c9_check CHECK (c9 < 0); -- ERROR
696701
ERROR: "ft1" is not a table
697702
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT no_const; -- ERROR
698703
ERROR: "ft1" is not a table

src/test/regress/sql/foreign_data.sql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,11 @@ ALTER FOREIGN TABLE ft1 ALTER COLUMN c7 DROP NOT NULL;
293293
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10) using '0'; -- ERROR
294294
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
295295
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE text;
296-
ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c9_check CHECK (c9 < 0);
296+
-- can't change the column type if it's used elsewhere
297+
CREATE TABLE use_ft1_column_type (x ft1);
298+
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET DATA TYPE integer; -- ERROR
299+
DROP TABLE use_ft1_column_type;
300+
ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c9_check CHECK (c9 < 0); -- ERROR
297301
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT no_const; -- ERROR
298302
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT IF EXISTS no_const;
299303
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c1_check;

0 commit comments

Comments
 (0)