Commit f285d958 authored by Tom Lane's avatar Tom Lane

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
parent 9ae0a4c7
...@@ -11714,12 +11714,11 @@ ATPrepAlterColumnType(List **wqueue, ...@@ -11714,12 +11714,11 @@ ATPrepAlterColumnType(List **wqueue,
errmsg("\"%s\" is not a table", errmsg("\"%s\" is not a table",
RelationGetRelationName(rel)))); RelationGetRelationName(rel))));
if (tab->relkind == RELKIND_COMPOSITE_TYPE || if (!RELKIND_HAS_STORAGE(tab->relkind))
tab->relkind == RELKIND_FOREIGN_TABLE)
{ {
/* /*
* For composite types and foreign tables, do this check now. Regular * For relations without storage, do this check now. Regular tables
* tables will check it later when the table is being rewritten. * will check it later when the table is being rewritten.
*/ */
find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL); find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
} }
......
...@@ -2063,11 +2063,24 @@ begin; ...@@ -2063,11 +2063,24 @@ begin;
create table skip_wal_skip_rewrite_index (c varchar(10) primary key); create table skip_wal_skip_rewrite_index (c varchar(10) primary key);
alter table skip_wal_skip_rewrite_index alter c type varchar(20); alter table skip_wal_skip_rewrite_index alter c type varchar(20);
commit; commit;
-- table's row type -- We disallow changing table's row type if it's used for storage
create table tab1 (a int, b text); create table at_tab1 (a int, b text);
create table tab2 (x int, y tab1); create table at_tab2 (x int, y at_tab1);
alter table tab1 alter column b type varchar; -- fails alter table at_tab1 alter column b type varchar; -- fails
ERROR: cannot alter table "tab1" because column "tab2.y" uses its row type 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 -- 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_partitioned (a int, b text) partition by range (a);
create table at_part_1 partition of at_partitioned for values from (0) to (1000); create table at_part_1 partition of at_partitioned for values from (0) to (1000);
......
...@@ -1424,10 +1424,21 @@ create table skip_wal_skip_rewrite_index (c varchar(10) primary key); ...@@ -1424,10 +1424,21 @@ create table skip_wal_skip_rewrite_index (c varchar(10) primary key);
alter table skip_wal_skip_rewrite_index alter c type varchar(20); alter table skip_wal_skip_rewrite_index alter c type varchar(20);
commit; commit;
-- table's row type -- We disallow changing table's row type if it's used for storage
create table tab1 (a int, b text); create table at_tab1 (a int, b text);
create table tab2 (x int, y tab1); create table at_tab2 (x int, y at_tab1);
alter table tab1 alter column b type varchar; -- fails 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 -- 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_partitioned (a int, b text) partition by range (a);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment