1/*-------------------------------------------------------------------------
2 *
3 * nodeSubplan.c
4 * routines to support sub-selects appearing in expressions
5 *
6 * This module is concerned with executing SubPlan expression nodes, which
7 * should not be confused with sub-SELECTs appearing in FROM. SubPlans are
8 * divided into "initplans", which are those that need only one evaluation per
9 * query (among other restrictions, this requires that they don't use any
10 * direct correlation variables from the parent plan level), and "regular"
11 * subplans, which are re-evaluated every time their result is required.
12 *
13 *
14 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
15 * Portions Copyright (c) 1994, Regents of the University of California
16 *
17 * IDENTIFICATION
18 * src/backend/executor/nodeSubplan.c
19 *
20 *-------------------------------------------------------------------------
21 */
22/*
23 * INTERFACE ROUTINES
24 * ExecSubPlan - process a subselect
25 * ExecInitSubPlan - initialize a subselect
26 */
27#include "postgres.h"
28
29#include <limits.h>
30#include <math.h>
31
32#include "access/htup_details.h"
33#include "executor/executor.h"
34#include "executor/nodeSubplan.h"
35#include "nodes/makefuncs.h"
36#include "nodes/nodeFuncs.h"
37#include "miscadmin.h"
38#include "utils/array.h"
39#include "utils/lsyscache.h"
40#include "utils/memutils.h"
41
42
43static Datum ExecHashSubPlan(SubPlanState *node,
44 ExprContext *econtext,
45 bool *isNull);
46static Datum ExecScanSubPlan(SubPlanState *node,
47 ExprContext *econtext,
48 bool *isNull);
49static void buildSubPlanHash(SubPlanState *node, ExprContext *econtext);
50static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
51 FmgrInfo *eqfunctions);
52static bool slotAllNulls(TupleTableSlot *slot);
53static bool slotNoNulls(TupleTableSlot *slot);
54
55
56/* ----------------------------------------------------------------
57 * ExecSubPlan
58 *
59 * This is the main entry point for execution of a regular SubPlan.
60 * ----------------------------------------------------------------
61 */
62Datum
63ExecSubPlan(SubPlanState *node,
64 ExprContext *econtext,
65 bool *isNull)
66{
67 SubPlan *subplan = node->subplan;
68 EState *estate = node->planstate->state;
69 ScanDirection dir = estate->es_direction;
70 Datum retval;
71
72 CHECK_FOR_INTERRUPTS();
73
74 /* Set non-null as default */
75 *isNull = false;
76
77 /* Sanity checks */
78 if (subplan->subLinkType == CTE_SUBLINK)
79 elog(ERROR, "CTE subplans should not be executed via ExecSubPlan");
80 if (subplan->setParam != NIL && subplan->subLinkType != MULTIEXPR_SUBLINK)
81 elog(ERROR, "cannot set parent params from subquery");
82
83 /* Force forward-scan mode for evaluation */
84 estate->es_direction = ForwardScanDirection;
85
86 /* Select appropriate evaluation strategy */
87 if (subplan->useHashTable)
88 retval = ExecHashSubPlan(node, econtext, isNull);
89 else
90 retval = ExecScanSubPlan(node, econtext, isNull);
91
92 /* restore scan direction */
93 estate->es_direction = dir;
94
95 return retval;
96}
97
98/*
99 * ExecHashSubPlan: store subselect result in an in-memory hash table
100 */
101static Datum
102ExecHashSubPlan(SubPlanState *node,
103 ExprContext *econtext,
104 bool *isNull)
105{
106 SubPlan *subplan = node->subplan;
107 PlanState *planstate = node->planstate;
108 TupleTableSlot *slot;
109
110 /* Shouldn't have any direct correlation Vars */
111 if (subplan->parParam != NIL || node->args != NIL)
112 elog(ERROR, "hashed subplan with direct correlation not supported");
113
114 /*
115 * If first time through or we need to rescan the subplan, build the hash
116 * table.
117 */
118 if (node->hashtable == NULL || planstate->chgParam != NULL)
119 buildSubPlanHash(node, econtext);
120
121 /*
122 * The result for an empty subplan is always FALSE; no need to evaluate
123 * lefthand side.
124 */
125 *isNull = false;
126 if (!node->havehashrows && !node->havenullrows)
127 return BoolGetDatum(false);
128
129 /*
130 * Evaluate lefthand expressions and form a projection tuple. First we
131 * have to set the econtext to use (hack alert!).
132 */
133 node->projLeft->pi_exprContext = econtext;
134 slot = ExecProject(node->projLeft);
135
136 /*
137 * Note: because we are typically called in a per-tuple context, we have
138 * to explicitly clear the projected tuple before returning. Otherwise,
139 * we'll have a double-free situation: the per-tuple context will probably
140 * be reset before we're called again, and then the tuple slot will think
141 * it still needs to free the tuple.
142 */
143
144 /*
145 * If the LHS is all non-null, probe for an exact match in the main hash
146 * table. If we find one, the result is TRUE. Otherwise, scan the
147 * partly-null table to see if there are any rows that aren't provably
148 * unequal to the LHS; if so, the result is UNKNOWN. (We skip that part
149 * if we don't care about UNKNOWN.) Otherwise, the result is FALSE.
150 *
151 * Note: the reason we can avoid a full scan of the main hash table is
152 * that the combining operators are assumed never to yield NULL when both
153 * inputs are non-null. If they were to do so, we might need to produce
154 * UNKNOWN instead of FALSE because of an UNKNOWN result in comparing the
155 * LHS to some main-table entry --- which is a comparison we will not even
156 * make, unless there's a chance match of hash keys.
157 */
158 if (slotNoNulls(slot))
159 {
160 if (node->havehashrows &&
161 FindTupleHashEntry(node->hashtable,
162 slot,
163 node->cur_eq_comp,
164 node->lhs_hash_funcs) != NULL)
165 {
166 ExecClearTuple(slot);
167 return BoolGetDatum(true);
168 }
169 if (node->havenullrows &&
170 findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
171 {
172 ExecClearTuple(slot);
173 *isNull = true;
174 return BoolGetDatum(false);
175 }
176 ExecClearTuple(slot);
177 return BoolGetDatum(false);
178 }
179
180 /*
181 * When the LHS is partly or wholly NULL, we can never return TRUE. If we
182 * don't care about UNKNOWN, just return FALSE. Otherwise, if the LHS is
183 * wholly NULL, immediately return UNKNOWN. (Since the combining
184 * operators are strict, the result could only be FALSE if the sub-select
185 * were empty, but we already handled that case.) Otherwise, we must scan
186 * both the main and partly-null tables to see if there are any rows that
187 * aren't provably unequal to the LHS; if so, the result is UNKNOWN.
188 * Otherwise, the result is FALSE.
189 */
190 if (node->hashnulls == NULL)
191 {
192 ExecClearTuple(slot);
193 return BoolGetDatum(false);
194 }
195 if (slotAllNulls(slot))
196 {
197 ExecClearTuple(slot);
198 *isNull = true;
199 return BoolGetDatum(false);
200 }
201 /* Scan partly-null table first, since more likely to get a match */
202 if (node->havenullrows &&
203 findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
204 {
205 ExecClearTuple(slot);
206 *isNull = true;
207 return BoolGetDatum(false);
208 }
209 if (node->havehashrows &&
210 findPartialMatch(node->hashtable, slot, node->cur_eq_funcs))
211 {
212 ExecClearTuple(slot);
213 *isNull = true;
214 return BoolGetDatum(false);
215 }
216 ExecClearTuple(slot);
217 return BoolGetDatum(false);
218}
219
220/*
221 * ExecScanSubPlan: default case where we have to rescan subplan each time
222 */
223static Datum
224ExecScanSubPlan(SubPlanState *node,
225 ExprContext *econtext,
226 bool *isNull)
227{
228 SubPlan *subplan = node->subplan;
229 PlanState *planstate = node->planstate;
230 SubLinkType subLinkType = subplan->subLinkType;
231 MemoryContext oldcontext;
232 TupleTableSlot *slot;
233 Datum result;
234 bool found = false; /* true if got at least one subplan tuple */
235 ListCell *pvar;
236 ListCell *l;
237 ArrayBuildStateAny *astate = NULL;
238
239 /*
240 * MULTIEXPR subplans, when "executed", just return NULL; but first we
241 * mark the subplan's output parameters as needing recalculation. (This
242 * is a bit of a hack: it relies on the subplan appearing later in its
243 * targetlist than any of the referencing Params, so that all the Params
244 * have been evaluated before we re-mark them for the next evaluation
245 * cycle. But in general resjunk tlist items appear after non-resjunk
246 * ones, so this should be safe.) Unlike ExecReScanSetParamPlan, we do
247 * *not* set bits in the parent plan node's chgParam, because we don't
248 * want to cause a rescan of the parent.
249 */
250 if (subLinkType == MULTIEXPR_SUBLINK)
251 {
252 EState *estate = node->parent->state;
253
254 foreach(l, subplan->setParam)
255 {
256 int paramid = lfirst_int(l);
257 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
258
259 prm->execPlan = node;
260 }
261 *isNull = true;
262 return (Datum) 0;
263 }
264
265 /* Initialize ArrayBuildStateAny in caller's context, if needed */
266 if (subLinkType == ARRAY_SUBLINK)
267 astate = initArrayResultAny(subplan->firstColType,
268 CurrentMemoryContext, true);
269
270 /*
271 * We are probably in a short-lived expression-evaluation context. Switch
272 * to the per-query context for manipulating the child plan's chgParam,
273 * calling ExecProcNode on it, etc.
274 */
275 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
276
277 /*
278 * Set Params of this plan from parent plan correlation values. (Any
279 * calculation we have to do is done in the parent econtext, since the
280 * Param values don't need to have per-query lifetime.)
281 */
282 Assert(list_length(subplan->parParam) == list_length(node->args));
283
284 forboth(l, subplan->parParam, pvar, node->args)
285 {
286 int paramid = lfirst_int(l);
287 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
288
289 prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
290 econtext,
291 &(prm->isnull));
292 planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
293 }
294
295 /*
296 * Now that we've set up its parameters, we can reset the subplan.
297 */
298 ExecReScan(planstate);
299
300 /*
301 * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result
302 * is boolean as are the results of the combining operators. We combine
303 * results across tuples (if the subplan produces more than one) using OR
304 * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
305 * (ROWCOMPARE_SUBLINK doesn't allow multiple tuples from the subplan.)
306 * NULL results from the combining operators are handled according to the
307 * usual SQL semantics for OR and AND. The result for no input tuples is
308 * FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
309 * ROWCOMPARE_SUBLINK.
310 *
311 * For EXPR_SUBLINK we require the subplan to produce no more than one
312 * tuple, else an error is raised. If zero tuples are produced, we return
313 * NULL. Assuming we get a tuple, we just use its first column (there can
314 * be only one non-junk column in this case).
315 *
316 * For ARRAY_SUBLINK we allow the subplan to produce any number of tuples,
317 * and form an array of the first column's values. Note in particular
318 * that we produce a zero-element array if no tuples are produced (this is
319 * a change from pre-8.3 behavior of returning NULL).
320 */
321 result = BoolGetDatum(subLinkType == ALL_SUBLINK);
322 *isNull = false;
323
324 for (slot = ExecProcNode(planstate);
325 !TupIsNull(slot);
326 slot = ExecProcNode(planstate))
327 {
328 TupleDesc tdesc = slot->tts_tupleDescriptor;
329 Datum rowresult;
330 bool rownull;
331 int col;
332 ListCell *plst;
333
334 if (subLinkType == EXISTS_SUBLINK)
335 {
336 found = true;
337 result = BoolGetDatum(true);
338 break;
339 }
340
341 if (subLinkType == EXPR_SUBLINK)
342 {
343 /* cannot allow multiple input tuples for EXPR sublink */
344 if (found)
345 ereport(ERROR,
346 (errcode(ERRCODE_CARDINALITY_VIOLATION),
347 errmsg("more than one row returned by a subquery used as an expression")));
348 found = true;
349
350 /*
351 * We need to copy the subplan's tuple in case the result is of
352 * pass-by-ref type --- our return value will point into this
353 * copied tuple! Can't use the subplan's instance of the tuple
354 * since it won't still be valid after next ExecProcNode() call.
355 * node->curTuple keeps track of the copied tuple for eventual
356 * freeing.
357 */
358 if (node->curTuple)
359 heap_freetuple(node->curTuple);
360 node->curTuple = ExecCopySlotHeapTuple(slot);
361
362 result = heap_getattr(node->curTuple, 1, tdesc, isNull);
363 /* keep scanning subplan to make sure there's only one tuple */
364 continue;
365 }
366
367 if (subLinkType == ARRAY_SUBLINK)
368 {
369 Datum dvalue;
370 bool disnull;
371
372 found = true;
373 /* stash away current value */
374 Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
375 dvalue = slot_getattr(slot, 1, &disnull);
376 astate = accumArrayResultAny(astate, dvalue, disnull,
377 subplan->firstColType, oldcontext);
378 /* keep scanning subplan to collect all values */
379 continue;
380 }
381
382 /* cannot allow multiple input tuples for ROWCOMPARE sublink either */
383 if (subLinkType == ROWCOMPARE_SUBLINK && found)
384 ereport(ERROR,
385 (errcode(ERRCODE_CARDINALITY_VIOLATION),
386 errmsg("more than one row returned by a subquery used as an expression")));
387
388 found = true;
389
390 /*
391 * For ALL, ANY, and ROWCOMPARE sublinks, load up the Params
392 * representing the columns of the sub-select, and then evaluate the
393 * combining expression.
394 */
395 col = 1;
396 foreach(plst, subplan->paramIds)
397 {
398 int paramid = lfirst_int(plst);
399 ParamExecData *prmdata;
400
401 prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
402 Assert(prmdata->execPlan == NULL);
403 prmdata->value = slot_getattr(slot, col, &(prmdata->isnull));
404 col++;
405 }
406
407 rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext,
408 &rownull);
409
410 if (subLinkType == ANY_SUBLINK)
411 {
412 /* combine across rows per OR semantics */
413 if (rownull)
414 *isNull = true;
415 else if (DatumGetBool(rowresult))
416 {
417 result = BoolGetDatum(true);
418 *isNull = false;
419 break; /* needn't look at any more rows */
420 }
421 }
422 else if (subLinkType == ALL_SUBLINK)
423 {
424 /* combine across rows per AND semantics */
425 if (rownull)
426 *isNull = true;
427 else if (!DatumGetBool(rowresult))
428 {
429 result = BoolGetDatum(false);
430 *isNull = false;
431 break; /* needn't look at any more rows */
432 }
433 }
434 else
435 {
436 /* must be ROWCOMPARE_SUBLINK */
437 result = rowresult;
438 *isNull = rownull;
439 }
440 }
441
442 MemoryContextSwitchTo(oldcontext);
443
444 if (subLinkType == ARRAY_SUBLINK)
445 {
446 /* We return the result in the caller's context */
447 result = makeArrayResultAny(astate, oldcontext, true);
448 }
449 else if (!found)
450 {
451 /*
452 * deal with empty subplan result. result/isNull were previously
453 * initialized correctly for all sublink types except EXPR and
454 * ROWCOMPARE; for those, return NULL.
455 */
456 if (subLinkType == EXPR_SUBLINK ||
457 subLinkType == ROWCOMPARE_SUBLINK)
458 {
459 result = (Datum) 0;
460 *isNull = true;
461 }
462 }
463
464 return result;
465}
466
467/*
468 * buildSubPlanHash: load hash table by scanning subplan output.
469 */
470static void
471buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
472{
473 SubPlan *subplan = node->subplan;
474 PlanState *planstate = node->planstate;
475 int ncols = list_length(subplan->paramIds);
476 ExprContext *innerecontext = node->innerecontext;
477 MemoryContext oldcontext;
478 long nbuckets;
479 TupleTableSlot *slot;
480
481 Assert(subplan->subLinkType == ANY_SUBLINK);
482
483 /*
484 * If we already had any hash tables, reset 'em; otherwise create empty
485 * hash table(s).
486 *
487 * If we need to distinguish accurately between FALSE and UNKNOWN (i.e.,
488 * NULL) results of the IN operation, then we have to store subplan output
489 * rows that are partly or wholly NULL. We store such rows in a separate
490 * hash table that we expect will be much smaller than the main table. (We
491 * can use hashing to eliminate partly-null rows that are not distinct. We
492 * keep them separate to minimize the cost of the inevitable full-table
493 * searches; see findPartialMatch.)
494 *
495 * If it's not necessary to distinguish FALSE and UNKNOWN, then we don't
496 * need to store subplan output rows that contain NULL.
497 */
498 MemoryContextReset(node->hashtablecxt);
499 node->hashtable = NULL;
500 node->hashnulls = NULL;
501 node->havehashrows = false;
502 node->havenullrows = false;
503
504 nbuckets = (long) Min(planstate->plan->plan_rows, (double) LONG_MAX);
505 if (nbuckets < 1)
506 nbuckets = 1;
507
508 if (node->hashtable)
509 ResetTupleHashTable(node->hashtable);
510 else
511 node->hashtable = BuildTupleHashTableExt(node->parent,
512 node->descRight,
513 ncols,
514 node->keyColIdx,
515 node->tab_eq_funcoids,
516 node->tab_hash_funcs,
517 node->tab_collations,
518 nbuckets,
519 0,
520 node->planstate->state->es_query_cxt,
521 node->hashtablecxt,
522 node->hashtempcxt,
523 false);
524
525 if (!subplan->unknownEqFalse)
526 {
527 if (ncols == 1)
528 nbuckets = 1; /* there can only be one entry */
529 else
530 {
531 nbuckets /= 16;
532 if (nbuckets < 1)
533 nbuckets = 1;
534 }
535
536 if (node->hashnulls)
537 ResetTupleHashTable(node->hashtable);
538 else
539 node->hashnulls = BuildTupleHashTableExt(node->parent,
540 node->descRight,
541 ncols,
542 node->keyColIdx,
543 node->tab_eq_funcoids,
544 node->tab_hash_funcs,
545 node->tab_collations,
546 nbuckets,
547 0,
548 node->planstate->state->es_query_cxt,
549 node->hashtablecxt,
550 node->hashtempcxt,
551 false);
552 }
553
554 /*
555 * We are probably in a short-lived expression-evaluation context. Switch
556 * to the per-query context for manipulating the child plan.
557 */
558 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
559
560 /*
561 * Reset subplan to start.
562 */
563 ExecReScan(planstate);
564
565 /*
566 * Scan the subplan and load the hash table(s). Note that when there are
567 * duplicate rows coming out of the sub-select, only one copy is stored.
568 */
569 for (slot = ExecProcNode(planstate);
570 !TupIsNull(slot);
571 slot = ExecProcNode(planstate))
572 {
573 int col = 1;
574 ListCell *plst;
575 bool isnew;
576
577 /*
578 * Load up the Params representing the raw sub-select outputs, then
579 * form the projection tuple to store in the hashtable.
580 */
581 foreach(plst, subplan->paramIds)
582 {
583 int paramid = lfirst_int(plst);
584 ParamExecData *prmdata;
585
586 prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
587 Assert(prmdata->execPlan == NULL);
588 prmdata->value = slot_getattr(slot, col,
589 &(prmdata->isnull));
590 col++;
591 }
592 slot = ExecProject(node->projRight);
593
594 /*
595 * If result contains any nulls, store separately or not at all.
596 */
597 if (slotNoNulls(slot))
598 {
599 (void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
600 node->havehashrows = true;
601 }
602 else if (node->hashnulls)
603 {
604 (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
605 node->havenullrows = true;
606 }
607
608 /*
609 * Reset innerecontext after each inner tuple to free any memory used
610 * during ExecProject.
611 */
612 ResetExprContext(innerecontext);
613 }
614
615 /*
616 * Since the projected tuples are in the sub-query's context and not the
617 * main context, we'd better clear the tuple slot before there's any
618 * chance of a reset of the sub-query's context. Else we will have the
619 * potential for a double free attempt. (XXX possibly no longer needed,
620 * but can't hurt.)
621 */
622 ExecClearTuple(node->projRight->pi_state.resultslot);
623
624 MemoryContextSwitchTo(oldcontext);
625}
626
627/*
628 * execTuplesUnequal
629 * Return true if two tuples are definitely unequal in the indicated
630 * fields.
631 *
632 * Nulls are neither equal nor unequal to anything else. A true result
633 * is obtained only if there are non-null fields that compare not-equal.
634 *
635 * slot1, slot2: the tuples to compare (must have same columns!)
636 * numCols: the number of attributes to be examined
637 * matchColIdx: array of attribute column numbers
638 * eqFunctions: array of fmgr lookup info for the equality functions to use
639 * evalContext: short-term memory context for executing the functions
640 */
641static bool
642execTuplesUnequal(TupleTableSlot *slot1,
643 TupleTableSlot *slot2,
644 int numCols,
645 AttrNumber *matchColIdx,
646 FmgrInfo *eqfunctions,
647 const Oid *collations,
648 MemoryContext evalContext)
649{
650 MemoryContext oldContext;
651 bool result;
652 int i;
653
654 /* Reset and switch into the temp context. */
655 MemoryContextReset(evalContext);
656 oldContext = MemoryContextSwitchTo(evalContext);
657
658 /*
659 * We cannot report a match without checking all the fields, but we can
660 * report a non-match as soon as we find unequal fields. So, start
661 * comparing at the last field (least significant sort key). That's the
662 * most likely to be different if we are dealing with sorted input.
663 */
664 result = false;
665
666 for (i = numCols; --i >= 0;)
667 {
668 AttrNumber att = matchColIdx[i];
669 Datum attr1,
670 attr2;
671 bool isNull1,
672 isNull2;
673
674 attr1 = slot_getattr(slot1, att, &isNull1);
675
676 if (isNull1)
677 continue; /* can't prove anything here */
678
679 attr2 = slot_getattr(slot2, att, &isNull2);
680
681 if (isNull2)
682 continue; /* can't prove anything here */
683
684 /* Apply the type-specific equality function */
685 if (!DatumGetBool(FunctionCall2Coll(&eqfunctions[i],
686 collations[i],
687 attr1, attr2)))
688 {
689 result = true; /* they are unequal */
690 break;
691 }
692 }
693
694 MemoryContextSwitchTo(oldContext);
695
696 return result;
697}
698
699/*
700 * findPartialMatch: does the hashtable contain an entry that is not
701 * provably distinct from the tuple?
702 *
703 * We have to scan the whole hashtable; we can't usefully use hashkeys
704 * to guide probing, since we might get partial matches on tuples with
705 * hashkeys quite unrelated to what we'd get from the given tuple.
706 *
707 * Caller must provide the equality functions to use, since in cross-type
708 * cases these are different from the hashtable's internal functions.
709 */
710static bool
711findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
712 FmgrInfo *eqfunctions)
713{
714 int numCols = hashtable->numCols;
715 AttrNumber *keyColIdx = hashtable->keyColIdx;
716 TupleHashIterator hashiter;
717 TupleHashEntry entry;
718
719 InitTupleHashIterator(hashtable, &hashiter);
720 while ((entry = ScanTupleHashTable(hashtable, &hashiter)) != NULL)
721 {
722 CHECK_FOR_INTERRUPTS();
723
724 ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
725 if (!execTuplesUnequal(slot, hashtable->tableslot,
726 numCols, keyColIdx,
727 eqfunctions,
728 hashtable->tab_collations,
729 hashtable->tempcxt))
730 {
731 TermTupleHashIterator(&hashiter);
732 return true;
733 }
734 }
735 /* No TermTupleHashIterator call needed here */
736 return false;
737}
738
739/*
740 * slotAllNulls: is the slot completely NULL?
741 *
742 * This does not test for dropped columns, which is OK because we only
743 * use it on projected tuples.
744 */
745static bool
746slotAllNulls(TupleTableSlot *slot)
747{
748 int ncols = slot->tts_tupleDescriptor->natts;
749 int i;
750
751 for (i = 1; i <= ncols; i++)
752 {
753 if (!slot_attisnull(slot, i))
754 return false;
755 }
756 return true;
757}
758
759/*
760 * slotNoNulls: is the slot entirely not NULL?
761 *
762 * This does not test for dropped columns, which is OK because we only
763 * use it on projected tuples.
764 */
765static bool
766slotNoNulls(TupleTableSlot *slot)
767{
768 int ncols = slot->tts_tupleDescriptor->natts;
769 int i;
770
771 for (i = 1; i <= ncols; i++)
772 {
773 if (slot_attisnull(slot, i))
774 return false;
775 }
776 return true;
777}
778
779/* ----------------------------------------------------------------
780 * ExecInitSubPlan
781 *
782 * Create a SubPlanState for a SubPlan; this is the SubPlan-specific part
783 * of ExecInitExpr(). We split it out so that it can be used for InitPlans
784 * as well as regular SubPlans. Note that we don't link the SubPlan into
785 * the parent's subPlan list, because that shouldn't happen for InitPlans.
786 * Instead, ExecInitExpr() does that one part.
787 * ----------------------------------------------------------------
788 */
789SubPlanState *
790ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
791{
792 SubPlanState *sstate = makeNode(SubPlanState);
793 EState *estate = parent->state;
794
795 sstate->subplan = subplan;
796
797 /* Link the SubPlanState to already-initialized subplan */
798 sstate->planstate = (PlanState *) list_nth(estate->es_subplanstates,
799 subplan->plan_id - 1);
800
801 /* ... and to its parent's state */
802 sstate->parent = parent;
803
804 /* Initialize subexpressions */
805 sstate->testexpr = ExecInitExpr((Expr *) subplan->testexpr, parent);
806 sstate->args = ExecInitExprList(subplan->args, parent);
807
808 /*
809 * initialize my state
810 */
811 sstate->curTuple = NULL;
812 sstate->curArray = PointerGetDatum(NULL);
813 sstate->projLeft = NULL;
814 sstate->projRight = NULL;
815 sstate->hashtable = NULL;
816 sstate->hashnulls = NULL;
817 sstate->hashtablecxt = NULL;
818 sstate->hashtempcxt = NULL;
819 sstate->innerecontext = NULL;
820 sstate->keyColIdx = NULL;
821 sstate->tab_eq_funcoids = NULL;
822 sstate->tab_hash_funcs = NULL;
823 sstate->tab_eq_funcs = NULL;
824 sstate->tab_collations = NULL;
825 sstate->lhs_hash_funcs = NULL;
826 sstate->cur_eq_funcs = NULL;
827
828 /*
829 * If this is an initplan or MULTIEXPR subplan, it has output parameters
830 * that the parent plan will use, so mark those parameters as needing
831 * evaluation. We don't actually run the subplan until we first need one
832 * of its outputs.
833 *
834 * A CTE subplan's output parameter is never to be evaluated in the normal
835 * way, so skip this in that case.
836 *
837 * Note that we don't set parent->chgParam here: the parent plan hasn't
838 * been run yet, so no need to force it to re-run.
839 */
840 if (subplan->setParam != NIL && subplan->subLinkType != CTE_SUBLINK)
841 {
842 ListCell *lst;
843
844 foreach(lst, subplan->setParam)
845 {
846 int paramid = lfirst_int(lst);
847 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
848
849 prm->execPlan = sstate;
850 }
851 }
852
853 /*
854 * If we are going to hash the subquery output, initialize relevant stuff.
855 * (We don't create the hashtable until needed, though.)
856 */
857 if (subplan->useHashTable)
858 {
859 int ncols,
860 i;
861 TupleDesc tupDescLeft;
862 TupleDesc tupDescRight;
863 Oid *cross_eq_funcoids;
864 TupleTableSlot *slot;
865 List *oplist,
866 *lefttlist,
867 *righttlist;
868 ListCell *l;
869
870 /* We need a memory context to hold the hash table(s) */
871 sstate->hashtablecxt =
872 AllocSetContextCreate(CurrentMemoryContext,
873 "Subplan HashTable Context",
874 ALLOCSET_DEFAULT_SIZES);
875 /* and a small one for the hash tables to use as temp storage */
876 sstate->hashtempcxt =
877 AllocSetContextCreate(CurrentMemoryContext,
878 "Subplan HashTable Temp Context",
879 ALLOCSET_SMALL_SIZES);
880 /* and a short-lived exprcontext for function evaluation */
881 sstate->innerecontext = CreateExprContext(estate);
882 /* Silly little array of column numbers 1..n */
883 ncols = list_length(subplan->paramIds);
884 sstate->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber));
885 for (i = 0; i < ncols; i++)
886 sstate->keyColIdx[i] = i + 1;
887
888 /*
889 * We use ExecProject to evaluate the lefthand and righthand
890 * expression lists and form tuples. (You might think that we could
891 * use the sub-select's output tuples directly, but that is not the
892 * case if we had to insert any run-time coercions of the sub-select's
893 * output datatypes; anyway this avoids storing any resjunk columns
894 * that might be in the sub-select's output.) Run through the
895 * combining expressions to build tlists for the lefthand and
896 * righthand sides.
897 *
898 * We also extract the combining operators themselves to initialize
899 * the equality and hashing functions for the hash tables.
900 */
901 if (IsA(subplan->testexpr, OpExpr))
902 {
903 /* single combining operator */
904 oplist = list_make1(subplan->testexpr);
905 }
906 else if (is_andclause(subplan->testexpr))
907 {
908 /* multiple combining operators */
909 oplist = castNode(BoolExpr, subplan->testexpr)->args;
910 }
911 else
912 {
913 /* shouldn't see anything else in a hashable subplan */
914 elog(ERROR, "unrecognized testexpr type: %d",
915 (int) nodeTag(subplan->testexpr));
916 oplist = NIL; /* keep compiler quiet */
917 }
918 Assert(list_length(oplist) == ncols);
919
920 lefttlist = righttlist = NIL;
921 sstate->tab_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
922 sstate->tab_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
923 sstate->tab_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
924 sstate->tab_collations = (Oid *) palloc(ncols * sizeof(Oid));
925 sstate->lhs_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
926 sstate->cur_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
927 /* we'll need the cross-type equality fns below, but not in sstate */
928 cross_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
929
930 i = 1;
931 foreach(l, oplist)
932 {
933 OpExpr *opexpr = lfirst_node(OpExpr, l);
934 Expr *expr;
935 TargetEntry *tle;
936 Oid rhs_eq_oper;
937 Oid left_hashfn;
938 Oid right_hashfn;
939
940 Assert(list_length(opexpr->args) == 2);
941
942 /* Process lefthand argument */
943 expr = (Expr *) linitial(opexpr->args);
944 tle = makeTargetEntry(expr,
945 i,
946 NULL,
947 false);
948 lefttlist = lappend(lefttlist, tle);
949
950 /* Process righthand argument */
951 expr = (Expr *) lsecond(opexpr->args);
952 tle = makeTargetEntry(expr,
953 i,
954 NULL,
955 false);
956 righttlist = lappend(righttlist, tle);
957
958 /* Lookup the equality function (potentially cross-type) */
959 cross_eq_funcoids[i - 1] = opexpr->opfuncid;
960 fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
961 fmgr_info_set_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
962
963 /* Look up the equality function for the RHS type */
964 if (!get_compatible_hash_operators(opexpr->opno,
965 NULL, &rhs_eq_oper))
966 elog(ERROR, "could not find compatible hash operator for operator %u",
967 opexpr->opno);
968 sstate->tab_eq_funcoids[i - 1] = get_opcode(rhs_eq_oper);
969 fmgr_info(sstate->tab_eq_funcoids[i - 1],
970 &sstate->tab_eq_funcs[i - 1]);
971
972 /* Lookup the associated hash functions */
973 if (!get_op_hash_functions(opexpr->opno,
974 &left_hashfn, &right_hashfn))
975 elog(ERROR, "could not find hash function for hash operator %u",
976 opexpr->opno);
977 fmgr_info(left_hashfn, &sstate->lhs_hash_funcs[i - 1]);
978 fmgr_info(right_hashfn, &sstate->tab_hash_funcs[i - 1]);
979
980 /* Set collation */
981 sstate->tab_collations[i - 1] = opexpr->inputcollid;
982
983 i++;
984 }
985
986 /*
987 * Construct tupdescs, slots and projection nodes for left and right
988 * sides. The lefthand expressions will be evaluated in the parent
989 * plan node's exprcontext, which we don't have access to here.
990 * Fortunately we can just pass NULL for now and fill it in later
991 * (hack alert!). The righthand expressions will be evaluated in our
992 * own innerecontext.
993 */
994 tupDescLeft = ExecTypeFromTL(lefttlist);
995 slot = ExecInitExtraTupleSlot(estate, tupDescLeft, &TTSOpsVirtual);
996 sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
997 NULL,
998 slot,
999 parent,
1000 NULL);
1001
1002 sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist);
1003 slot = ExecInitExtraTupleSlot(estate, tupDescRight, &TTSOpsVirtual);
1004 sstate->projRight = ExecBuildProjectionInfo(righttlist,
1005 sstate->innerecontext,
1006 slot,
1007 sstate->planstate,
1008 NULL);
1009
1010 /*
1011 * Create comparator for lookups of rows in the table (potentially
1012 * cross-type comparisons).
1013 */
1014 sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
1015 &TTSOpsVirtual, &TTSOpsMinimalTuple,
1016 ncols,
1017 sstate->keyColIdx,
1018 cross_eq_funcoids,
1019 sstate->tab_collations,
1020 parent);
1021 }
1022
1023 return sstate;
1024}
1025
1026/* ----------------------------------------------------------------
1027 * ExecSetParamPlan
1028 *
1029 * Executes a subplan and sets its output parameters.
1030 *
1031 * This is called from ExecEvalParamExec() when the value of a PARAM_EXEC
1032 * parameter is requested and the param's execPlan field is set (indicating
1033 * that the param has not yet been evaluated). This allows lazy evaluation
1034 * of initplans: we don't run the subplan until/unless we need its output.
1035 * Note that this routine MUST clear the execPlan fields of the plan's
1036 * output parameters after evaluating them!
1037 *
1038 * The results of this function are stored in the EState associated with the
1039 * ExprContext (particularly, its ecxt_param_exec_vals); any pass-by-ref
1040 * result Datums are allocated in the EState's per-query memory. The passed
1041 * econtext can be any ExprContext belonging to that EState; which one is
1042 * important only to the extent that the ExprContext's per-tuple memory
1043 * context is used to evaluate any parameters passed down to the subplan.
1044 * (Thus in principle, the shorter-lived the ExprContext the better, since
1045 * that data isn't needed after we return. In practice, because initplan
1046 * parameters are never more complex than Vars, Aggrefs, etc, evaluating them
1047 * currently never leaks any memory anyway.)
1048 * ----------------------------------------------------------------
1049 */
1050void
1051ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
1052{
1053 SubPlan *subplan = node->subplan;
1054 PlanState *planstate = node->planstate;
1055 SubLinkType subLinkType = subplan->subLinkType;
1056 EState *estate = planstate->state;
1057 ScanDirection dir = estate->es_direction;
1058 MemoryContext oldcontext;
1059 TupleTableSlot *slot;
1060 ListCell *pvar;
1061 ListCell *l;
1062 bool found = false;
1063 ArrayBuildStateAny *astate = NULL;
1064
1065 if (subLinkType == ANY_SUBLINK ||
1066 subLinkType == ALL_SUBLINK)
1067 elog(ERROR, "ANY/ALL subselect unsupported as initplan");
1068 if (subLinkType == CTE_SUBLINK)
1069 elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
1070
1071 /*
1072 * Enforce forward scan direction regardless of caller. It's hard but not
1073 * impossible to get here in backward scan, so make it work anyway.
1074 */
1075 estate->es_direction = ForwardScanDirection;
1076
1077 /* Initialize ArrayBuildStateAny in caller's context, if needed */
1078 if (subLinkType == ARRAY_SUBLINK)
1079 astate = initArrayResultAny(subplan->firstColType,
1080 CurrentMemoryContext, true);
1081
1082 /*
1083 * Must switch to per-query memory context.
1084 */
1085 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
1086
1087 /*
1088 * Set Params of this plan from parent plan correlation values. (Any
1089 * calculation we have to do is done in the parent econtext, since the
1090 * Param values don't need to have per-query lifetime.) Currently, we
1091 * expect only MULTIEXPR_SUBLINK plans to have any correlation values.
1092 */
1093 Assert(subplan->parParam == NIL || subLinkType == MULTIEXPR_SUBLINK);
1094 Assert(list_length(subplan->parParam) == list_length(node->args));
1095
1096 forboth(l, subplan->parParam, pvar, node->args)
1097 {
1098 int paramid = lfirst_int(l);
1099 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1100
1101 prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
1102 econtext,
1103 &(prm->isnull));
1104 planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
1105 }
1106
1107 /*
1108 * Run the plan. (If it needs to be rescanned, the first ExecProcNode
1109 * call will take care of that.)
1110 */
1111 for (slot = ExecProcNode(planstate);
1112 !TupIsNull(slot);
1113 slot = ExecProcNode(planstate))
1114 {
1115 TupleDesc tdesc = slot->tts_tupleDescriptor;
1116 int i = 1;
1117
1118 if (subLinkType == EXISTS_SUBLINK)
1119 {
1120 /* There can be only one setParam... */
1121 int paramid = linitial_int(subplan->setParam);
1122 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1123
1124 prm->execPlan = NULL;
1125 prm->value = BoolGetDatum(true);
1126 prm->isnull = false;
1127 found = true;
1128 break;
1129 }
1130
1131 if (subLinkType == ARRAY_SUBLINK)
1132 {
1133 Datum dvalue;
1134 bool disnull;
1135
1136 found = true;
1137 /* stash away current value */
1138 Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
1139 dvalue = slot_getattr(slot, 1, &disnull);
1140 astate = accumArrayResultAny(astate, dvalue, disnull,
1141 subplan->firstColType, oldcontext);
1142 /* keep scanning subplan to collect all values */
1143 continue;
1144 }
1145
1146 if (found &&
1147 (subLinkType == EXPR_SUBLINK ||
1148 subLinkType == MULTIEXPR_SUBLINK ||
1149 subLinkType == ROWCOMPARE_SUBLINK))
1150 ereport(ERROR,
1151 (errcode(ERRCODE_CARDINALITY_VIOLATION),
1152 errmsg("more than one row returned by a subquery used as an expression")));
1153
1154 found = true;
1155
1156 /*
1157 * We need to copy the subplan's tuple into our own context, in case
1158 * any of the params are pass-by-ref type --- the pointers stored in
1159 * the param structs will point at this copied tuple! node->curTuple
1160 * keeps track of the copied tuple for eventual freeing.
1161 */
1162 if (node->curTuple)
1163 heap_freetuple(node->curTuple);
1164 node->curTuple = ExecCopySlotHeapTuple(slot);
1165
1166 /*
1167 * Now set all the setParam params from the columns of the tuple
1168 */
1169 foreach(l, subplan->setParam)
1170 {
1171 int paramid = lfirst_int(l);
1172 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1173
1174 prm->execPlan = NULL;
1175 prm->value = heap_getattr(node->curTuple, i, tdesc,
1176 &(prm->isnull));
1177 i++;
1178 }
1179 }
1180
1181 if (subLinkType == ARRAY_SUBLINK)
1182 {
1183 /* There can be only one setParam... */
1184 int paramid = linitial_int(subplan->setParam);
1185 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1186
1187 /*
1188 * We build the result array in query context so it won't disappear;
1189 * to avoid leaking memory across repeated calls, we have to remember
1190 * the latest value, much as for curTuple above.
1191 */
1192 if (node->curArray != PointerGetDatum(NULL))
1193 pfree(DatumGetPointer(node->curArray));
1194 node->curArray = makeArrayResultAny(astate,
1195 econtext->ecxt_per_query_memory,
1196 true);
1197 prm->execPlan = NULL;
1198 prm->value = node->curArray;
1199 prm->isnull = false;
1200 }
1201 else if (!found)
1202 {
1203 if (subLinkType == EXISTS_SUBLINK)
1204 {
1205 /* There can be only one setParam... */
1206 int paramid = linitial_int(subplan->setParam);
1207 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1208
1209 prm->execPlan = NULL;
1210 prm->value = BoolGetDatum(false);
1211 prm->isnull = false;
1212 }
1213 else
1214 {
1215 /* For other sublink types, set all the output params to NULL */
1216 foreach(l, subplan->setParam)
1217 {
1218 int paramid = lfirst_int(l);
1219 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1220
1221 prm->execPlan = NULL;
1222 prm->value = (Datum) 0;
1223 prm->isnull = true;
1224 }
1225 }
1226 }
1227
1228 MemoryContextSwitchTo(oldcontext);
1229
1230 /* restore scan direction */
1231 estate->es_direction = dir;
1232}
1233
1234/*
1235 * ExecSetParamPlanMulti
1236 *
1237 * Apply ExecSetParamPlan to evaluate any not-yet-evaluated initplan output
1238 * parameters whose ParamIDs are listed in "params". Any listed params that
1239 * are not initplan outputs are ignored.
1240 *
1241 * As with ExecSetParamPlan, any ExprContext belonging to the current EState
1242 * can be used, but in principle a shorter-lived ExprContext is better than a
1243 * longer-lived one.
1244 */
1245void
1246ExecSetParamPlanMulti(const Bitmapset *params, ExprContext *econtext)
1247{
1248 int paramid;
1249
1250 paramid = -1;
1251 while ((paramid = bms_next_member(params, paramid)) >= 0)
1252 {
1253 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1254
1255 if (prm->execPlan != NULL)
1256 {
1257 /* Parameter not evaluated yet, so go do it */
1258 ExecSetParamPlan(prm->execPlan, econtext);
1259 /* ExecSetParamPlan should have processed this param... */
1260 Assert(prm->execPlan == NULL);
1261 }
1262 }
1263}
1264
1265/*
1266 * Mark an initplan as needing recalculation
1267 */
1268void
1269ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
1270{
1271 PlanState *planstate = node->planstate;
1272 SubPlan *subplan = node->subplan;
1273 EState *estate = parent->state;
1274 ListCell *l;
1275
1276 /* sanity checks */
1277 if (subplan->parParam != NIL)
1278 elog(ERROR, "direct correlated subquery unsupported as initplan");
1279 if (subplan->setParam == NIL)
1280 elog(ERROR, "setParam list of initplan is empty");
1281 if (bms_is_empty(planstate->plan->extParam))
1282 elog(ERROR, "extParam set of initplan is empty");
1283
1284 /*
1285 * Don't actually re-scan: it'll happen inside ExecSetParamPlan if needed.
1286 */
1287
1288 /*
1289 * Mark this subplan's output parameters as needing recalculation.
1290 *
1291 * CTE subplans are never executed via parameter recalculation; instead
1292 * they get run when called by nodeCtescan.c. So don't mark the output
1293 * parameter of a CTE subplan as dirty, but do set the chgParam bit for it
1294 * so that dependent plan nodes will get told to rescan.
1295 */
1296 foreach(l, subplan->setParam)
1297 {
1298 int paramid = lfirst_int(l);
1299 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
1300
1301 if (subplan->subLinkType != CTE_SUBLINK)
1302 prm->execPlan = node;
1303
1304 parent->chgParam = bms_add_member(parent->chgParam, paramid);
1305 }
1306}
1307
1308
1309/*
1310 * ExecInitAlternativeSubPlan
1311 *
1312 * Initialize for execution of one of a set of alternative subplans.
1313 */
1314AlternativeSubPlanState *
1315ExecInitAlternativeSubPlan(AlternativeSubPlan *asplan, PlanState *parent)
1316{
1317 AlternativeSubPlanState *asstate = makeNode(AlternativeSubPlanState);
1318 double num_calls;
1319 SubPlan *subplan1;
1320 SubPlan *subplan2;
1321 Cost cost1;
1322 Cost cost2;
1323 ListCell *lc;
1324
1325 asstate->subplan = asplan;
1326
1327 /*
1328 * Initialize subplans. (Can we get away with only initializing the one
1329 * we're going to use?)
1330 */
1331 foreach(lc, asplan->subplans)
1332 {
1333 SubPlan *sp = lfirst_node(SubPlan, lc);
1334 SubPlanState *sps = ExecInitSubPlan(sp, parent);
1335
1336 asstate->subplans = lappend(asstate->subplans, sps);
1337 parent->subPlan = lappend(parent->subPlan, sps);
1338 }
1339
1340 /*
1341 * Select the one to be used. For this, we need an estimate of the number
1342 * of executions of the subplan. We use the number of output rows
1343 * expected from the parent plan node. This is a good estimate if we are
1344 * in the parent's targetlist, and an underestimate (but probably not by
1345 * more than a factor of 2) if we are in the qual.
1346 */
1347 num_calls = parent->plan->plan_rows;
1348
1349 /*
1350 * The planner saved enough info so that we don't have to work very hard
1351 * to estimate the total cost, given the number-of-calls estimate.
1352 */
1353 Assert(list_length(asplan->subplans) == 2);
1354 subplan1 = (SubPlan *) linitial(asplan->subplans);
1355 subplan2 = (SubPlan *) lsecond(asplan->subplans);
1356
1357 cost1 = subplan1->startup_cost + num_calls * subplan1->per_call_cost;
1358 cost2 = subplan2->startup_cost + num_calls * subplan2->per_call_cost;
1359
1360 if (cost1 < cost2)
1361 asstate->active = 0;
1362 else
1363 asstate->active = 1;
1364
1365 return asstate;
1366}
1367
1368/*
1369 * ExecAlternativeSubPlan
1370 *
1371 * Execute one of a set of alternative subplans.
1372 *
1373 * Note: in future we might consider changing to different subplans on the
1374 * fly, in case the original rowcount estimate turns out to be way off.
1375 */
1376Datum
1377ExecAlternativeSubPlan(AlternativeSubPlanState *node,
1378 ExprContext *econtext,
1379 bool *isNull)
1380{
1381 /* Just pass control to the active subplan */
1382 SubPlanState *activesp = list_nth_node(SubPlanState,
1383 node->subplans, node->active);
1384
1385 return ExecSubPlan(activesp, econtext, isNull);
1386}
1387