Skip to content

Commit 8aad248

Browse files
committed
Block creation of partitions with open references to its parent
When a partition is created as part of a trigger processing, it is possible that the partition which just gets created changes the properties of the table the executor of the ongoing command relies on, causing a subsequent crash. This has been found possible when for example using a BEFORE INSERT which creates a new partition for a partitioned table being inserted to. Any attempt to do so is blocked when working on a partition, with regression tests added for both CREATE TABLE PARTITION OF and ALTER TABLE ATTACH PARTITION. Reported-by: Dmitry Shalashov Author: Amit Langote Reviewed-by: Michael Paquier, Tom Lane Discussion: https://postgr.es/m/15437-3fe01ee66bd1bae1@postgresql.org Backpatch-through: 10
1 parent 70c38e7 commit 8aad248

File tree

5 files changed

+72
-0
lines changed

5 files changed

+72
-0
lines changed

src/backend/commands/tablecmds.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,6 +1750,14 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
17501750
else
17511751
relation = heap_openrv(parent, AccessExclusiveLock);
17521752

1753+
/*
1754+
* Check for active uses of the parent partitioned table in the
1755+
* current transaction, such as being used in some manner by an
1756+
* enclosing command.
1757+
*/
1758+
if (is_partition)
1759+
CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
1760+
17531761
/*
17541762
* We do not allow partitioned tables and partitions to participate in
17551763
* regular inheritance.

src/test/regress/expected/alter_table.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3669,6 +3669,24 @@ alter table temp_part_parent attach partition temp_part_child
36693669
for values in (1, 2); -- ok
36703670
drop table perm_part_parent cascade;
36713671
drop table temp_part_parent cascade;
3672+
-- check that attaching partitions to a table while it is being used is
3673+
-- prevented
3674+
create table tab_part_attach (a int) partition by list (a);
3675+
create or replace function func_part_attach() returns trigger
3676+
language plpgsql as $$
3677+
begin
3678+
execute 'create table tab_part_attach_1 (a int)';
3679+
execute 'alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)';
3680+
return null;
3681+
end $$;
3682+
create trigger trig_part_attach before insert on tab_part_attach
3683+
for each statement execute procedure func_part_attach();
3684+
insert into tab_part_attach values (1);
3685+
ERROR: cannot ALTER TABLE "tab_part_attach" because it is being used by active queries in this session
3686+
CONTEXT: SQL statement "alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)"
3687+
PL/pgSQL function func_part_attach() line 4 at EXECUTE
3688+
drop table tab_part_attach;
3689+
drop function func_part_attach();
36723690
-- test case where the partitioning operator is a SQL function whose
36733691
-- evaluation results in the table's relcache being rebuilt partway through
36743692
-- the execution of an ATTACH PARTITION command

src/test/regress/expected/create_table.out

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,3 +830,19 @@ ERROR: cannot create a temporary relation as partition of permanent relation "p
830830
create temp table temp_part partition of temp_parted for values in (1, 2); -- ok
831831
drop table perm_parted cascade;
832832
drop table temp_parted cascade;
833+
-- check that adding partitions to a table while it is being used is prevented
834+
create table tab_part_create (a int) partition by list (a);
835+
create or replace function func_part_create() returns trigger
836+
language plpgsql as $$
837+
begin
838+
execute 'create table tab_part_create_1 partition of tab_part_create for values in (1)';
839+
return null;
840+
end $$;
841+
create trigger trig_part_create before insert on tab_part_create
842+
for each statement execute procedure func_part_create();
843+
insert into tab_part_create values (1);
844+
ERROR: cannot CREATE TABLE .. PARTITION OF "tab_part_create" because it is being used by active queries in this session
845+
CONTEXT: SQL statement "create table tab_part_create_1 partition of tab_part_create for values in (1)"
846+
PL/pgSQL function func_part_create() line 3 at EXECUTE
847+
drop table tab_part_create;
848+
drop function func_part_create();

src/test/regress/sql/alter_table.sql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,6 +2389,22 @@ alter table temp_part_parent attach partition temp_part_child
23892389
drop table perm_part_parent cascade;
23902390
drop table temp_part_parent cascade;
23912391

2392+
-- check that attaching partitions to a table while it is being used is
2393+
-- prevented
2394+
create table tab_part_attach (a int) partition by list (a);
2395+
create or replace function func_part_attach() returns trigger
2396+
language plpgsql as $$
2397+
begin
2398+
execute 'create table tab_part_attach_1 (a int)';
2399+
execute 'alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)';
2400+
return null;
2401+
end $$;
2402+
create trigger trig_part_attach before insert on tab_part_attach
2403+
for each statement execute procedure func_part_attach();
2404+
insert into tab_part_attach values (1);
2405+
drop table tab_part_attach;
2406+
drop function func_part_attach();
2407+
23922408
-- test case where the partitioning operator is a SQL function whose
23932409
-- evaluation results in the table's relcache being rebuilt partway through
23942410
-- the execution of an ATTACH PARTITION command

src/test/regress/sql/create_table.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,3 +679,17 @@ create temp table temp_part partition of perm_parted for values in (1, 2); -- er
679679
create temp table temp_part partition of temp_parted for values in (1, 2); -- ok
680680
drop table perm_parted cascade;
681681
drop table temp_parted cascade;
682+
683+
-- check that adding partitions to a table while it is being used is prevented
684+
create table tab_part_create (a int) partition by list (a);
685+
create or replace function func_part_create() returns trigger
686+
language plpgsql as $$
687+
begin
688+
execute 'create table tab_part_create_1 partition of tab_part_create for values in (1)';
689+
return null;
690+
end $$;
691+
create trigger trig_part_create before insert on tab_part_create
692+
for each statement execute procedure func_part_create();
693+
insert into tab_part_create values (1);
694+
drop table tab_part_create;
695+
drop function func_part_create();

0 commit comments

Comments
 (0)