aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/executor/nodeAppend.c32
-rw-r--r--src/backend/executor/nodeMergeAppend.c38
-rw-r--r--src/backend/executor/nodeRecursiveunion.c8
3 files changed, 55 insertions, 23 deletions
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index ca0f54d676f..b5d56569f7f 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -110,6 +110,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
{
AppendState *appendstate = makeNode(AppendState);
PlanState **appendplanstates;
+ const TupleTableSlotOps *appendops;
Bitmapset *validsubplans;
Bitmapset *asyncplans;
int nplans;
@@ -176,15 +177,6 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
appendstate->as_prune_state = NULL;
}
- /*
- * Initialize result tuple type and slot.
- */
- ExecInitResultTupleSlotTL(&appendstate->ps, &TTSOpsVirtual);
-
- /* node returns slots from each of its subnodes, therefore not fixed */
- appendstate->ps.resultopsset = true;
- appendstate->ps.resultopsfixed = false;
-
appendplanstates = (PlanState **) palloc(nplans *
sizeof(PlanState *));
@@ -227,6 +219,28 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
appendstate->appendplans = appendplanstates;
appendstate->as_nplans = nplans;
+ /*
+ * Initialize Append's result tuple type and slot. If the child plans all
+ * produce the same fixed slot type, we can use that slot type; otherwise
+ * make a virtual slot. (Note that the result slot itself is used only to
+ * return a null tuple at end of execution; real tuples are returned to
+ * the caller in the children's own result slots. What we are doing here
+ * is allowing the parent plan node to optimize if the Append will return
+ * only one kind of slot.)
+ */
+ appendops = ExecGetCommonSlotOps(appendplanstates, j);
+ if (appendops != NULL)
+ {
+ ExecInitResultTupleSlotTL(&appendstate->ps, appendops);
+ }
+ else
+ {
+ ExecInitResultTupleSlotTL(&appendstate->ps, &TTSOpsVirtual);
+ /* show that the output slot type is not fixed */
+ appendstate->ps.resultopsset = true;
+ appendstate->ps.resultopsfixed = false;
+ }
+
/* Initialize async state */
appendstate->as_asyncplans = asyncplans;
appendstate->as_nasyncplans = nasyncplans;
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index e1b9b984a7a..081734e8172 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -66,6 +66,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
{
MergeAppendState *mergestate = makeNode(MergeAppendState);
PlanState **mergeplanstates;
+ const TupleTableSlotOps *mergeops;
Bitmapset *validsubplans;
int nplans;
int i,
@@ -129,18 +130,6 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
mergestate);
/*
- * Miscellaneous initialization
- *
- * MergeAppend nodes do have Result slots, which hold pointers to tuples,
- * so we have to initialize them. FIXME
- */
- ExecInitResultTupleSlotTL(&mergestate->ps, &TTSOpsVirtual);
-
- /* node returns slots from each of its subnodes, therefore not fixed */
- mergestate->ps.resultopsset = true;
- mergestate->ps.resultopsfixed = false;
-
- /*
* call ExecInitNode on each of the valid plans to be executed and save
* the results into the mergeplanstates array.
*/
@@ -153,6 +142,31 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
mergeplanstates[j++] = ExecInitNode(initNode, estate, eflags);
}
+ /*
+ * Initialize MergeAppend's result tuple type and slot. If the child
+ * plans all produce the same fixed slot type, we can use that slot type;
+ * otherwise make a virtual slot. (Note that the result slot itself is
+ * used only to return a null tuple at end of execution; real tuples are
+ * returned to the caller in the children's own result slots. What we are
+ * doing here is allowing the parent plan node to optimize if the
+ * MergeAppend will return only one kind of slot.)
+ */
+ mergeops = ExecGetCommonSlotOps(mergeplanstates, j);
+ if (mergeops != NULL)
+ {
+ ExecInitResultTupleSlotTL(&mergestate->ps, mergeops);
+ }
+ else
+ {
+ ExecInitResultTupleSlotTL(&mergestate->ps, &TTSOpsVirtual);
+ /* show that the output slot type is not fixed */
+ mergestate->ps.resultopsset = true;
+ mergestate->ps.resultopsfixed = false;
+ }
+
+ /*
+ * Miscellaneous initialization
+ */
mergestate->ps.ps_ProjInfo = NULL;
/*
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index 39be4cdc3b1..b577b72b50c 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -37,10 +37,14 @@ build_hash_table(RecursiveUnionState *rustate)
Assert(node->numCols > 0);
Assert(node->numGroups > 0);
- /* XXX is it worth working a bit harder to determine the inputOps here? */
+ /*
+ * If both child plans deliver the same fixed tuple slot type, we can tell
+ * BuildTupleHashTableExt to expect that slot type as input. Otherwise,
+ * we'll pass NULL denoting that any slot type is possible.
+ */
rustate->hashtable = BuildTupleHashTableExt(&rustate->ps,
desc,
- NULL,
+ ExecGetCommonChildSlotOps(&rustate->ps),
node->numCols,
node->dupColIdx,
rustate->eqfuncoids,