]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Prevent altering partitioned table's rowtype, if it's used elsewhere.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 6 Jan 2022 21:46:46 +0000 (16:46 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 6 Jan 2022 21:46:46 +0000 (16:46 -0500)
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

src/backend/commands/tablecmds.c
src/test/regress/expected/alter_table.out
src/test/regress/sql/alter_table.sql

index 851432ab257b795120afd6814c66b5c534f00187..f7c590799461496895d07a1c218ead1212c23413 100644 (file)
@@ -9878,11 +9878,13 @@ 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 ||
+               tab->relkind == RELKIND_PARTITIONED_INDEX)
        {
                /*
-                * 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);
        }
index 298d9c81ee0e0b238c85c1e4097ac34cff2487fd..ba2e80a3b94926296e1d7863705915d2178d8730 100644 (file)
@@ -2093,11 +2093,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;
 -- Alter column type that's part of a partitioned index
 create table at_partitioned (a int, b text) partition by range (a);
 create table at_part_1 partition of at_partitioned for values from (0) to (1000);
index 20713bd0c6e1d246908eac5aaaed970dcc1bdcfb..6b3f7d88baed44f74482a77eb9577a159ba900c3 100644 (file)
@@ -1420,10 +1420,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;
 
 -- Alter column type that's part of a partitioned index
 create table at_partitioned (a int, b text) partition by range (a);