Skip to content

Commit f0b9000

Browse files
committed
Use ExecGetCommonSlotOps infrastructure in more places.
Append, MergeAppend, and RecursiveUnion can all use the support functions added in commit 2762792. The first two can report a fixed result slot type if all their children return the same fixed slot type. That does nothing for the append step itself, but might allow optimizations in the parent plan node. RecursiveUnion can optimize tuple hash table operations in the same way as SetOp now does. Patch by me; thanks to Richard Guo and David Rowley for review. Discussion: https://postgr.es/m/1850138.1731549611@sss.pgh.pa.us
1 parent 8d96f57 commit f0b9000

File tree

3 files changed

+55
-23
lines changed

3 files changed

+55
-23
lines changed

src/backend/executor/nodeAppend.c

+23-9
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
110110
{
111111
AppendState *appendstate = makeNode(AppendState);
112112
PlanState **appendplanstates;
113+
const TupleTableSlotOps *appendops;
113114
Bitmapset *validsubplans;
114115
Bitmapset *asyncplans;
115116
int nplans;
@@ -176,15 +177,6 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
176177
appendstate->as_prune_state = NULL;
177178
}
178179

179-
/*
180-
* Initialize result tuple type and slot.
181-
*/
182-
ExecInitResultTupleSlotTL(&appendstate->ps, &TTSOpsVirtual);
183-
184-
/* node returns slots from each of its subnodes, therefore not fixed */
185-
appendstate->ps.resultopsset = true;
186-
appendstate->ps.resultopsfixed = false;
187-
188180
appendplanstates = (PlanState **) palloc(nplans *
189181
sizeof(PlanState *));
190182

@@ -227,6 +219,28 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
227219
appendstate->appendplans = appendplanstates;
228220
appendstate->as_nplans = nplans;
229221

222+
/*
223+
* Initialize Append's result tuple type and slot. If the child plans all
224+
* produce the same fixed slot type, we can use that slot type; otherwise
225+
* make a virtual slot. (Note that the result slot itself is used only to
226+
* return a null tuple at end of execution; real tuples are returned to
227+
* the caller in the children's own result slots. What we are doing here
228+
* is allowing the parent plan node to optimize if the Append will return
229+
* only one kind of slot.)
230+
*/
231+
appendops = ExecGetCommonSlotOps(appendplanstates, j);
232+
if (appendops != NULL)
233+
{
234+
ExecInitResultTupleSlotTL(&appendstate->ps, appendops);
235+
}
236+
else
237+
{
238+
ExecInitResultTupleSlotTL(&appendstate->ps, &TTSOpsVirtual);
239+
/* show that the output slot type is not fixed */
240+
appendstate->ps.resultopsset = true;
241+
appendstate->ps.resultopsfixed = false;
242+
}
243+
230244
/* Initialize async state */
231245
appendstate->as_asyncplans = asyncplans;
232246
appendstate->as_nasyncplans = nasyncplans;

src/backend/executor/nodeMergeAppend.c

+26-12
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
6666
{
6767
MergeAppendState *mergestate = makeNode(MergeAppendState);
6868
PlanState **mergeplanstates;
69+
const TupleTableSlotOps *mergeops;
6970
Bitmapset *validsubplans;
7071
int nplans;
7172
int i,
@@ -128,18 +129,6 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
128129
mergestate->ms_heap = binaryheap_allocate(nplans, heap_compare_slots,
129130
mergestate);
130131

131-
/*
132-
* Miscellaneous initialization
133-
*
134-
* MergeAppend nodes do have Result slots, which hold pointers to tuples,
135-
* so we have to initialize them. FIXME
136-
*/
137-
ExecInitResultTupleSlotTL(&mergestate->ps, &TTSOpsVirtual);
138-
139-
/* node returns slots from each of its subnodes, therefore not fixed */
140-
mergestate->ps.resultopsset = true;
141-
mergestate->ps.resultopsfixed = false;
142-
143132
/*
144133
* call ExecInitNode on each of the valid plans to be executed and save
145134
* the results into the mergeplanstates array.
@@ -153,6 +142,31 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
153142
mergeplanstates[j++] = ExecInitNode(initNode, estate, eflags);
154143
}
155144

145+
/*
146+
* Initialize MergeAppend's result tuple type and slot. If the child
147+
* plans all produce the same fixed slot type, we can use that slot type;
148+
* otherwise make a virtual slot. (Note that the result slot itself is
149+
* used only to return a null tuple at end of execution; real tuples are
150+
* returned to the caller in the children's own result slots. What we are
151+
* doing here is allowing the parent plan node to optimize if the
152+
* MergeAppend will return only one kind of slot.)
153+
*/
154+
mergeops = ExecGetCommonSlotOps(mergeplanstates, j);
155+
if (mergeops != NULL)
156+
{
157+
ExecInitResultTupleSlotTL(&mergestate->ps, mergeops);
158+
}
159+
else
160+
{
161+
ExecInitResultTupleSlotTL(&mergestate->ps, &TTSOpsVirtual);
162+
/* show that the output slot type is not fixed */
163+
mergestate->ps.resultopsset = true;
164+
mergestate->ps.resultopsfixed = false;
165+
}
166+
167+
/*
168+
* Miscellaneous initialization
169+
*/
156170
mergestate->ps.ps_ProjInfo = NULL;
157171

158172
/*

src/backend/executor/nodeRecursiveunion.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,14 @@ build_hash_table(RecursiveUnionState *rustate)
3737
Assert(node->numCols > 0);
3838
Assert(node->numGroups > 0);
3939

40-
/* XXX is it worth working a bit harder to determine the inputOps here? */
40+
/*
41+
* If both child plans deliver the same fixed tuple slot type, we can tell
42+
* BuildTupleHashTableExt to expect that slot type as input. Otherwise,
43+
* we'll pass NULL denoting that any slot type is possible.
44+
*/
4145
rustate->hashtable = BuildTupleHashTableExt(&rustate->ps,
4246
desc,
43-
NULL,
47+
ExecGetCommonChildSlotOps(&rustate->ps),
4448
node->numCols,
4549
node->dupColIdx,
4650
rustate->eqfuncoids,

0 commit comments

Comments
 (0)