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 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 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 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 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 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 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 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 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 * 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 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 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 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 * 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 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