Fix EvalPlanQualStart to handle partitioned result rels correctly.

The es_root_result_relations array needs to be shallow-copied in the
same way as the main es_result_relations array, else EPQ rechecks on
partitioned result relations fail, as seen in bug #15677 from
Norbert Benkocs.

Amit Langote, isolation test case added by me

Discussion: https://postgr.es/m/15677-0bf089579b4cd02d@postgresql.org
Discussion: https://postgr.es/m/19321.1554567786@sss.pgh.pa.us
This commit is contained in:
Tom Lane 2019-04-08 12:20:22 -04:00
parent 348f57ce5b
commit a8cb8f1246
3 changed files with 42 additions and 1 deletions

View File

@ -2779,7 +2779,7 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
* es_param_exec_vals, etc.
*
* The ResultRelInfo array management is trickier than it looks. We
* create a fresh array for the child but copy all the content from the
* create fresh arrays for the child but copy all the content from the
* parent. This is because it's okay for the child to share any
* per-relation state the parent has already created --- but if the child
* sets up any ResultRelInfo fields, such as its own junkfilter, that
@ -2800,6 +2800,7 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
if (parentestate->es_num_result_relations > 0)
{
int numResultRelations = parentestate->es_num_result_relations;
int numRootResultRels = parentestate->es_num_root_result_relations;
ResultRelInfo *resultRelInfos;
resultRelInfos = (ResultRelInfo *)
@ -2808,6 +2809,17 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
numResultRelations * sizeof(ResultRelInfo));
estate->es_result_relations = resultRelInfos;
estate->es_num_result_relations = numResultRelations;
/* Also transfer partitioned root result relations. */
if (numRootResultRels > 0)
{
resultRelInfos = (ResultRelInfo *)
palloc(numRootResultRels * sizeof(ResultRelInfo));
memcpy(resultRelInfos, parentestate->es_root_result_relations,
numRootResultRels * sizeof(ResultRelInfo));
estate->es_root_result_relations = resultRelInfos;
estate->es_num_root_result_relations = numRootResultRels;
}
}
/* es_result_relation_info must NOT be copied */
/* es_trig_target_relations must NOT be copied */

View File

@ -629,3 +629,15 @@ step multireadwcte: <... completed>
subid id
1 1
starting permutation: simplepartupdate complexpartupdate c1 c2
step simplepartupdate:
update parttbl set a = a;
step complexpartupdate:
with u as (update parttbl set a = a returning parttbl.*)
update parttbl set a = u.a from u;
<waiting ...>
step c1: COMMIT;
step complexpartupdate: <... completed>
step c2: COMMIT;

View File

@ -32,6 +32,10 @@ setup
CREATE TABLE jointest AS SELECT generate_series(1,10) AS id, 0 AS data;
CREATE INDEX ON jointest(id);
CREATE TABLE parttbl (a int) PARTITION BY LIST (a);
CREATE TABLE parttbl1 PARTITION OF parttbl FOR VALUES IN (1);
INSERT INTO parttbl VALUES (1);
}
teardown
@ -41,6 +45,7 @@ teardown
DROP TABLE accounts_ext;
DROP TABLE p CASCADE;
DROP TABLE table_a, table_b, jointest;
DROP TABLE parttbl;
}
session "s1"
@ -137,6 +142,12 @@ step "selectresultforupdate" {
where jt.id = y for update of jt, ss1, ss2;
}
# test for EPQ on a partitioned result table
step "simplepartupdate" {
update parttbl set a = a;
}
session "s2"
setup { BEGIN ISOLATION LEVEL READ COMMITTED; }
@ -174,6 +185,10 @@ step "updateforcip3" {
}
step "wrtwcte" { UPDATE table_a SET value = 'tableAValue2' WHERE id = 1; }
step "wrjt" { UPDATE jointest SET data = 42 WHERE id = 7; }
step "complexpartupdate" {
with u as (update parttbl set a = a returning parttbl.*)
update parttbl set a = u.a from u;
}
# Use writable CTEs to create self-updated rows, that then are
# (updated|deleted). The *fail versions of the tests additionally
@ -261,3 +276,5 @@ permutation "wrtwcte" "readwcte" "c1" "c2"
permutation "wrjt" "selectjoinforupdate" "c2" "c1"
permutation "wrjt" "selectresultforupdate" "c2" "c1"
permutation "wrtwcte" "multireadwcte" "c1" "c2"
permutation "simplepartupdate" "complexpartupdate" "c1" "c2"