]> granicus.if.org Git - postgresql/commitdiff
Fix EvalPlanQualStart to handle partitioned result rels correctly.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 8 Apr 2019 16:20:23 +0000 (12:20 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 8 Apr 2019 16:20:23 +0000 (12:20 -0400)
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

src/backend/executor/execMain.c
src/test/isolation/expected/eval-plan-qual.out
src/test/isolation/specs/eval-plan-qual.spec

index 14704f8838c9f9225f023d1cfc2b4af9ed61b1fd..bf7631276d9bddf50aec1f69ef808b4cd1b99bbe 100644 (file)
@@ -3101,7 +3101,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
@@ -3118,6 +3118,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 *)
@@ -3126,6 +3127,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 */
index fe4100d51d49df26de1a0d8d58b00cccbc270f63..92346802d878912874b387e4ad43a2c65b50963e 100644 (file)
@@ -263,3 +263,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;
index 35f3be1cc8d20e711bb0ca7ed47f52e9212caec4..88531b7dbe7400c623f9567e4951efd4bfdddb39 100644 (file)
@@ -24,6 +24,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
@@ -31,6 +35,7 @@ teardown
  DROP TABLE accounts;
  DROP TABLE p CASCADE;
  DROP TABLE table_a, table_b, jointest;
+ DROP TABLE parttbl;
 }
 
 session "s1"
@@ -99,6 +104,12 @@ step "selectjoinforupdate"  {
        select * from jointest a join jointest b on a.id=b.id for update;
 }
 
+# test for EPQ on a partitioned result table
+
+step "simplepartupdate"        {
+       update parttbl set a = a;
+}
+
 
 session "s2"
 setup          { BEGIN ISOLATION LEVEL READ COMMITTED; }
@@ -133,6 +144,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;
+}
 step "c2"      { COMMIT; }
 
 session "s3"
@@ -177,3 +192,5 @@ permutation "updateforcip" "updateforcip3" "c1" "c2" "read_a"
 permutation "wrtwcte" "readwcte" "c1" "c2"
 permutation "wrjt" "selectjoinforupdate" "c2" "c1"
 permutation "wrtwcte" "multireadwcte" "c1" "c2"
+
+permutation "simplepartupdate" "complexpartupdate" "c1" "c2"