aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Paquier <michael@paquier.xyz>2018-11-05 11:04:20 +0900
committerMichael Paquier <michael@paquier.xyz>2018-11-05 11:04:20 +0900
commit8aad248f7c67f1225027414530ce2809c1fcd104 (patch)
tree3fcd42dd091be1833bacedcc95d87b46015da55d
parent70c38e7080128e27cb6b9e20237f2c36807b0000 (diff)
downloadpostgresql-8aad248f7c67f1225027414530ce2809c1fcd104.tar.gz
postgresql-8aad248f7c67f1225027414530ce2809c1fcd104.zip
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
-rw-r--r--src/backend/commands/tablecmds.c8
-rw-r--r--src/test/regress/expected/alter_table.out18
-rw-r--r--src/test/regress/expected/create_table.out16
-rw-r--r--src/test/regress/sql/alter_table.sql16
-rw-r--r--src/test/regress/sql/create_table.sql14
5 files changed, 72 insertions, 0 deletions
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
@@ -1751,6 +1751,14 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
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();