diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 153aec263e..3b6d672d75 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1993,6 +1993,14 @@ MergeAttributes(List *schema, List *supers, char relpersistence, relation = heap_openrv(parent, AccessExclusiveLock); /* + * Check for active uses of the parent paritioned table in the current + * transaction, such as being used in some manner by an enclosing + * command, like by insert's tuple routing. + */ + 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 68cd3e5676..5c94400e74 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3954,6 +3954,20 @@ 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 adding partitions to a table while it is being used is prevented +create table check_not_in_use (a int) partition by list (a); +create or replace function add_part_func () returns trigger language plpgsql as $$ + begin + execute 'create table check_not_in_use1 (a int)'; + execute 'alter table check_not_in_use attach partition check_not_in_use1 default'; + end $$; +create trigger add_part_trig before insert on check_not_in_use + for each statement execute procedure add_part_func(); +insert into check_not_in_use values (1); +ERROR: cannot ALTER TABLE "check_not_in_use" because it is being used by active queries in this session +CONTEXT: SQL statement "alter table check_not_in_use attach partition check_not_in_use1 default" +PL/pgSQL function add_part_func() line 4 at EXECUTE +drop table check_not_in_use; -- 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 744b9990a6..ebdd875356 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -910,3 +910,16 @@ 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 check_not_in_use (a int) partition by list (a); +create function add_part_func () returns trigger language plpgsql as $$ + begin + execute 'create table check_not_in_use1 partition of check_not_in_use default'; + end $$; +create trigger add_part_trig before insert on check_not_in_use + for each statement execute procedure add_part_func(); +insert into check_not_in_use values (1); +ERROR: cannot CREATE TABLE .. PARTITION OF "check_not_in_use" because it is being used by active queries in this session +CONTEXT: SQL statement "create table check_not_in_use1 partition of check_not_in_use default" +PL/pgSQL function add_part_func() line 3 at EXECUTE +drop table check_not_in_use; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 6890346637..3d6c9b4599 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2607,6 +2607,18 @@ 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 adding partitions to a table while it is being used is prevented +create table check_not_in_use (a int) partition by list (a); +create or replace function add_part_func () returns trigger language plpgsql as $$ + begin + execute 'create table check_not_in_use1 (a int)'; + execute 'alter table check_not_in_use attach partition check_not_in_use1 default'; + end $$; +create trigger add_part_trig before insert on check_not_in_use + for each statement execute procedure add_part_func(); +insert into check_not_in_use values (1); +drop table check_not_in_use; + -- 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 81fa7658b0..a34dd8f0e7 100644 --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@ -730,3 +730,14 @@ 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 check_not_in_use (a int) partition by list (a); +create function add_part_func () returns trigger language plpgsql as $$ + begin + execute 'create table check_not_in_use1 partition of check_not_in_use default'; + end $$; +create trigger add_part_trig before insert on check_not_in_use + for each statement execute procedure add_part_func(); +insert into check_not_in_use values (1); +drop table check_not_in_use;