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