Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7c222d5

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 948af52 commit 7c222d5

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
@@ -1963,6 +1963,14 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
19631963
else
19641964
relation = heap_openrv(parent, AccessExclusiveLock);
19651965

1966+
/*
1967+
* Check for active uses of the parent partitioned table in the
1968+
* current transaction, such as being used in some manner by an
1969+
* enclosing command.
1970+
*/
1971+
if (is_partition)
1972+
CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
1973+
19661974
/*
19671975
* We do not allow partitioned tables and partitions to participate in
19681976
* regular inheritance.

src/test/regress/expected/alter_table.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3960,6 +3960,24 @@ ERROR: cannot attach a temporary relation as partition of permanent relation "p
39603960
alter table temp_part_parent attach partition temp_part_child default; -- ok
39613961
drop table perm_part_parent cascade;
39623962
drop table temp_part_parent cascade;
3963+
-- check that attaching partitions to a table while it is being used is
3964+
-- prevented
3965+
create table tab_part_attach (a int) partition by list (a);
3966+
create or replace function func_part_attach() returns trigger
3967+
language plpgsql as $$
3968+
begin
3969+
execute 'create table tab_part_attach_1 (a int)';
3970+
execute 'alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)';
3971+
return null;
3972+
end $$;
3973+
create trigger trig_part_attach before insert on tab_part_attach
3974+
for each statement execute procedure func_part_attach();
3975+
insert into tab_part_attach values (1);
3976+
ERROR: cannot ALTER TABLE "tab_part_attach" because it is being used by active queries in this session
3977+
CONTEXT: SQL statement "alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)"
3978+
PL/pgSQL function func_part_attach() line 4 at EXECUTE
3979+
drop table tab_part_attach;
3980+
drop function func_part_attach();
39633981
-- test case where the partitioning operator is a SQL function whose
39643982
-- evaluation results in the table's relcache being rebuilt partway through
39653983
-- 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
@@ -904,3 +904,19 @@ ERROR: cannot create a temporary relation as partition of permanent relation "p
904904
create temp table temp_part partition of temp_parted default; -- ok
905905
drop table perm_parted cascade;
906906
drop table temp_parted cascade;
907+
-- check that adding partitions to a table while it is being used is prevented
908+
create table tab_part_create (a int) partition by list (a);
909+
create or replace function func_part_create() returns trigger
910+
language plpgsql as $$
911+
begin
912+
execute 'create table tab_part_create_1 partition of tab_part_create for values in (1)';
913+
return null;
914+
end $$;
915+
create trigger trig_part_create before insert on tab_part_create
916+
for each statement execute procedure func_part_create();
917+
insert into tab_part_create values (1);
918+
ERROR: cannot CREATE TABLE .. PARTITION OF "tab_part_create" because it is being used by active queries in this session
919+
CONTEXT: SQL statement "create table tab_part_create_1 partition of tab_part_create for values in (1)"
920+
PL/pgSQL function func_part_create() line 3 at EXECUTE
921+
drop table tab_part_create;
922+
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
@@ -2619,6 +2619,22 @@ alter table temp_part_parent attach partition temp_part_child default; -- ok
26192619
drop table perm_part_parent cascade;
26202620
drop table temp_part_parent cascade;
26212621

2622+
-- check that attaching partitions to a table while it is being used is
2623+
-- prevented
2624+
create table tab_part_attach (a int) partition by list (a);
2625+
create or replace function func_part_attach() returns trigger
2626+
language plpgsql as $$
2627+
begin
2628+
execute 'create table tab_part_attach_1 (a int)';
2629+
execute 'alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)';
2630+
return null;
2631+
end $$;
2632+
create trigger trig_part_attach before insert on tab_part_attach
2633+
for each statement execute procedure func_part_attach();
2634+
insert into tab_part_attach values (1);
2635+
drop table tab_part_attach;
2636+
drop function func_part_attach();
2637+
26222638
-- test case where the partitioning operator is a SQL function whose
26232639
-- evaluation results in the table's relcache being rebuilt partway through
26242640
-- 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
@@ -730,3 +730,17 @@ create temp table temp_part partition of perm_parted default; -- error
730730
create temp table temp_part partition of temp_parted default; -- ok
731731
drop table perm_parted cascade;
732732
drop table temp_parted cascade;
733+
734+
-- check that adding partitions to a table while it is being used is prevented
735+
create table tab_part_create (a int) partition by list (a);
736+
create or replace function func_part_create() returns trigger
737+
language plpgsql as $$
738+
begin
739+
execute 'create table tab_part_create_1 partition of tab_part_create for values in (1)';
740+
return null;
741+
end $$;
742+
create trigger trig_part_create before insert on tab_part_create
743+
for each statement execute procedure func_part_create();
744+
insert into tab_part_create values (1);
745+
drop table tab_part_create;
746+
drop function func_part_create();

0 commit comments

Comments
 (0)