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-2018, 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 "miscadmin.h"
37 #include "optimizer/clauses.h"
38 #include "utils/array.h"
39 #include "utils/lsyscache.h"
40 #include "utils/memutils.h"
41
42
43 static Datum ExecHashSubPlan(SubPlanState *node,
44 ExprContext *econtext,
45 bool *isNull);
46 static Datum ExecScanSubPlan(SubPlanState *node,
47 ExprContext *econtext,
48 bool *isNull);
49 static void buildSubPlanHash(SubPlanState *node, ExprContext *econtext);
50 static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
51 FmgrInfo *eqfunctions);
52 static bool slotAllNulls(TupleTableSlot *slot);
53 static 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 */
62 Datum
ExecSubPlan(SubPlanState * node,ExprContext * econtext,bool * isNull)63 ExecSubPlan(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 */
101 static Datum
ExecHashSubPlan(SubPlanState * node,ExprContext * econtext,bool * isNull)102 ExecHashSubPlan(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 */
223 static Datum
ExecScanSubPlan(SubPlanState * node,ExprContext * econtext,bool * isNull)224 ExecScanSubPlan(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 = ExecCopySlotTuple(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 */
470 static void
buildSubPlanHash(SubPlanState * node,ExprContext * econtext)471 buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
472 {
473 SubPlan *subplan = node->subplan;
474 PlanState *planstate = node->planstate;
475 int ncols = node->numCols;
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->havehashrows = false;
500 node->havenullrows = false;
501
502 nbuckets = (long) Min(planstate->plan->plan_rows, (double) LONG_MAX);
503 if (nbuckets < 1)
504 nbuckets = 1;
505
506 if (node->hashtable)
507 ResetTupleHashTable(node->hashtable);
508 else
509 node->hashtable = BuildTupleHashTableExt(node->parent,
510 node->descRight,
511 ncols,
512 node->keyColIdx,
513 node->tab_eq_funcoids,
514 node->tab_hash_funcs,
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 nbuckets,
543 0,
544 node->planstate->state->es_query_cxt,
545 node->hashtablecxt,
546 node->hashtempcxt,
547 false);
548 }
549 else
550 node->hashnulls = NULL;
551
552 /*
553 * We are probably in a short-lived expression-evaluation context. Switch
554 * to the per-query context for manipulating the child plan.
555 */
556 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
557
558 /*
559 * Reset subplan to start.
560 */
561 ExecReScan(planstate);
562
563 /*
564 * Scan the subplan and load the hash table(s). Note that when there are
565 * duplicate rows coming out of the sub-select, only one copy is stored.
566 */
567 for (slot = ExecProcNode(planstate);
568 !TupIsNull(slot);
569 slot = ExecProcNode(planstate))
570 {
571 int col = 1;
572 ListCell *plst;
573 bool isnew;
574
575 /*
576 * Load up the Params representing the raw sub-select outputs, then
577 * form the projection tuple to store in the hashtable.
578 */
579 foreach(plst, subplan->paramIds)
580 {
581 int paramid = lfirst_int(plst);
582 ParamExecData *prmdata;
583
584 prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
585 Assert(prmdata->execPlan == NULL);
586 prmdata->value = slot_getattr(slot, col,
587 &(prmdata->isnull));
588 col++;
589 }
590 slot = ExecProject(node->projRight);
591
592 /*
593 * If result contains any nulls, store separately or not at all.
594 */
595 if (slotNoNulls(slot))
596 {
597 (void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
598 node->havehashrows = true;
599 }
600 else if (node->hashnulls)
601 {
602 (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
603 node->havenullrows = true;
604 }
605
606 /*
607 * Reset innerecontext after each inner tuple to free any memory used
608 * during ExecProject.
609 */
610 ResetExprContext(innerecontext);
611 }
612
613 /*
614 * Since the projected tuples are in the sub-query's context and not the
615 * main context, we'd better clear the tuple slot before there's any
616 * chance of a reset of the sub-query's context. Else we will have the
617 * potential for a double free attempt. (XXX possibly no longer needed,
618 * but can't hurt.)
619 */
620 ExecClearTuple(node->projRight->pi_state.resultslot);
621
622 MemoryContextSwitchTo(oldcontext);
623 }
624
625 /*
626 * execTuplesUnequal
627 * Return true if two tuples are definitely unequal in the indicated
628 * fields.
629 *
630 * Nulls are neither equal nor unequal to anything else. A true result
631 * is obtained only if there are non-null fields that compare not-equal.
632 *
633 * slot1, slot2: the tuples to compare (must have same columns!)
634 * numCols: the number of attributes to be examined
635 * matchColIdx: array of attribute column numbers
636 * eqFunctions: array of fmgr lookup info for the equality functions to use
637 * evalContext: short-term memory context for executing the functions
638 */
639 static bool
execTuplesUnequal(TupleTableSlot * slot1,TupleTableSlot * slot2,int numCols,AttrNumber * matchColIdx,FmgrInfo * eqfunctions,MemoryContext evalContext)640 execTuplesUnequal(TupleTableSlot *slot1,
641 TupleTableSlot *slot2,
642 int numCols,
643 AttrNumber *matchColIdx,
644 FmgrInfo *eqfunctions,
645 MemoryContext evalContext)
646 {
647 MemoryContext oldContext;
648 bool result;
649 int i;
650
651 /* Reset and switch into the temp context. */
652 MemoryContextReset(evalContext);
653 oldContext = MemoryContextSwitchTo(evalContext);
654
655 /*
656 * We cannot report a match without checking all the fields, but we can
657 * report a non-match as soon as we find unequal fields. So, start
658 * comparing at the last field (least significant sort key). That's the
659 * most likely to be different if we are dealing with sorted input.
660 */
661 result = false;
662
663 for (i = numCols; --i >= 0;)
664 {
665 AttrNumber att = matchColIdx[i];
666 Datum attr1,
667 attr2;
668 bool isNull1,
669 isNull2;
670
671 attr1 = slot_getattr(slot1, att, &isNull1);
672
673 if (isNull1)
674 continue; /* can't prove anything here */
675
676 attr2 = slot_getattr(slot2, att, &isNull2);
677
678 if (isNull2)
679 continue; /* can't prove anything here */
680
681 /* Apply the type-specific equality function */
682
683 if (!DatumGetBool(FunctionCall2(&eqfunctions[i],
684 attr1, attr2)))
685 {
686 result = true; /* they are unequal */
687 break;
688 }
689 }
690
691 MemoryContextSwitchTo(oldContext);
692
693 return result;
694 }
695
696 /*
697 * findPartialMatch: does the hashtable contain an entry that is not
698 * provably distinct from the tuple?
699 *
700 * We have to scan the whole hashtable; we can't usefully use hashkeys
701 * to guide probing, since we might get partial matches on tuples with
702 * hashkeys quite unrelated to what we'd get from the given tuple.
703 *
704 * Caller must provide the equality functions to use, since in cross-type
705 * cases these are different from the hashtable's internal functions.
706 */
707 static bool
findPartialMatch(TupleHashTable hashtable,TupleTableSlot * slot,FmgrInfo * eqfunctions)708 findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
709 FmgrInfo *eqfunctions)
710 {
711 int numCols = hashtable->numCols;
712 AttrNumber *keyColIdx = hashtable->keyColIdx;
713 TupleHashIterator hashiter;
714 TupleHashEntry entry;
715
716 InitTupleHashIterator(hashtable, &hashiter);
717 while ((entry = ScanTupleHashTable(hashtable, &hashiter)) != NULL)
718 {
719 CHECK_FOR_INTERRUPTS();
720
721 ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
722 if (!execTuplesUnequal(slot, hashtable->tableslot,
723 numCols, keyColIdx,
724 eqfunctions,
725 hashtable->tempcxt))
726 {
727 TermTupleHashIterator(&hashiter);
728 return true;
729 }
730 }
731 /* No TermTupleHashIterator call needed here */
732 return false;
733 }
734
735 /*
736 * slotAllNulls: is the slot completely NULL?
737 *
738 * This does not test for dropped columns, which is OK because we only
739 * use it on projected tuples.
740 */
741 static bool
slotAllNulls(TupleTableSlot * slot)742 slotAllNulls(TupleTableSlot *slot)
743 {
744 int ncols = slot->tts_tupleDescriptor->natts;
745 int i;
746
747 for (i = 1; i <= ncols; i++)
748 {
749 if (!slot_attisnull(slot, i))
750 return false;
751 }
752 return true;
753 }
754
755 /*
756 * slotNoNulls: is the slot entirely not NULL?
757 *
758 * This does not test for dropped columns, which is OK because we only
759 * use it on projected tuples.
760 */
761 static bool
slotNoNulls(TupleTableSlot * slot)762 slotNoNulls(TupleTableSlot *slot)
763 {
764 int ncols = slot->tts_tupleDescriptor->natts;
765 int i;
766
767 for (i = 1; i <= ncols; i++)
768 {
769 if (slot_attisnull(slot, i))
770 return false;
771 }
772 return true;
773 }
774
775 /* ----------------------------------------------------------------
776 * ExecInitSubPlan
777 *
778 * Create a SubPlanState for a SubPlan; this is the SubPlan-specific part
779 * of ExecInitExpr(). We split it out so that it can be used for InitPlans
780 * as well as regular SubPlans. Note that we don't link the SubPlan into
781 * the parent's subPlan list, because that shouldn't happen for InitPlans.
782 * Instead, ExecInitExpr() does that one part.
783 * ----------------------------------------------------------------
784 */
785 SubPlanState *
ExecInitSubPlan(SubPlan * subplan,PlanState * parent)786 ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
787 {
788 SubPlanState *sstate = makeNode(SubPlanState);
789 EState *estate = parent->state;
790
791 sstate->subplan = subplan;
792
793 /* Link the SubPlanState to already-initialized subplan */
794 sstate->planstate = (PlanState *) list_nth(estate->es_subplanstates,
795 subplan->plan_id - 1);
796
797 /*
798 * This check can fail if the planner mistakenly puts a parallel-unsafe
799 * subplan into a parallelized subquery; see ExecSerializePlan.
800 */
801 if (sstate->planstate == NULL)
802 elog(ERROR, "subplan \"%s\" was not initialized",
803 subplan->plan_name);
804
805 /* Link to parent's state, too */
806 sstate->parent = parent;
807
808 /* Initialize subexpressions */
809 sstate->testexpr = ExecInitExpr((Expr *) subplan->testexpr, parent);
810 sstate->args = ExecInitExprList(subplan->args, parent);
811
812 /*
813 * initialize my state
814 */
815 sstate->curTuple = NULL;
816 sstate->curArray = PointerGetDatum(NULL);
817 sstate->projLeft = NULL;
818 sstate->projRight = NULL;
819 sstate->hashtable = NULL;
820 sstate->hashnulls = NULL;
821 sstate->hashtablecxt = NULL;
822 sstate->hashtempcxt = NULL;
823 sstate->innerecontext = NULL;
824 sstate->keyColIdx = NULL;
825 sstate->tab_eq_funcoids = NULL;
826 sstate->tab_hash_funcs = NULL;
827 sstate->tab_eq_funcs = NULL;
828 sstate->lhs_hash_funcs = NULL;
829 sstate->cur_eq_funcs = NULL;
830
831 /*
832 * If this is an initplan or MULTIEXPR subplan, it has output parameters
833 * that the parent plan will use, so mark those parameters as needing
834 * evaluation. We don't actually run the subplan until we first need one
835 * of its outputs.
836 *
837 * A CTE subplan's output parameter is never to be evaluated in the normal
838 * way, so skip this in that case.
839 *
840 * Note that we don't set parent->chgParam here: the parent plan hasn't
841 * been run yet, so no need to force it to re-run.
842 */
843 if (subplan->setParam != NIL && subplan->subLinkType != CTE_SUBLINK)
844 {
845 ListCell *lst;
846
847 foreach(lst, subplan->setParam)
848 {
849 int paramid = lfirst_int(lst);
850 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
851
852 prm->execPlan = sstate;
853 }
854 }
855
856 /*
857 * If we are going to hash the subquery output, initialize relevant stuff.
858 * (We don't create the hashtable until needed, though.)
859 */
860 if (subplan->useHashTable)
861 {
862 int ncols,
863 i;
864 TupleDesc tupDescLeft;
865 TupleDesc tupDescRight;
866 Oid *cross_eq_funcoids;
867 TupleTableSlot *slot;
868 List *oplist,
869 *lefttlist,
870 *righttlist;
871 ListCell *l;
872
873 /* We need a memory context to hold the hash table(s) */
874 sstate->hashtablecxt =
875 AllocSetContextCreate(CurrentMemoryContext,
876 "Subplan HashTable Context",
877 ALLOCSET_DEFAULT_SIZES);
878 /* and a small one for the hash tables to use as temp storage */
879 sstate->hashtempcxt =
880 AllocSetContextCreate(CurrentMemoryContext,
881 "Subplan HashTable Temp Context",
882 ALLOCSET_SMALL_SIZES);
883 /* and a short-lived exprcontext for function evaluation */
884 sstate->innerecontext = CreateExprContext(estate);
885
886 /*
887 * We use ExecProject to evaluate the lefthand and righthand
888 * expression lists and form tuples. (You might think that we could
889 * use the sub-select's output tuples directly, but that is not the
890 * case if we had to insert any run-time coercions of the sub-select's
891 * output datatypes; anyway this avoids storing any resjunk columns
892 * that might be in the sub-select's output.) Run through the
893 * combining expressions to build tlists for the lefthand and
894 * righthand sides.
895 *
896 * We also extract the combining operators themselves to initialize
897 * the equality and hashing functions for the hash tables.
898 */
899 if (IsA(subplan->testexpr, OpExpr))
900 {
901 /* single combining operator */
902 oplist = list_make1(subplan->testexpr);
903 }
904 else if (and_clause((Node *) subplan->testexpr))
905 {
906 /* multiple combining operators */
907 oplist = castNode(BoolExpr, subplan->testexpr)->args;
908 }
909 else
910 {
911 /* shouldn't see anything else in a hashable subplan */
912 elog(ERROR, "unrecognized testexpr type: %d",
913 (int) nodeTag(subplan->testexpr));
914 oplist = NIL; /* keep compiler quiet */
915 }
916 ncols = list_length(oplist);
917
918 lefttlist = righttlist = NIL;
919 sstate->numCols = ncols;
920 sstate->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber));
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->lhs_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
925 sstate->cur_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
926 /* we'll need the cross-type equality fns below, but not in sstate */
927 cross_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
928
929 i = 1;
930 foreach(l, oplist)
931 {
932 OpExpr *opexpr = lfirst_node(OpExpr, l);
933 Expr *expr;
934 TargetEntry *tle;
935 Oid rhs_eq_oper;
936 Oid left_hashfn;
937 Oid right_hashfn;
938
939 Assert(list_length(opexpr->args) == 2);
940
941 /* Process lefthand argument */
942 expr = (Expr *) linitial(opexpr->args);
943 tle = makeTargetEntry(expr,
944 i,
945 NULL,
946 false);
947 lefttlist = lappend(lefttlist, tle);
948
949 /* Process righthand argument */
950 expr = (Expr *) lsecond(opexpr->args);
951 tle = makeTargetEntry(expr,
952 i,
953 NULL,
954 false);
955 righttlist = lappend(righttlist, tle);
956
957 /* Lookup the equality function (potentially cross-type) */
958 cross_eq_funcoids[i - 1] = opexpr->opfuncid;
959 fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
960 fmgr_info_set_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
961
962 /* Look up the equality function for the RHS type */
963 if (!get_compatible_hash_operators(opexpr->opno,
964 NULL, &rhs_eq_oper))
965 elog(ERROR, "could not find compatible hash operator for operator %u",
966 opexpr->opno);
967 sstate->tab_eq_funcoids[i - 1] = get_opcode(rhs_eq_oper);
968 fmgr_info(sstate->tab_eq_funcoids[i - 1],
969 &sstate->tab_eq_funcs[i - 1]);
970
971 /* Lookup the associated hash functions */
972 if (!get_op_hash_functions(opexpr->opno,
973 &left_hashfn, &right_hashfn))
974 elog(ERROR, "could not find hash function for hash operator %u",
975 opexpr->opno);
976 fmgr_info(left_hashfn, &sstate->lhs_hash_funcs[i - 1]);
977 fmgr_info(right_hashfn, &sstate->tab_hash_funcs[i - 1]);
978
979 /* keyColIdx is just column numbers 1..n */
980 sstate->keyColIdx[i - 1] = i;
981
982 i++;
983 }
984
985 /*
986 * Construct tupdescs, slots and projection nodes for left and right
987 * sides. The lefthand expressions will be evaluated in the parent
988 * plan node's exprcontext, which we don't have access to here.
989 * Fortunately we can just pass NULL for now and fill it in later
990 * (hack alert!). The righthand expressions will be evaluated in our
991 * own innerecontext.
992 */
993 tupDescLeft = ExecTypeFromTL(lefttlist, false);
994 slot = ExecInitExtraTupleSlot(estate, tupDescLeft);
995 sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
996 NULL,
997 slot,
998 parent,
999 NULL);
1000
1001 sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist, false);
1002 slot = ExecInitExtraTupleSlot(estate, tupDescRight);
1003 sstate->projRight = ExecBuildProjectionInfo(righttlist,
1004 sstate->innerecontext,
1005 slot,
1006 sstate->planstate,
1007 NULL);
1008
1009 /*
1010 * Create comparator for lookups of rows in the table (potentially
1011 * cross-type comparisons).
1012 */
1013 sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
1014 ncols,
1015 sstate->keyColIdx,
1016 cross_eq_funcoids,
1017 parent);
1018 }
1019
1020 return sstate;
1021 }
1022
1023 /* ----------------------------------------------------------------
1024 * ExecSetParamPlan
1025 *
1026 * Executes a subplan and sets its output parameters.
1027 *
1028 * This is called from ExecEvalParamExec() when the value of a PARAM_EXEC
1029 * parameter is requested and the param's execPlan field is set (indicating
1030 * that the param has not yet been evaluated). This allows lazy evaluation
1031 * of initplans: we don't run the subplan until/unless we need its output.
1032 * Note that this routine MUST clear the execPlan fields of the plan's
1033 * output parameters after evaluating them!
1034 *
1035 * The results of this function are stored in the EState associated with the
1036 * ExprContext (particularly, its ecxt_param_exec_vals); any pass-by-ref
1037 * result Datums are allocated in the EState's per-query memory. The passed
1038 * econtext can be any ExprContext belonging to that EState; which one is
1039 * important only to the extent that the ExprContext's per-tuple memory
1040 * context is used to evaluate any parameters passed down to the subplan.
1041 * (Thus in principle, the shorter-lived the ExprContext the better, since
1042 * that data isn't needed after we return. In practice, because initplan
1043 * parameters are never more complex than Vars, Aggrefs, etc, evaluating them
1044 * currently never leaks any memory anyway.)
1045 * ----------------------------------------------------------------
1046 */
1047 void
ExecSetParamPlan(SubPlanState * node,ExprContext * econtext)1048 ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
1049 {
1050 SubPlan *subplan = node->subplan;
1051 PlanState *planstate = node->planstate;
1052 SubLinkType subLinkType = subplan->subLinkType;
1053 EState *estate = planstate->state;
1054 ScanDirection dir = estate->es_direction;
1055 MemoryContext oldcontext;
1056 TupleTableSlot *slot;
1057 ListCell *pvar;
1058 ListCell *l;
1059 bool found = false;
1060 ArrayBuildStateAny *astate = NULL;
1061
1062 if (subLinkType == ANY_SUBLINK ||
1063 subLinkType == ALL_SUBLINK)
1064 elog(ERROR, "ANY/ALL subselect unsupported as initplan");
1065 if (subLinkType == CTE_SUBLINK)
1066 elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
1067
1068 /*
1069 * Enforce forward scan direction regardless of caller. It's hard but not
1070 * impossible to get here in backward scan, so make it work anyway.
1071 */
1072 estate->es_direction = ForwardScanDirection;
1073
1074 /* Initialize ArrayBuildStateAny in caller's context, if needed */
1075 if (subLinkType == ARRAY_SUBLINK)
1076 astate = initArrayResultAny(subplan->firstColType,
1077 CurrentMemoryContext, true);
1078
1079 /*
1080 * Must switch to per-query memory context.
1081 */
1082 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
1083
1084 /*
1085 * Set Params of this plan from parent plan correlation values. (Any
1086 * calculation we have to do is done in the parent econtext, since the
1087 * Param values don't need to have per-query lifetime.) Currently, we
1088 * expect only MULTIEXPR_SUBLINK plans to have any correlation values.
1089 */
1090 Assert(subplan->parParam == NIL || subLinkType == MULTIEXPR_SUBLINK);
1091 Assert(list_length(subplan->parParam) == list_length(node->args));
1092
1093 forboth(l, subplan->parParam, pvar, node->args)
1094 {
1095 int paramid = lfirst_int(l);
1096 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1097
1098 prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
1099 econtext,
1100 &(prm->isnull));
1101 planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
1102 }
1103
1104 /*
1105 * Run the plan. (If it needs to be rescanned, the first ExecProcNode
1106 * call will take care of that.)
1107 */
1108 for (slot = ExecProcNode(planstate);
1109 !TupIsNull(slot);
1110 slot = ExecProcNode(planstate))
1111 {
1112 TupleDesc tdesc = slot->tts_tupleDescriptor;
1113 int i = 1;
1114
1115 if (subLinkType == EXISTS_SUBLINK)
1116 {
1117 /* There can be only one setParam... */
1118 int paramid = linitial_int(subplan->setParam);
1119 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1120
1121 prm->execPlan = NULL;
1122 prm->value = BoolGetDatum(true);
1123 prm->isnull = false;
1124 found = true;
1125 break;
1126 }
1127
1128 if (subLinkType == ARRAY_SUBLINK)
1129 {
1130 Datum dvalue;
1131 bool disnull;
1132
1133 found = true;
1134 /* stash away current value */
1135 Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
1136 dvalue = slot_getattr(slot, 1, &disnull);
1137 astate = accumArrayResultAny(astate, dvalue, disnull,
1138 subplan->firstColType, oldcontext);
1139 /* keep scanning subplan to collect all values */
1140 continue;
1141 }
1142
1143 if (found &&
1144 (subLinkType == EXPR_SUBLINK ||
1145 subLinkType == MULTIEXPR_SUBLINK ||
1146 subLinkType == ROWCOMPARE_SUBLINK))
1147 ereport(ERROR,
1148 (errcode(ERRCODE_CARDINALITY_VIOLATION),
1149 errmsg("more than one row returned by a subquery used as an expression")));
1150
1151 found = true;
1152
1153 /*
1154 * We need to copy the subplan's tuple into our own context, in case
1155 * any of the params are pass-by-ref type --- the pointers stored in
1156 * the param structs will point at this copied tuple! node->curTuple
1157 * keeps track of the copied tuple for eventual freeing.
1158 */
1159 if (node->curTuple)
1160 heap_freetuple(node->curTuple);
1161 node->curTuple = ExecCopySlotTuple(slot);
1162
1163 /*
1164 * Now set all the setParam params from the columns of the tuple
1165 */
1166 foreach(l, subplan->setParam)
1167 {
1168 int paramid = lfirst_int(l);
1169 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1170
1171 prm->execPlan = NULL;
1172 prm->value = heap_getattr(node->curTuple, i, tdesc,
1173 &(prm->isnull));
1174 i++;
1175 }
1176 }
1177
1178 if (subLinkType == ARRAY_SUBLINK)
1179 {
1180 /* There can be only one setParam... */
1181 int paramid = linitial_int(subplan->setParam);
1182 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1183
1184 /*
1185 * We build the result array in query context so it won't disappear;
1186 * to avoid leaking memory across repeated calls, we have to remember
1187 * the latest value, much as for curTuple above.
1188 */
1189 if (node->curArray != PointerGetDatum(NULL))
1190 pfree(DatumGetPointer(node->curArray));
1191 node->curArray = makeArrayResultAny(astate,
1192 econtext->ecxt_per_query_memory,
1193 true);
1194 prm->execPlan = NULL;
1195 prm->value = node->curArray;
1196 prm->isnull = false;
1197 }
1198 else if (!found)
1199 {
1200 if (subLinkType == EXISTS_SUBLINK)
1201 {
1202 /* There can be only one setParam... */
1203 int paramid = linitial_int(subplan->setParam);
1204 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1205
1206 prm->execPlan = NULL;
1207 prm->value = BoolGetDatum(false);
1208 prm->isnull = false;
1209 }
1210 else
1211 {
1212 /* For other sublink types, set all the output params to NULL */
1213 foreach(l, subplan->setParam)
1214 {
1215 int paramid = lfirst_int(l);
1216 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1217
1218 prm->execPlan = NULL;
1219 prm->value = (Datum) 0;
1220 prm->isnull = true;
1221 }
1222 }
1223 }
1224
1225 MemoryContextSwitchTo(oldcontext);
1226
1227 /* restore scan direction */
1228 estate->es_direction = dir;
1229 }
1230
1231 /*
1232 * ExecSetParamPlanMulti
1233 *
1234 * Apply ExecSetParamPlan to evaluate any not-yet-evaluated initplan output
1235 * parameters whose ParamIDs are listed in "params". Any listed params that
1236 * are not initplan outputs are ignored.
1237 *
1238 * As with ExecSetParamPlan, any ExprContext belonging to the current EState
1239 * can be used, but in principle a shorter-lived ExprContext is better than a
1240 * longer-lived one.
1241 */
1242 void
ExecSetParamPlanMulti(const Bitmapset * params,ExprContext * econtext)1243 ExecSetParamPlanMulti(const Bitmapset *params, ExprContext *econtext)
1244 {
1245 int paramid;
1246
1247 paramid = -1;
1248 while ((paramid = bms_next_member(params, paramid)) >= 0)
1249 {
1250 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1251
1252 if (prm->execPlan != NULL)
1253 {
1254 /* Parameter not evaluated yet, so go do it */
1255 ExecSetParamPlan(prm->execPlan, econtext);
1256 /* ExecSetParamPlan should have processed this param... */
1257 Assert(prm->execPlan == NULL);
1258 }
1259 }
1260 }
1261
1262 /*
1263 * Mark an initplan as needing recalculation
1264 */
1265 void
ExecReScanSetParamPlan(SubPlanState * node,PlanState * parent)1266 ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
1267 {
1268 PlanState *planstate = node->planstate;
1269 SubPlan *subplan = node->subplan;
1270 EState *estate = parent->state;
1271 ListCell *l;
1272
1273 /* sanity checks */
1274 if (subplan->parParam != NIL)
1275 elog(ERROR, "direct correlated subquery unsupported as initplan");
1276 if (subplan->setParam == NIL)
1277 elog(ERROR, "setParam list of initplan is empty");
1278 if (bms_is_empty(planstate->plan->extParam))
1279 elog(ERROR, "extParam set of initplan is empty");
1280
1281 /*
1282 * Don't actually re-scan: it'll happen inside ExecSetParamPlan if needed.
1283 */
1284
1285 /*
1286 * Mark this subplan's output parameters as needing recalculation.
1287 *
1288 * CTE subplans are never executed via parameter recalculation; instead
1289 * they get run when called by nodeCtescan.c. So don't mark the output
1290 * parameter of a CTE subplan as dirty, but do set the chgParam bit for it
1291 * so that dependent plan nodes will get told to rescan.
1292 */
1293 foreach(l, subplan->setParam)
1294 {
1295 int paramid = lfirst_int(l);
1296 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
1297
1298 if (subplan->subLinkType != CTE_SUBLINK)
1299 prm->execPlan = node;
1300
1301 parent->chgParam = bms_add_member(parent->chgParam, paramid);
1302 }
1303 }
1304
1305
1306 /*
1307 * ExecInitAlternativeSubPlan
1308 *
1309 * Initialize for execution of one of a set of alternative subplans.
1310 */
1311 AlternativeSubPlanState *
ExecInitAlternativeSubPlan(AlternativeSubPlan * asplan,PlanState * parent)1312 ExecInitAlternativeSubPlan(AlternativeSubPlan *asplan, PlanState *parent)
1313 {
1314 AlternativeSubPlanState *asstate = makeNode(AlternativeSubPlanState);
1315 double num_calls;
1316 SubPlan *subplan1;
1317 SubPlan *subplan2;
1318 Cost cost1;
1319 Cost cost2;
1320 ListCell *lc;
1321
1322 asstate->subplan = asplan;
1323
1324 /*
1325 * Initialize subplans. (Can we get away with only initializing the one
1326 * we're going to use?)
1327 */
1328 foreach(lc, asplan->subplans)
1329 {
1330 SubPlan *sp = lfirst_node(SubPlan, lc);
1331 SubPlanState *sps = ExecInitSubPlan(sp, parent);
1332
1333 asstate->subplans = lappend(asstate->subplans, sps);
1334 parent->subPlan = lappend(parent->subPlan, sps);
1335 }
1336
1337 /*
1338 * Select the one to be used. For this, we need an estimate of the number
1339 * of executions of the subplan. We use the number of output rows
1340 * expected from the parent plan node. This is a good estimate if we are
1341 * in the parent's targetlist, and an underestimate (but probably not by
1342 * more than a factor of 2) if we are in the qual.
1343 */
1344 num_calls = parent->plan->plan_rows;
1345
1346 /*
1347 * The planner saved enough info so that we don't have to work very hard
1348 * to estimate the total cost, given the number-of-calls estimate.
1349 */
1350 Assert(list_length(asplan->subplans) == 2);
1351 subplan1 = (SubPlan *) linitial(asplan->subplans);
1352 subplan2 = (SubPlan *) lsecond(asplan->subplans);
1353
1354 cost1 = subplan1->startup_cost + num_calls * subplan1->per_call_cost;
1355 cost2 = subplan2->startup_cost + num_calls * subplan2->per_call_cost;
1356
1357 if (cost1 < cost2)
1358 asstate->active = 0;
1359 else
1360 asstate->active = 1;
1361
1362 return asstate;
1363 }
1364
1365 /*
1366 * ExecAlternativeSubPlan
1367 *
1368 * Execute one of a set of alternative subplans.
1369 *
1370 * Note: in future we might consider changing to different subplans on the
1371 * fly, in case the original rowcount estimate turns out to be way off.
1372 */
1373 Datum
ExecAlternativeSubPlan(AlternativeSubPlanState * node,ExprContext * econtext,bool * isNull)1374 ExecAlternativeSubPlan(AlternativeSubPlanState *node,
1375 ExprContext *econtext,
1376 bool *isNull)
1377 {
1378 /* Just pass control to the active subplan */
1379 SubPlanState *activesp = list_nth_node(SubPlanState,
1380 node->subplans, node->active);
1381
1382 return ExecSubPlan(activesp, econtext, isNull);
1383 }
1384