mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
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
This commit is contained in:
parent
4bc772e2af
commit
dc3e436b19
@ -1993,6 +1993,14 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
|
||||
else
|
||||
relation = heap_openrv(parent, AccessExclusiveLock);
|
||||
|
||||
/*
|
||||
* Check for active uses of the parent partitioned table in the
|
||||
* current transaction, such as being used in some manner by an
|
||||
* enclosing command.
|
||||
*/
|
||||
if (is_partition)
|
||||
CheckTableNotInUse(relation, "CREATE TABLE .. PARTITION OF");
|
||||
|
||||
/*
|
||||
* We do not allow partitioned tables and partitions to participate in
|
||||
* regular inheritance.
|
||||
|
@ -3954,6 +3954,24 @@ ERROR: cannot attach a temporary relation as partition of permanent relation "p
|
||||
alter table temp_part_parent attach partition temp_part_child default; -- ok
|
||||
drop table perm_part_parent cascade;
|
||||
drop table temp_part_parent cascade;
|
||||
-- check that attaching partitions to a table while it is being used is
|
||||
-- prevented
|
||||
create table tab_part_attach (a int) partition by list (a);
|
||||
create or replace function func_part_attach() returns trigger
|
||||
language plpgsql as $$
|
||||
begin
|
||||
execute 'create table tab_part_attach_1 (a int)';
|
||||
execute 'alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)';
|
||||
return null;
|
||||
end $$;
|
||||
create trigger trig_part_attach before insert on tab_part_attach
|
||||
for each statement execute procedure func_part_attach();
|
||||
insert into tab_part_attach values (1);
|
||||
ERROR: cannot ALTER TABLE "tab_part_attach" because it is being used by active queries in this session
|
||||
CONTEXT: SQL statement "alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)"
|
||||
PL/pgSQL function func_part_attach() line 4 at EXECUTE
|
||||
drop table tab_part_attach;
|
||||
drop function func_part_attach();
|
||||
-- test case where the partitioning operator is a SQL function whose
|
||||
-- evaluation results in the table's relcache being rebuilt partway through
|
||||
-- the execution of an ATTACH PARTITION command
|
||||
|
@ -910,3 +910,19 @@ ERROR: cannot create a temporary relation as partition of permanent relation "p
|
||||
create temp table temp_part partition of temp_parted default; -- ok
|
||||
drop table perm_parted cascade;
|
||||
drop table temp_parted cascade;
|
||||
-- check that adding partitions to a table while it is being used is prevented
|
||||
create table tab_part_create (a int) partition by list (a);
|
||||
create or replace function func_part_create() returns trigger
|
||||
language plpgsql as $$
|
||||
begin
|
||||
execute 'create table tab_part_create_1 partition of tab_part_create for values in (1)';
|
||||
return null;
|
||||
end $$;
|
||||
create trigger trig_part_create before insert on tab_part_create
|
||||
for each statement execute procedure func_part_create();
|
||||
insert into tab_part_create values (1);
|
||||
ERROR: cannot CREATE TABLE .. PARTITION OF "tab_part_create" because it is being used by active queries in this session
|
||||
CONTEXT: SQL statement "create table tab_part_create_1 partition of tab_part_create for values in (1)"
|
||||
PL/pgSQL function func_part_create() line 3 at EXECUTE
|
||||
drop table tab_part_create;
|
||||
drop function func_part_create();
|
||||
|
@ -2607,6 +2607,22 @@ alter table temp_part_parent attach partition temp_part_child default; -- ok
|
||||
drop table perm_part_parent cascade;
|
||||
drop table temp_part_parent cascade;
|
||||
|
||||
-- check that attaching partitions to a table while it is being used is
|
||||
-- prevented
|
||||
create table tab_part_attach (a int) partition by list (a);
|
||||
create or replace function func_part_attach() returns trigger
|
||||
language plpgsql as $$
|
||||
begin
|
||||
execute 'create table tab_part_attach_1 (a int)';
|
||||
execute 'alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)';
|
||||
return null;
|
||||
end $$;
|
||||
create trigger trig_part_attach before insert on tab_part_attach
|
||||
for each statement execute procedure func_part_attach();
|
||||
insert into tab_part_attach values (1);
|
||||
drop table tab_part_attach;
|
||||
drop function func_part_attach();
|
||||
|
||||
-- test case where the partitioning operator is a SQL function whose
|
||||
-- evaluation results in the table's relcache being rebuilt partway through
|
||||
-- the execution of an ATTACH PARTITION command
|
||||
|
@ -730,3 +730,17 @@ create temp table temp_part partition of perm_parted default; -- error
|
||||
create temp table temp_part partition of temp_parted default; -- ok
|
||||
drop table perm_parted cascade;
|
||||
drop table temp_parted cascade;
|
||||
|
||||
-- check that adding partitions to a table while it is being used is prevented
|
||||
create table tab_part_create (a int) partition by list (a);
|
||||
create or replace function func_part_create() returns trigger
|
||||
language plpgsql as $$
|
||||
begin
|
||||
execute 'create table tab_part_create_1 partition of tab_part_create for values in (1)';
|
||||
return null;
|
||||
end $$;
|
||||
create trigger trig_part_create before insert on tab_part_create
|
||||
for each statement execute procedure func_part_create();
|
||||
insert into tab_part_create values (1);
|
||||
drop table tab_part_create;
|
||||
drop function func_part_create();
|
||||
|
Loading…
Reference in New Issue
Block a user