Skip to content

Commit ccc7c3a

Browse files
committed
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
1 parent ada0e91 commit ccc7c3a

File tree

3 files changed

+36
-13
lines changed

3 files changed

+36
-13
lines changed

src/backend/commands/tablecmds.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10852,12 +10852,11 @@ ATPrepAlterColumnType(List **wqueue,
1085210852
errmsg("\"%s\" is not a table",
1085310853
RelationGetRelationName(rel))));
1085410854

10855-
if (tab->relkind == RELKIND_COMPOSITE_TYPE ||
10856-
tab->relkind == RELKIND_FOREIGN_TABLE)
10855+
if (!RELKIND_HAS_STORAGE(tab->relkind))
1085710856
{
1085810857
/*
10859-
* For composite types, do this check now. Tables will check it later
10860-
* when the table is being rewritten.
10858+
* For relations without storage, do this check now. Regular tables
10859+
* will check it later when the table is being rewritten.
1086110860
*/
1086210861
find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
1086310862
}

src/test/regress/expected/alter_table.out

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2050,11 +2050,24 @@ select * from another;
20502050
(3 rows)
20512051

20522052
drop table another;
2053-
-- table's row type
2054-
create table tab1 (a int, b text);
2055-
create table tab2 (x int, y tab1);
2056-
alter table tab1 alter column b type varchar; -- fails
2057-
ERROR: cannot alter table "tab1" because column "tab2.y" uses its row type
2053+
-- We disallow changing table's row type if it's used for storage
2054+
create table at_tab1 (a int, b text);
2055+
create table at_tab2 (x int, y at_tab1);
2056+
alter table at_tab1 alter column b type varchar; -- fails
2057+
ERROR: cannot alter table "at_tab1" because column "at_tab2.y" uses its row type
2058+
drop table at_tab2;
2059+
-- Use of row type in an expression is defended differently
2060+
create table at_tab2 (x int, y text, check((x,y)::at_tab1 = (1,'42')::at_tab1));
2061+
alter table at_tab1 alter column b type varchar; -- allowed, but ...
2062+
insert into at_tab2 values(1,'42'); -- ... this will fail
2063+
ERROR: ROW() column has type text instead of type character varying
2064+
drop table at_tab1, at_tab2;
2065+
-- Check it for a partitioned table, too
2066+
create table at_tab1 (a int, b text) partition by list(a);
2067+
create table at_tab2 (x int, y at_tab1);
2068+
alter table at_tab1 alter column b type varchar; -- fails
2069+
ERROR: cannot alter table "at_tab1" because column "at_tab2.y" uses its row type
2070+
drop table at_tab1, at_tab2;
20582071
-- Alter column type that's part of a partitioned index
20592072
create table at_partitioned (a int, b text) partition by range (a);
20602073
create table at_part_1 partition of at_partitioned for values from (0) to (1000);

src/test/regress/sql/alter_table.sql

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,10 +1411,21 @@ select * from another;
14111411

14121412
drop table another;
14131413

1414-
-- table's row type
1415-
create table tab1 (a int, b text);
1416-
create table tab2 (x int, y tab1);
1417-
alter table tab1 alter column b type varchar; -- fails
1414+
-- We disallow changing table's row type if it's used for storage
1415+
create table at_tab1 (a int, b text);
1416+
create table at_tab2 (x int, y at_tab1);
1417+
alter table at_tab1 alter column b type varchar; -- fails
1418+
drop table at_tab2;
1419+
-- Use of row type in an expression is defended differently
1420+
create table at_tab2 (x int, y text, check((x,y)::at_tab1 = (1,'42')::at_tab1));
1421+
alter table at_tab1 alter column b type varchar; -- allowed, but ...
1422+
insert into at_tab2 values(1,'42'); -- ... this will fail
1423+
drop table at_tab1, at_tab2;
1424+
-- Check it for a partitioned table, too
1425+
create table at_tab1 (a int, b text) partition by list(a);
1426+
create table at_tab2 (x int, y at_tab1);
1427+
alter table at_tab1 alter column b type varchar; -- fails
1428+
drop table at_tab1, at_tab2;
14181429

14191430
-- Alter column type that's part of a partitioned index
14201431
create table at_partitioned (a int, b text) partition by range (a);

0 commit comments

Comments
 (0)