]> granicus.if.org Git - postgresql/commitdiff
Fix slot type assumptions for nodeGather[Merge].
authorAndres Freund <andres@anarazel.de>
Fri, 16 Nov 2018 07:10:50 +0000 (23:10 -0800)
committerAndres Freund <andres@anarazel.de>
Fri, 16 Nov 2018 07:16:41 +0000 (23:16 -0800)
The assumption made in 1a0586de3657c was wrong, as evidenced by
buildfarm failure on locust, which runs with
force_parallel_mode=regress.  The tuples accessed in either nodes are
in the outer slot, and we can't trivially rely on the slot type being
known because the leader might execute the subsidiary node directly,
or via the tuple queue on a worker. In the latter case the tuple will
always be a heaptuple slot, but in the former, it'll be whatever the
subsidiary node returns.

src/backend/executor/nodeGather.c
src/backend/executor/nodeGatherMerge.c

index e45e07f0a1a628d102e7d3bd4f935e90528f3c4f..c979a5577490d778f7b444e67ef6bfedf3016c8d 100644 (file)
@@ -91,10 +91,14 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
        outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags);
        tupDesc = ExecGetResultType(outerPlanState(gatherstate));
 
-       /* this node uses tuples from the tuple queue as scan slot */
-       gatherstate->ps.scanops = &TTSOpsHeapTuple;
-       gatherstate->ps.scanopsfixed = true;
-       gatherstate->ps.scanopsset = true;
+       /*
+        * Leader may access ExecProcNode result directly (if
+        * need_to_scan_locally), or from workers via tuple queue.  So we can't
+        * trivially rely on the slot type being fixed for expressions evaluated
+        * within this node.
+        */
+       gatherstate->ps.outeropsset = true;
+       gatherstate->ps.outeropsfixed = false;
 
        /*
         * Initialize result type and projection.
@@ -102,6 +106,16 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
        ExecInitResultTypeTL(&gatherstate->ps);
        ExecConditionalAssignProjectionInfo(&gatherstate->ps, tupDesc, OUTER_VAR);
 
+       /*
+        * Without projections result slot type is not trivially known, see
+        * comment above.
+        */
+       if (gatherstate->ps.ps_ProjInfo == NULL)
+       {
+               gatherstate->ps.resultopsset = true;
+               gatherstate->ps.resultopsfixed = false;
+       }
+
        /*
         * Initialize funnel slot to same tuple descriptor as outer plan.
         */
index 651565123befdbc558e3176f84423797241e9b07..51d910bd5ee0854b7d81a5806752c4e6123a9b9f 100644 (file)
@@ -109,6 +109,15 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
        outerNode = outerPlan(node);
        outerPlanState(gm_state) = ExecInitNode(outerNode, estate, eflags);
 
+       /*
+        * Leader may access ExecProcNode result directly (if
+        * need_to_scan_locally), or from workers via tuple queue.  So we can't
+        * trivially rely on the slot type being fixed for expressions evaluated
+        * within this node.
+        */
+       gm_state->ps.outeropsset = true;
+       gm_state->ps.outeropsfixed = false;
+
        /*
         * Store the tuple descriptor into gather merge state, so we can use it
         * while initializing the gather merge slots.
@@ -122,7 +131,10 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
        ExecInitResultTypeTL(&gm_state->ps);
        ExecConditionalAssignProjectionInfo(&gm_state->ps, tupDesc, OUTER_VAR);
 
-       /* leader accesses ExecProcNode result directly, others go through tuple queue */
+       /*
+        * Without projections result slot type is not trivially known, see
+        * comment above.
+        */
        if (gm_state->ps.ps_ProjInfo == NULL)
        {
                gm_state->ps.resultopsset = true;