00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "postgres.h"
00020
00021 #include <limits.h>
00022 #include <math.h>
00023
00024 #include "access/htup_details.h"
00025 #include "executor/executor.h"
00026 #include "executor/nodeSubplan.h"
00027 #include "nodes/makefuncs.h"
00028 #include "optimizer/clauses.h"
00029 #include "utils/array.h"
00030 #include "utils/lsyscache.h"
00031 #include "utils/memutils.h"
00032
00033
00034 static Datum ExecSubPlan(SubPlanState *node,
00035 ExprContext *econtext,
00036 bool *isNull,
00037 ExprDoneCond *isDone);
00038 static Datum ExecAlternativeSubPlan(AlternativeSubPlanState *node,
00039 ExprContext *econtext,
00040 bool *isNull,
00041 ExprDoneCond *isDone);
00042 static Datum ExecHashSubPlan(SubPlanState *node,
00043 ExprContext *econtext,
00044 bool *isNull);
00045 static Datum ExecScanSubPlan(SubPlanState *node,
00046 ExprContext *econtext,
00047 bool *isNull);
00048 static void buildSubPlanHash(SubPlanState *node, ExprContext *econtext);
00049 static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
00050 FmgrInfo *eqfunctions);
00051 static bool slotAllNulls(TupleTableSlot *slot);
00052 static bool slotNoNulls(TupleTableSlot *slot);
00053
00054
00055
00056
00057
00058
00059 static Datum
00060 ExecSubPlan(SubPlanState *node,
00061 ExprContext *econtext,
00062 bool *isNull,
00063 ExprDoneCond *isDone)
00064 {
00065 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
00066
00067
00068 *isNull = false;
00069 if (isDone)
00070 *isDone = ExprSingleResult;
00071
00072
00073 if (subplan->subLinkType == CTE_SUBLINK)
00074 elog(ERROR, "CTE subplans should not be executed via ExecSubPlan");
00075 if (subplan->setParam != NIL)
00076 elog(ERROR, "cannot set parent params from subquery");
00077
00078
00079 if (subplan->useHashTable)
00080 return ExecHashSubPlan(node, econtext, isNull);
00081 else
00082 return ExecScanSubPlan(node, econtext, isNull);
00083 }
00084
00085
00086
00087
00088 static Datum
00089 ExecHashSubPlan(SubPlanState *node,
00090 ExprContext *econtext,
00091 bool *isNull)
00092 {
00093 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
00094 PlanState *planstate = node->planstate;
00095 TupleTableSlot *slot;
00096
00097
00098 if (subplan->parParam != NIL || node->args != NIL)
00099 elog(ERROR, "hashed subplan with direct correlation not supported");
00100
00101
00102
00103
00104
00105 if (node->hashtable == NULL || planstate->chgParam != NULL)
00106 buildSubPlanHash(node, econtext);
00107
00108
00109
00110
00111
00112 *isNull = false;
00113 if (!node->havehashrows && !node->havenullrows)
00114 return BoolGetDatum(false);
00115
00116
00117
00118
00119
00120 node->projLeft->pi_exprContext = econtext;
00121 slot = ExecProject(node->projLeft, NULL);
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 if (slotNoNulls(slot))
00146 {
00147 if (node->havehashrows &&
00148 FindTupleHashEntry(node->hashtable,
00149 slot,
00150 node->cur_eq_funcs,
00151 node->lhs_hash_funcs) != NULL)
00152 {
00153 ExecClearTuple(slot);
00154 return BoolGetDatum(true);
00155 }
00156 if (node->havenullrows &&
00157 findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
00158 {
00159 ExecClearTuple(slot);
00160 *isNull = true;
00161 return BoolGetDatum(false);
00162 }
00163 ExecClearTuple(slot);
00164 return BoolGetDatum(false);
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 if (node->hashnulls == NULL)
00178 {
00179 ExecClearTuple(slot);
00180 return BoolGetDatum(false);
00181 }
00182 if (slotAllNulls(slot))
00183 {
00184 ExecClearTuple(slot);
00185 *isNull = true;
00186 return BoolGetDatum(false);
00187 }
00188
00189 if (node->havenullrows &&
00190 findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
00191 {
00192 ExecClearTuple(slot);
00193 *isNull = true;
00194 return BoolGetDatum(false);
00195 }
00196 if (node->havehashrows &&
00197 findPartialMatch(node->hashtable, slot, node->cur_eq_funcs))
00198 {
00199 ExecClearTuple(slot);
00200 *isNull = true;
00201 return BoolGetDatum(false);
00202 }
00203 ExecClearTuple(slot);
00204 return BoolGetDatum(false);
00205 }
00206
00207
00208
00209
00210 static Datum
00211 ExecScanSubPlan(SubPlanState *node,
00212 ExprContext *econtext,
00213 bool *isNull)
00214 {
00215 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
00216 PlanState *planstate = node->planstate;
00217 SubLinkType subLinkType = subplan->subLinkType;
00218 MemoryContext oldcontext;
00219 TupleTableSlot *slot;
00220 Datum result;
00221 bool found = false;
00222 ListCell *pvar;
00223 ListCell *l;
00224 ArrayBuildState *astate = NULL;
00225
00226
00227
00228
00229
00230
00231 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
00232
00233
00234
00235
00236
00237
00238 Assert(list_length(subplan->parParam) == list_length(node->args));
00239
00240 forboth(l, subplan->parParam, pvar, node->args)
00241 {
00242 int paramid = lfirst_int(l);
00243 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
00244
00245 prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
00246 econtext,
00247 &(prm->isnull),
00248 NULL);
00249 planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
00250 }
00251
00252
00253
00254
00255 ExecReScan(planstate);
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 result = BoolGetDatum(subLinkType == ALL_SUBLINK);
00279 *isNull = false;
00280
00281 for (slot = ExecProcNode(planstate);
00282 !TupIsNull(slot);
00283 slot = ExecProcNode(planstate))
00284 {
00285 TupleDesc tdesc = slot->tts_tupleDescriptor;
00286 Datum rowresult;
00287 bool rownull;
00288 int col;
00289 ListCell *plst;
00290
00291 if (subLinkType == EXISTS_SUBLINK)
00292 {
00293 found = true;
00294 result = BoolGetDatum(true);
00295 break;
00296 }
00297
00298 if (subLinkType == EXPR_SUBLINK)
00299 {
00300
00301 if (found)
00302 ereport(ERROR,
00303 (errcode(ERRCODE_CARDINALITY_VIOLATION),
00304 errmsg("more than one row returned by a subquery used as an expression")));
00305 found = true;
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315 if (node->curTuple)
00316 heap_freetuple(node->curTuple);
00317 node->curTuple = ExecCopySlotTuple(slot);
00318
00319 result = heap_getattr(node->curTuple, 1, tdesc, isNull);
00320
00321 continue;
00322 }
00323
00324 if (subLinkType == ARRAY_SUBLINK)
00325 {
00326 Datum dvalue;
00327 bool disnull;
00328
00329 found = true;
00330
00331 Assert(subplan->firstColType == tdesc->attrs[0]->atttypid);
00332 dvalue = slot_getattr(slot, 1, &disnull);
00333 astate = accumArrayResult(astate, dvalue, disnull,
00334 subplan->firstColType, oldcontext);
00335
00336 continue;
00337 }
00338
00339
00340 if (subLinkType == ROWCOMPARE_SUBLINK && found)
00341 ereport(ERROR,
00342 (errcode(ERRCODE_CARDINALITY_VIOLATION),
00343 errmsg("more than one row returned by a subquery used as an expression")));
00344
00345 found = true;
00346
00347
00348
00349
00350
00351
00352 col = 1;
00353 foreach(plst, subplan->paramIds)
00354 {
00355 int paramid = lfirst_int(plst);
00356 ParamExecData *prmdata;
00357
00358 prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
00359 Assert(prmdata->execPlan == NULL);
00360 prmdata->value = slot_getattr(slot, col, &(prmdata->isnull));
00361 col++;
00362 }
00363
00364 rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext,
00365 &rownull, NULL);
00366
00367 if (subLinkType == ANY_SUBLINK)
00368 {
00369
00370 if (rownull)
00371 *isNull = true;
00372 else if (DatumGetBool(rowresult))
00373 {
00374 result = BoolGetDatum(true);
00375 *isNull = false;
00376 break;
00377 }
00378 }
00379 else if (subLinkType == ALL_SUBLINK)
00380 {
00381
00382 if (rownull)
00383 *isNull = true;
00384 else if (!DatumGetBool(rowresult))
00385 {
00386 result = BoolGetDatum(false);
00387 *isNull = false;
00388 break;
00389 }
00390 }
00391 else
00392 {
00393
00394 result = rowresult;
00395 *isNull = rownull;
00396 }
00397 }
00398
00399 MemoryContextSwitchTo(oldcontext);
00400
00401 if (subLinkType == ARRAY_SUBLINK)
00402 {
00403
00404 if (astate != NULL)
00405 result = makeArrayResult(astate, oldcontext);
00406 else
00407 result = PointerGetDatum(construct_empty_array(subplan->firstColType));
00408 }
00409 else if (!found)
00410 {
00411
00412
00413
00414
00415
00416 if (subLinkType == EXPR_SUBLINK ||
00417 subLinkType == ROWCOMPARE_SUBLINK)
00418 {
00419 result = (Datum) 0;
00420 *isNull = true;
00421 }
00422 }
00423
00424 return result;
00425 }
00426
00427
00428
00429
00430 static void
00431 buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
00432 {
00433 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
00434 PlanState *planstate = node->planstate;
00435 int ncols = list_length(subplan->paramIds);
00436 ExprContext *innerecontext = node->innerecontext;
00437 MemoryContext oldcontext;
00438 long nbuckets;
00439 TupleTableSlot *slot;
00440
00441 Assert(subplan->subLinkType == ANY_SUBLINK);
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 MemoryContextReset(node->hashtablecxt);
00459 node->hashtable = NULL;
00460 node->hashnulls = NULL;
00461 node->havehashrows = false;
00462 node->havenullrows = false;
00463
00464 nbuckets = (long) Min(planstate->plan->plan_rows, (double) LONG_MAX);
00465 if (nbuckets < 1)
00466 nbuckets = 1;
00467
00468 node->hashtable = BuildTupleHashTable(ncols,
00469 node->keyColIdx,
00470 node->tab_eq_funcs,
00471 node->tab_hash_funcs,
00472 nbuckets,
00473 sizeof(TupleHashEntryData),
00474 node->hashtablecxt,
00475 node->hashtempcxt);
00476
00477 if (!subplan->unknownEqFalse)
00478 {
00479 if (ncols == 1)
00480 nbuckets = 1;
00481 else
00482 {
00483 nbuckets /= 16;
00484 if (nbuckets < 1)
00485 nbuckets = 1;
00486 }
00487 node->hashnulls = BuildTupleHashTable(ncols,
00488 node->keyColIdx,
00489 node->tab_eq_funcs,
00490 node->tab_hash_funcs,
00491 nbuckets,
00492 sizeof(TupleHashEntryData),
00493 node->hashtablecxt,
00494 node->hashtempcxt);
00495 }
00496
00497
00498
00499
00500
00501 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
00502
00503
00504
00505
00506 ExecReScan(planstate);
00507
00508
00509
00510
00511
00512 for (slot = ExecProcNode(planstate);
00513 !TupIsNull(slot);
00514 slot = ExecProcNode(planstate))
00515 {
00516 int col = 1;
00517 ListCell *plst;
00518 bool isnew;
00519
00520
00521
00522
00523
00524 foreach(plst, subplan->paramIds)
00525 {
00526 int paramid = lfirst_int(plst);
00527 ParamExecData *prmdata;
00528
00529 prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
00530 Assert(prmdata->execPlan == NULL);
00531 prmdata->value = slot_getattr(slot, col,
00532 &(prmdata->isnull));
00533 col++;
00534 }
00535 slot = ExecProject(node->projRight, NULL);
00536
00537
00538
00539
00540 if (slotNoNulls(slot))
00541 {
00542 (void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
00543 node->havehashrows = true;
00544 }
00545 else if (node->hashnulls)
00546 {
00547 (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
00548 node->havenullrows = true;
00549 }
00550
00551
00552
00553
00554
00555 ResetExprContext(innerecontext);
00556 }
00557
00558
00559
00560
00561
00562
00563
00564
00565 ExecClearTuple(node->projRight->pi_slot);
00566
00567 MemoryContextSwitchTo(oldcontext);
00568 }
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581 static bool
00582 findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
00583 FmgrInfo *eqfunctions)
00584 {
00585 int numCols = hashtable->numCols;
00586 AttrNumber *keyColIdx = hashtable->keyColIdx;
00587 TupleHashIterator hashiter;
00588 TupleHashEntry entry;
00589
00590 InitTupleHashIterator(hashtable, &hashiter);
00591 while ((entry = ScanTupleHashTable(&hashiter)) != NULL)
00592 {
00593 ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
00594 if (!execTuplesUnequal(slot, hashtable->tableslot,
00595 numCols, keyColIdx,
00596 eqfunctions,
00597 hashtable->tempcxt))
00598 {
00599 TermTupleHashIterator(&hashiter);
00600 return true;
00601 }
00602 }
00603
00604 return false;
00605 }
00606
00607
00608
00609
00610
00611
00612
00613 static bool
00614 slotAllNulls(TupleTableSlot *slot)
00615 {
00616 int ncols = slot->tts_tupleDescriptor->natts;
00617 int i;
00618
00619 for (i = 1; i <= ncols; i++)
00620 {
00621 if (!slot_attisnull(slot, i))
00622 return false;
00623 }
00624 return true;
00625 }
00626
00627
00628
00629
00630
00631
00632
00633 static bool
00634 slotNoNulls(TupleTableSlot *slot)
00635 {
00636 int ncols = slot->tts_tupleDescriptor->natts;
00637 int i;
00638
00639 for (i = 1; i <= ncols; i++)
00640 {
00641 if (slot_attisnull(slot, i))
00642 return false;
00643 }
00644 return true;
00645 }
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657 SubPlanState *
00658 ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
00659 {
00660 SubPlanState *sstate = makeNode(SubPlanState);
00661 EState *estate = parent->state;
00662
00663 sstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecSubPlan;
00664 sstate->xprstate.expr = (Expr *) subplan;
00665
00666
00667 sstate->planstate = (PlanState *) list_nth(estate->es_subplanstates,
00668 subplan->plan_id - 1);
00669
00670
00671 sstate->testexpr = ExecInitExpr((Expr *) subplan->testexpr, parent);
00672 sstate->args = (List *) ExecInitExpr((Expr *) subplan->args, parent);
00673
00674
00675
00676
00677 sstate->curTuple = NULL;
00678 sstate->curArray = PointerGetDatum(NULL);
00679 sstate->projLeft = NULL;
00680 sstate->projRight = NULL;
00681 sstate->hashtable = NULL;
00682 sstate->hashnulls = NULL;
00683 sstate->hashtablecxt = NULL;
00684 sstate->hashtempcxt = NULL;
00685 sstate->innerecontext = NULL;
00686 sstate->keyColIdx = NULL;
00687 sstate->tab_hash_funcs = NULL;
00688 sstate->tab_eq_funcs = NULL;
00689 sstate->lhs_hash_funcs = NULL;
00690 sstate->cur_eq_funcs = NULL;
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703 if (subplan->setParam != NIL && subplan->subLinkType != CTE_SUBLINK)
00704 {
00705 ListCell *lst;
00706
00707 foreach(lst, subplan->setParam)
00708 {
00709 int paramid = lfirst_int(lst);
00710 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
00711
00712 prm->execPlan = sstate;
00713 }
00714 }
00715
00716
00717
00718
00719
00720 if (subplan->useHashTable)
00721 {
00722 int ncols,
00723 i;
00724 TupleDesc tupDesc;
00725 TupleTableSlot *slot;
00726 List *oplist,
00727 *lefttlist,
00728 *righttlist,
00729 *leftptlist,
00730 *rightptlist;
00731 ListCell *l;
00732
00733
00734 sstate->hashtablecxt =
00735 AllocSetContextCreate(CurrentMemoryContext,
00736 "Subplan HashTable Context",
00737 ALLOCSET_DEFAULT_MINSIZE,
00738 ALLOCSET_DEFAULT_INITSIZE,
00739 ALLOCSET_DEFAULT_MAXSIZE);
00740
00741 sstate->hashtempcxt =
00742 AllocSetContextCreate(CurrentMemoryContext,
00743 "Subplan HashTable Temp Context",
00744 ALLOCSET_SMALL_MINSIZE,
00745 ALLOCSET_SMALL_INITSIZE,
00746 ALLOCSET_SMALL_MAXSIZE);
00747
00748 sstate->innerecontext = CreateExprContext(estate);
00749
00750 ncols = list_length(subplan->paramIds);
00751 sstate->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber));
00752 for (i = 0; i < ncols; i++)
00753 sstate->keyColIdx[i] = i + 1;
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769 if (IsA(sstate->testexpr->expr, OpExpr))
00770 {
00771
00772 oplist = list_make1(sstate->testexpr);
00773 }
00774 else if (and_clause((Node *) sstate->testexpr->expr))
00775 {
00776
00777 Assert(IsA(sstate->testexpr, BoolExprState));
00778 oplist = ((BoolExprState *) sstate->testexpr)->args;
00779 }
00780 else
00781 {
00782
00783 elog(ERROR, "unrecognized testexpr type: %d",
00784 (int) nodeTag(sstate->testexpr->expr));
00785 oplist = NIL;
00786 }
00787 Assert(list_length(oplist) == ncols);
00788
00789 lefttlist = righttlist = NIL;
00790 leftptlist = rightptlist = NIL;
00791 sstate->tab_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
00792 sstate->tab_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
00793 sstate->lhs_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
00794 sstate->cur_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
00795 i = 1;
00796 foreach(l, oplist)
00797 {
00798 FuncExprState *fstate = (FuncExprState *) lfirst(l);
00799 OpExpr *opexpr = (OpExpr *) fstate->xprstate.expr;
00800 ExprState *exstate;
00801 Expr *expr;
00802 TargetEntry *tle;
00803 GenericExprState *tlestate;
00804 Oid rhs_eq_oper;
00805 Oid left_hashfn;
00806 Oid right_hashfn;
00807
00808 Assert(IsA(fstate, FuncExprState));
00809 Assert(IsA(opexpr, OpExpr));
00810 Assert(list_length(fstate->args) == 2);
00811
00812
00813 exstate = (ExprState *) linitial(fstate->args);
00814 expr = exstate->expr;
00815 tle = makeTargetEntry(expr,
00816 i,
00817 NULL,
00818 false);
00819 tlestate = makeNode(GenericExprState);
00820 tlestate->xprstate.expr = (Expr *) tle;
00821 tlestate->xprstate.evalfunc = NULL;
00822 tlestate->arg = exstate;
00823 lefttlist = lappend(lefttlist, tlestate);
00824 leftptlist = lappend(leftptlist, tle);
00825
00826
00827 exstate = (ExprState *) lsecond(fstate->args);
00828 expr = exstate->expr;
00829 tle = makeTargetEntry(expr,
00830 i,
00831 NULL,
00832 false);
00833 tlestate = makeNode(GenericExprState);
00834 tlestate->xprstate.expr = (Expr *) tle;
00835 tlestate->xprstate.evalfunc = NULL;
00836 tlestate->arg = exstate;
00837 righttlist = lappend(righttlist, tlestate);
00838 rightptlist = lappend(rightptlist, tle);
00839
00840
00841 fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
00842 fmgr_info_set_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
00843
00844
00845 if (!get_compatible_hash_operators(opexpr->opno,
00846 NULL, &rhs_eq_oper))
00847 elog(ERROR, "could not find compatible hash operator for operator %u",
00848 opexpr->opno);
00849 fmgr_info(get_opcode(rhs_eq_oper), &sstate->tab_eq_funcs[i - 1]);
00850
00851
00852 if (!get_op_hash_functions(opexpr->opno,
00853 &left_hashfn, &right_hashfn))
00854 elog(ERROR, "could not find hash function for hash operator %u",
00855 opexpr->opno);
00856 fmgr_info(left_hashfn, &sstate->lhs_hash_funcs[i - 1]);
00857 fmgr_info(right_hashfn, &sstate->tab_hash_funcs[i - 1]);
00858
00859 i++;
00860 }
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870 tupDesc = ExecTypeFromTL(leftptlist, false);
00871 slot = ExecInitExtraTupleSlot(estate);
00872 ExecSetSlotDescriptor(slot, tupDesc);
00873 sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
00874 NULL,
00875 slot,
00876 NULL);
00877
00878 tupDesc = ExecTypeFromTL(rightptlist, false);
00879 slot = ExecInitExtraTupleSlot(estate);
00880 ExecSetSlotDescriptor(slot, tupDesc);
00881 sstate->projRight = ExecBuildProjectionInfo(righttlist,
00882 sstate->innerecontext,
00883 slot,
00884 NULL);
00885 }
00886
00887 return sstate;
00888 }
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903 void
00904 ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
00905 {
00906 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
00907 PlanState *planstate = node->planstate;
00908 SubLinkType subLinkType = subplan->subLinkType;
00909 MemoryContext oldcontext;
00910 TupleTableSlot *slot;
00911 ListCell *l;
00912 bool found = false;
00913 ArrayBuildState *astate = NULL;
00914
00915 if (subLinkType == ANY_SUBLINK ||
00916 subLinkType == ALL_SUBLINK)
00917 elog(ERROR, "ANY/ALL subselect unsupported as initplan");
00918 if (subLinkType == CTE_SUBLINK)
00919 elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
00920
00921
00922
00923
00924 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
00925
00926
00927
00928
00929
00930 for (slot = ExecProcNode(planstate);
00931 !TupIsNull(slot);
00932 slot = ExecProcNode(planstate))
00933 {
00934 TupleDesc tdesc = slot->tts_tupleDescriptor;
00935 int i = 1;
00936
00937 if (subLinkType == EXISTS_SUBLINK)
00938 {
00939
00940 int paramid = linitial_int(subplan->setParam);
00941 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
00942
00943 prm->execPlan = NULL;
00944 prm->value = BoolGetDatum(true);
00945 prm->isnull = false;
00946 found = true;
00947 break;
00948 }
00949
00950 if (subLinkType == ARRAY_SUBLINK)
00951 {
00952 Datum dvalue;
00953 bool disnull;
00954
00955 found = true;
00956
00957 Assert(subplan->firstColType == tdesc->attrs[0]->atttypid);
00958 dvalue = slot_getattr(slot, 1, &disnull);
00959 astate = accumArrayResult(astate, dvalue, disnull,
00960 subplan->firstColType, oldcontext);
00961
00962 continue;
00963 }
00964
00965 if (found &&
00966 (subLinkType == EXPR_SUBLINK ||
00967 subLinkType == ROWCOMPARE_SUBLINK))
00968 ereport(ERROR,
00969 (errcode(ERRCODE_CARDINALITY_VIOLATION),
00970 errmsg("more than one row returned by a subquery used as an expression")));
00971
00972 found = true;
00973
00974
00975
00976
00977
00978
00979
00980 if (node->curTuple)
00981 heap_freetuple(node->curTuple);
00982 node->curTuple = ExecCopySlotTuple(slot);
00983
00984
00985
00986
00987 foreach(l, subplan->setParam)
00988 {
00989 int paramid = lfirst_int(l);
00990 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
00991
00992 prm->execPlan = NULL;
00993 prm->value = heap_getattr(node->curTuple, i, tdesc,
00994 &(prm->isnull));
00995 i++;
00996 }
00997 }
00998
00999 if (subLinkType == ARRAY_SUBLINK)
01000 {
01001
01002 int paramid = linitial_int(subplan->setParam);
01003 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
01004
01005
01006
01007
01008
01009
01010 if (node->curArray != PointerGetDatum(NULL))
01011 pfree(DatumGetPointer(node->curArray));
01012 if (astate != NULL)
01013 node->curArray = makeArrayResult(astate,
01014 econtext->ecxt_per_query_memory);
01015 else
01016 {
01017 MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
01018 node->curArray = PointerGetDatum(construct_empty_array(subplan->firstColType));
01019 }
01020 prm->execPlan = NULL;
01021 prm->value = node->curArray;
01022 prm->isnull = false;
01023 }
01024 else if (!found)
01025 {
01026 if (subLinkType == EXISTS_SUBLINK)
01027 {
01028
01029 int paramid = linitial_int(subplan->setParam);
01030 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
01031
01032 prm->execPlan = NULL;
01033 prm->value = BoolGetDatum(false);
01034 prm->isnull = false;
01035 }
01036 else
01037 {
01038 foreach(l, subplan->setParam)
01039 {
01040 int paramid = lfirst_int(l);
01041 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
01042
01043 prm->execPlan = NULL;
01044 prm->value = (Datum) 0;
01045 prm->isnull = true;
01046 }
01047 }
01048 }
01049
01050 MemoryContextSwitchTo(oldcontext);
01051 }
01052
01053
01054
01055
01056 void
01057 ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
01058 {
01059 PlanState *planstate = node->planstate;
01060 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
01061 EState *estate = parent->state;
01062 ListCell *l;
01063
01064
01065 if (subplan->parParam != NIL)
01066 elog(ERROR, "direct correlated subquery unsupported as initplan");
01067 if (subplan->setParam == NIL)
01068 elog(ERROR, "setParam list of initplan is empty");
01069 if (bms_is_empty(planstate->plan->extParam))
01070 elog(ERROR, "extParam set of initplan is empty");
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084 foreach(l, subplan->setParam)
01085 {
01086 int paramid = lfirst_int(l);
01087 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
01088
01089 if (subplan->subLinkType != CTE_SUBLINK)
01090 prm->execPlan = node;
01091
01092 parent->chgParam = bms_add_member(parent->chgParam, paramid);
01093 }
01094 }
01095
01096
01097
01098
01099
01100
01101
01102 AlternativeSubPlanState *
01103 ExecInitAlternativeSubPlan(AlternativeSubPlan *asplan, PlanState *parent)
01104 {
01105 AlternativeSubPlanState *asstate = makeNode(AlternativeSubPlanState);
01106 double num_calls;
01107 SubPlan *subplan1;
01108 SubPlan *subplan2;
01109 Cost cost1;
01110 Cost cost2;
01111
01112 asstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecAlternativeSubPlan;
01113 asstate->xprstate.expr = (Expr *) asplan;
01114
01115
01116
01117
01118
01119 asstate->subplans = (List *) ExecInitExpr((Expr *) asplan->subplans,
01120 parent);
01121
01122
01123
01124
01125
01126
01127
01128
01129 num_calls = parent->plan->plan_rows;
01130
01131
01132
01133
01134
01135 Assert(list_length(asplan->subplans) == 2);
01136 subplan1 = (SubPlan *) linitial(asplan->subplans);
01137 subplan2 = (SubPlan *) lsecond(asplan->subplans);
01138
01139 cost1 = subplan1->startup_cost + num_calls * subplan1->per_call_cost;
01140 cost2 = subplan2->startup_cost + num_calls * subplan2->per_call_cost;
01141
01142 if (cost1 < cost2)
01143 asstate->active = 0;
01144 else
01145 asstate->active = 1;
01146
01147 return asstate;
01148 }
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158 static Datum
01159 ExecAlternativeSubPlan(AlternativeSubPlanState *node,
01160 ExprContext *econtext,
01161 bool *isNull,
01162 ExprDoneCond *isDone)
01163 {
01164
01165 SubPlanState *activesp = (SubPlanState *) list_nth(node->subplans,
01166 node->active);
01167
01168 Assert(IsA(activesp, SubPlanState));
01169
01170 return ExecSubPlan(activesp,
01171 econtext,
01172 isNull,
01173 isDone);
01174 }