summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2022-01-06 16:46:46 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2022-01-06 16:46:46 -0500
commite5b044c84e8a8c0a3bfca66a245b08316532110c (patch)
tree2ae237c63e1b3d16d6ad00db081cfd23ba57a4dc /src
parent4a8282425f6b6db19a07dcb634b5a670d0289c95 (diff)
Prevent altering partitioned table's rowtype, if it's used elsewhere.
We disallow altering a column datatype within a regular table, if the table's rowtype is used as a column type elsewhere, because we lack code to go around and rewrite the other tables. This restriction should apply to partitioned tables as well, but it was not checked because ATRewriteTables and ATPrepAlterColumnType were not on the same page about who should do it for which relkinds. Per bug #17351 from Alexander Lakhin. Back-patch to all supported branches. Discussion: https://postgr.es/m/17351-6db1870f3f4f612a@postgresql.org
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/tablecmds.c7
-rw-r--r--src/test/regress/expected/alter_table.out23
-rw-r--r--src/test/regress/sql/alter_table.sql19
3 files changed, 37 insertions, 12 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index ef88a10f017..b0a7e3221f1 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8847,11 +8847,12 @@ ATPrepAlterColumnType(List **wqueue,
RelationGetRelationName(rel))));
if (tab->relkind == RELKIND_COMPOSITE_TYPE ||
- tab->relkind == RELKIND_FOREIGN_TABLE)
+ tab->relkind == RELKIND_FOREIGN_TABLE ||
+ tab->relkind == RELKIND_PARTITIONED_TABLE)
{
/*
- * For composite types, do this check now. Tables will check it later
- * when the table is being rewritten.
+ * For relations without storage, do this check now. Regular tables
+ * will check it later when the table is being rewritten.
*/
find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
}
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index c22ae567549..d5667160894 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -2036,11 +2036,24 @@ select * from another;
(3 rows)
drop table another;
--- table's row type
-create table tab1 (a int, b text);
-create table tab2 (x int, y tab1);
-alter table tab1 alter column b type varchar; -- fails
-ERROR: cannot alter table "tab1" because column "tab2.y" uses its row type
+-- We disallow changing table's row type if it's used for storage
+create table at_tab1 (a int, b text);
+create table at_tab2 (x int, y at_tab1);
+alter table at_tab1 alter column b type varchar; -- fails
+ERROR: cannot alter table "at_tab1" because column "at_tab2.y" uses its row type
+drop table at_tab2;
+-- Use of row type in an expression is defended differently
+create table at_tab2 (x int, y text, check((x,y)::at_tab1 = (1,'42')::at_tab1));
+alter table at_tab1 alter column b type varchar; -- allowed, but ...
+insert into at_tab2 values(1,'42'); -- ... this will fail
+ERROR: ROW() column has type text instead of type character varying
+drop table at_tab1, at_tab2;
+-- Check it for a partitioned table, too
+create table at_tab1 (a int, b text) partition by list(a);
+create table at_tab2 (x int, y at_tab1);
+alter table at_tab1 alter column b type varchar; -- fails
+ERROR: cannot alter table "at_tab1" because column "at_tab2.y" uses its row type
+drop table at_tab1, at_tab2;
-- disallow recursive containment of row types
create temp table recur1 (f1 int);
alter table recur1 add column f2 recur1; -- fails
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 67c7fa131ef..4968b1f7a35 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -1370,10 +1370,21 @@ select * from another;
drop table another;
--- table's row type
-create table tab1 (a int, b text);
-create table tab2 (x int, y tab1);
-alter table tab1 alter column b type varchar; -- fails
+-- We disallow changing table's row type if it's used for storage
+create table at_tab1 (a int, b text);
+create table at_tab2 (x int, y at_tab1);
+alter table at_tab1 alter column b type varchar; -- fails
+drop table at_tab2;
+-- Use of row type in an expression is defended differently
+create table at_tab2 (x int, y text, check((x,y)::at_tab1 = (1,'42')::at_tab1));
+alter table at_tab1 alter column b type varchar; -- allowed, but ...
+insert into at_tab2 values(1,'42'); -- ... this will fail
+drop table at_tab1, at_tab2;
+-- Check it for a partitioned table, too
+create table at_tab1 (a int, b text) partition by list(a);
+create table at_tab2 (x int, y at_tab1);
+alter table at_tab1 alter column b type varchar; -- fails
+drop table at_tab1, at_tab2;
-- disallow recursive containment of row types
create temp table recur1 (f1 int);