Skip to content

Commit f285d95

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 9ae0a4c commit f285d95

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
@@ -11714,12 +11714,11 @@ ATPrepAlterColumnType(List **wqueue,
1171411714
errmsg("\"%s\" is not a table",
1171511715
RelationGetRelationName(rel))));
1171611716

11717-
if (tab->relkind == RELKIND_COMPOSITE_TYPE ||
11718-
tab->relkind == RELKIND_FOREIGN_TABLE)
11717+
if (!RELKIND_HAS_STORAGE(tab->relkind))
1171911718
{
1172011719
/*
11721-
* For composite types and foreign tables, do this check now. Regular
11722-
* tables will check it later when the table is being rewritten.
11720+
* For relations without storage, do this check now. Regular tables
11721+
* will check it later when the table is being rewritten.
1172311722
*/
1172411723
find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
1172511724
}

src/test/regress/expected/alter_table.out

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2063,11 +2063,24 @@ begin;
20632063
create table skip_wal_skip_rewrite_index (c varchar(10) primary key);
20642064
alter table skip_wal_skip_rewrite_index alter c type varchar(20);
20652065
commit;
2066-
-- table's row type
2067-
create table tab1 (a int, b text);
2068-
create table tab2 (x int, y tab1);
2069-
alter table tab1 alter column b type varchar; -- fails
2070-
ERROR: cannot alter table "tab1" because column "tab2.y" uses its row type
2066+
-- We disallow changing table's row type if it's used for storage
2067+
create table at_tab1 (a int, b text);
2068+
create table at_tab2 (x int, y at_tab1);
2069+
alter table at_tab1 alter column b type varchar; -- fails
2070+
ERROR: cannot alter table "at_tab1" because column "at_tab2.y" uses its row type
2071+
drop table at_tab2;
2072+
-- Use of row type in an expression is defended differently
2073+
create table at_tab2 (x int, y text, check((x,y)::at_tab1 = (1,'42')::at_tab1));
2074+
alter table at_tab1 alter column b type varchar; -- allowed, but ...
2075+
insert into at_tab2 values(1,'42'); -- ... this will fail
2076+
ERROR: ROW() column has type text instead of type character varying
2077+
drop table at_tab1, at_tab2;
2078+
-- Check it for a partitioned table, too
2079+
create table at_tab1 (a int, b text) partition by list(a);
2080+
create table at_tab2 (x int, y at_tab1);
2081+
alter table at_tab1 alter column b type varchar; -- fails
2082+
ERROR: cannot alter table "at_tab1" because column "at_tab2.y" uses its row type
2083+
drop table at_tab1, at_tab2;
20712084
-- Alter column type that's part of a partitioned index
20722085
create table at_partitioned (a int, b text) partition by range (a);
20732086
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
@@ -1424,10 +1424,21 @@ create table skip_wal_skip_rewrite_index (c varchar(10) primary key);
14241424
alter table skip_wal_skip_rewrite_index alter c type varchar(20);
14251425
commit;
14261426

1427-
-- table's row type
1428-
create table tab1 (a int, b text);
1429-
create table tab2 (x int, y tab1);
1430-
alter table tab1 alter column b type varchar; -- fails
1427+
-- We disallow changing table's row type if it's used for storage
1428+
create table at_tab1 (a int, b text);
1429+
create table at_tab2 (x int, y at_tab1);
1430+
alter table at_tab1 alter column b type varchar; -- fails
1431+
drop table at_tab2;
1432+
-- Use of row type in an expression is defended differently
1433+
create table at_tab2 (x int, y text, check((x,y)::at_tab1 = (1,'42')::at_tab1));
1434+
alter table at_tab1 alter column b type varchar; -- allowed, but ...
1435+
insert into at_tab2 values(1,'42'); -- ... this will fail
1436+
drop table at_tab1, at_tab2;
1437+
-- Check it for a partitioned table, too
1438+
create table at_tab1 (a int, b text) partition by list(a);
1439+
create table at_tab2 (x int, y at_tab1);
1440+
alter table at_tab1 alter column b type varchar; -- fails
1441+
drop table at_tab1, at_tab2;
14311442

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

0 commit comments

Comments
 (0)