check-table-not-used-when-create-partition-of-3.patch

text/plain

Filename: check-table-not-used-when-create-partition-of-3.patch
Type: text/plain
Part: 0
Message: Re: BUG #15437: Segfault during insert into declarative partitioned table with a trigger creating partition

Patch

Format: unified
File+
src/backend/commands/tablecmds.c 8 0
src/test/regress/expected/alter_table.out 14 0
src/test/regress/expected/create_table.out 13 0
src/test/regress/sql/alter_table.sql 12 0
src/test/regress/sql/create_table.sql 11 0
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;