提交 e3cf4f26 编写于 作者: A Adam Berlin 提交者: Adam Berlin

Do not modify a cached plan statement during ExecuteTruncate.

User defined functions cache their plan, therefore if we modify the
plan during execution, we risk having invalid data during the next
execution of the cached plan.

ExecuteTruncate modifies the plan's relations when declaring partitions
that need truncation.

Instead, we copy the list of relations that need truncation and add the
partition relations to the copy.
上级 0fe07f49
...@@ -1574,11 +1574,17 @@ ExecuteTruncate(TruncateStmt *stmt) ...@@ -1574,11 +1574,17 @@ ExecuteTruncate(TruncateStmt *stmt)
SubTransactionId mySubid; SubTransactionId mySubid;
ListCell *cell; ListCell *cell;
List *partList = NIL; List *partList = NIL;
List *relationsToTruncate = NIL;
/*
* Copy list to ensure we do not modify a cached plan
*/
relationsToTruncate = list_copy(stmt->relations);
/* /*
* Check if table has partitions and add them too * Check if table has partitions and add them too
*/ */
foreach(cell, stmt->relations) foreach(cell, relationsToTruncate)
{ {
RangeVar *rv = lfirst(cell); RangeVar *rv = lfirst(cell);
Relation rel; Relation rel;
...@@ -1596,12 +1602,12 @@ ExecuteTruncate(TruncateStmt *stmt) ...@@ -1596,12 +1602,12 @@ ExecuteTruncate(TruncateStmt *stmt)
heap_close(rel, NoLock); heap_close(rel, NoLock);
} }
stmt->relations = list_concat(partList, stmt->relations); relationsToTruncate = list_concat(partList, relationsToTruncate);
/* /*
* Open, exclusive-lock, and check all the explicitly-specified relations * Open, exclusive-lock, and check all the explicitly-specified relations
*/ */
foreach(cell, stmt->relations) foreach(cell, relationsToTruncate)
{ {
RangeVar *rv = lfirst(cell); RangeVar *rv = lfirst(cell);
Relation rel; Relation rel;
......
-- Given there is a partitioned table
create table some_partitioned_table_to_truncate
(
a integer
)
partition by range (a) (
partition b start (0)
);
NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Greenplum Database data distribution key for this table.
HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew.
NOTICE: CREATE TABLE will create partition "some_partitioned_table_to_truncate_1_prt_b" for table "some_partitioned_table_to_truncate"
-- And a function that truncates the partitioned table
CREATE OR REPLACE FUNCTION truncate_a_partition_table() RETURNS VOID AS
$$
BEGIN
TRUNCATE some_partitioned_table_to_truncate;
END;
$$ LANGUAGE plpgsql;
-- When I truncate the table twice
insert into some_partitioned_table_to_truncate
select i from generate_series(1, 10) i;
select count(*) from some_partitioned_table_to_truncate;
count
-------
10
(1 row)
select truncate_a_partition_table();
truncate_a_partition_table
----------------------------
(1 row)
select count(*) from some_partitioned_table_to_truncate;
count
-------
0
(1 row)
-- Then I get the same result both times (no rows)
insert into some_partitioned_table_to_truncate
select i from generate_series(1, 10) i;
select count(*) from some_partitioned_table_to_truncate;
count
-------
10
(1 row)
select truncate_a_partition_table();
truncate_a_partition_table
----------------------------
(1 row)
select count(*) from some_partitioned_table_to_truncate;
count
-------
0
(1 row)
...@@ -86,7 +86,7 @@ test: partial_table ...@@ -86,7 +86,7 @@ test: partial_table
# 'partition' runs for a long time, so try to keep it together with other # 'partition' runs for a long time, so try to keep it together with other
# long-running tests. # long-running tests.
test: partition partition1 partition_indexing parruleord partition_storage partition_ddl partition_with_user_defined_function partition_unlogged partition_subquery test: partition partition1 partition_indexing parruleord partition_storage partition_ddl partition_with_user_defined_function partition_unlogged partition_subquery partition_with_user_defined_function_that_truncates
test: index_constraint_naming index_constraint_naming_partition index_constraint_naming_upgrade test: index_constraint_naming index_constraint_naming_partition index_constraint_naming_upgrade
# 'partition_locking' gets confused if other backends run concurrently and # 'partition_locking' gets confused if other backends run concurrently and
......
-- Given there is a partitioned table
create table some_partitioned_table_to_truncate
(
a integer
)
partition by range (a) (
partition b start (0)
);
-- And a function that truncates the partitioned table
CREATE OR REPLACE FUNCTION truncate_a_partition_table() RETURNS VOID AS
$$
BEGIN
TRUNCATE some_partitioned_table_to_truncate;
END;
$$ LANGUAGE plpgsql;
-- When I truncate the table twice
insert into some_partitioned_table_to_truncate
select i from generate_series(1, 10) i;
select count(*) from some_partitioned_table_to_truncate;
select truncate_a_partition_table();
select count(*) from some_partitioned_table_to_truncate;
-- Then I get the same result both times (no rows)
insert into some_partitioned_table_to_truncate
select i from generate_series(1, 10) i;
select count(*) from some_partitioned_table_to_truncate;
select truncate_a_partition_table();
select count(*) from some_partitioned_table_to_truncate;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册