Skip to content

Commit 7ead992

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 328dfbd commit 7ead992

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
@@ -12183,12 +12183,11 @@ ATPrepAlterColumnType(List **wqueue,
1218312183
errmsg("\"%s\" is not a table",
1218412184
RelationGetRelationName(rel))));
1218512185

12186-
if (tab->relkind == RELKIND_COMPOSITE_TYPE ||
12187-
tab->relkind == RELKIND_FOREIGN_TABLE)
12186+
if (!RELKIND_HAS_STORAGE(tab->relkind))
1218812187
{
1218912188
/*
12190-
* For composite types and foreign tables, do this check now. Regular
12191-
* tables will check it later when the table is being rewritten.
12189+
* For relations without storage, do this check now. Regular tables
12190+
* will check it later when the table is being rewritten.
1219212191
*/
1219312192
find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
1219412193
}

src/test/regress/expected/alter_table.out

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

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

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

0 commit comments

Comments
 (0)