postgres.git / summary / log / commit / refs

commit    8aad248f7c67f1225027414530ce2809c1fcd104
Author:   Michael Paquier <michael@paquier.xyz>
Date:     Mon Nov 05 02:04:20 2018 +0000

    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


src/backend/commands/tablecmds.c | 8 ++++++++ src/test/regress/expected/alter_table.out | 18 ++++++++++++++++++ src/test/regress/expected/create_table.out | 16 ++++++++++++++++ src/test/regress/sql/alter_table.sql | 16 ++++++++++++++++ src/test/regress/sql/create_table.sql | 14 ++++++++++++++ 5 files changed, 72 insertions(+) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 7557b49dd82..971a8721e1c 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1750,6 +1750,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. diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index bd3f918e482..70e140039ac 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3669,6 +3669,24 @@ alter table temp_part_parent attach partition temp_part_child for values in (1, 2); -- 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 diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 660398bdbe0..481510c2bb1 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -830,3 +830,19 @@ ERROR: cannot create a temporary relation as partition of permanent relation "p create temp table temp_part partition of temp_parted for values in (1, 2); -- 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(); diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 24b60f9b6e2..e79b402a322 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2389,6 +2389,22 @@ alter table temp_part_parent attach partition temp_part_child 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 diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql index 16f2edb897b..bc6191f4ace 100644 --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@ -679,3 +679,17 @@ create temp table temp_part partition of perm_parted for values in (1, 2); -- er create temp table temp_part partition of temp_parted for values in (1, 2); -- 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(); [parent: 70c38e708012]