Header And Logo

PostgreSQL
| The world's most advanced open source database.

nodeSubplan.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * nodeSubplan.c
00004  *    routines to support subselects
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  * IDENTIFICATION
00010  *    src/backend/executor/nodeSubplan.c
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 /*
00015  *   INTERFACE ROUTINES
00016  *      ExecSubPlan  - process a subselect
00017  *      ExecInitSubPlan - initialize a subselect
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  *      ExecSubPlan
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     /* Set default values for result flags: non-null, not a set result */
00068     *isNull = false;
00069     if (isDone)
00070         *isDone = ExprSingleResult;
00071 
00072     /* Sanity checks */
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     /* Select appropriate evaluation strategy */
00079     if (subplan->useHashTable)
00080         return ExecHashSubPlan(node, econtext, isNull);
00081     else
00082         return ExecScanSubPlan(node, econtext, isNull);
00083 }
00084 
00085 /*
00086  * ExecHashSubPlan: store subselect result in an in-memory hash table
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     /* Shouldn't have any direct correlation Vars */
00098     if (subplan->parParam != NIL || node->args != NIL)
00099         elog(ERROR, "hashed subplan with direct correlation not supported");
00100 
00101     /*
00102      * If first time through or we need to rescan the subplan, build the hash
00103      * table.
00104      */
00105     if (node->hashtable == NULL || planstate->chgParam != NULL)
00106         buildSubPlanHash(node, econtext);
00107 
00108     /*
00109      * The result for an empty subplan is always FALSE; no need to evaluate
00110      * lefthand side.
00111      */
00112     *isNull = false;
00113     if (!node->havehashrows && !node->havenullrows)
00114         return BoolGetDatum(false);
00115 
00116     /*
00117      * Evaluate lefthand expressions and form a projection tuple. First we
00118      * have to set the econtext to use (hack alert!).
00119      */
00120     node->projLeft->pi_exprContext = econtext;
00121     slot = ExecProject(node->projLeft, NULL);
00122 
00123     /*
00124      * Note: because we are typically called in a per-tuple context, we have
00125      * to explicitly clear the projected tuple before returning. Otherwise,
00126      * we'll have a double-free situation: the per-tuple context will probably
00127      * be reset before we're called again, and then the tuple slot will think
00128      * it still needs to free the tuple.
00129      */
00130 
00131     /*
00132      * If the LHS is all non-null, probe for an exact match in the main hash
00133      * table.  If we find one, the result is TRUE. Otherwise, scan the
00134      * partly-null table to see if there are any rows that aren't provably
00135      * unequal to the LHS; if so, the result is UNKNOWN.  (We skip that part
00136      * if we don't care about UNKNOWN.) Otherwise, the result is FALSE.
00137      *
00138      * Note: the reason we can avoid a full scan of the main hash table is
00139      * that the combining operators are assumed never to yield NULL when both
00140      * inputs are non-null.  If they were to do so, we might need to produce
00141      * UNKNOWN instead of FALSE because of an UNKNOWN result in comparing the
00142      * LHS to some main-table entry --- which is a comparison we will not even
00143      * make, unless there's a chance match of hash keys.
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      * When the LHS is partly or wholly NULL, we can never return TRUE. If we
00169      * don't care about UNKNOWN, just return FALSE.  Otherwise, if the LHS is
00170      * wholly NULL, immediately return UNKNOWN.  (Since the combining
00171      * operators are strict, the result could only be FALSE if the sub-select
00172      * were empty, but we already handled that case.) Otherwise, we must scan
00173      * both the main and partly-null tables to see if there are any rows that
00174      * aren't provably unequal to the LHS; if so, the result is UNKNOWN.
00175      * Otherwise, the result is FALSE.
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     /* Scan partly-null table first, since more likely to get a match */
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  * ExecScanSubPlan: default case where we have to rescan subplan each time
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;  /* TRUE if got at least one subplan tuple */
00222     ListCell   *pvar;
00223     ListCell   *l;
00224     ArrayBuildState *astate = NULL;
00225 
00226     /*
00227      * We are probably in a short-lived expression-evaluation context. Switch
00228      * to the per-query context for manipulating the child plan's chgParam,
00229      * calling ExecProcNode on it, etc.
00230      */
00231     oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
00232 
00233     /*
00234      * Set Params of this plan from parent plan correlation values. (Any
00235      * calculation we have to do is done in the parent econtext, since the
00236      * Param values don't need to have per-query lifetime.)
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      * Now that we've set up its parameters, we can reset the subplan.
00254      */
00255     ExecReScan(planstate);
00256 
00257     /*
00258      * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result
00259      * is boolean as are the results of the combining operators. We combine
00260      * results across tuples (if the subplan produces more than one) using OR
00261      * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
00262      * (ROWCOMPARE_SUBLINK doesn't allow multiple tuples from the subplan.)
00263      * NULL results from the combining operators are handled according to the
00264      * usual SQL semantics for OR and AND.  The result for no input tuples is
00265      * FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
00266      * ROWCOMPARE_SUBLINK.
00267      *
00268      * For EXPR_SUBLINK we require the subplan to produce no more than one
00269      * tuple, else an error is raised.  If zero tuples are produced, we return
00270      * NULL.  Assuming we get a tuple, we just use its first column (there can
00271      * be only one non-junk column in this case).
00272      *
00273      * For ARRAY_SUBLINK we allow the subplan to produce any number of tuples,
00274      * and form an array of the first column's values.  Note in particular
00275      * that we produce a zero-element array if no tuples are produced (this is
00276      * a change from pre-8.3 behavior of returning NULL).
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             /* cannot allow multiple input tuples for EXPR sublink */
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              * We need to copy the subplan's tuple in case the result is of
00309              * pass-by-ref type --- our return value will point into this
00310              * copied tuple!  Can't use the subplan's instance of the tuple
00311              * since it won't still be valid after next ExecProcNode() call.
00312              * node->curTuple keeps track of the copied tuple for eventual
00313              * freeing.
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             /* keep scanning subplan to make sure there's only one tuple */
00321             continue;
00322         }
00323 
00324         if (subLinkType == ARRAY_SUBLINK)
00325         {
00326             Datum       dvalue;
00327             bool        disnull;
00328 
00329             found = true;
00330             /* stash away current value */
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             /* keep scanning subplan to collect all values */
00336             continue;
00337         }
00338 
00339         /* cannot allow multiple input tuples for ROWCOMPARE sublink either */
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          * For ALL, ANY, and ROWCOMPARE sublinks, load up the Params
00349          * representing the columns of the sub-select, and then evaluate the
00350          * combining expression.
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             /* combine across rows per OR semantics */
00370             if (rownull)
00371                 *isNull = true;
00372             else if (DatumGetBool(rowresult))
00373             {
00374                 result = BoolGetDatum(true);
00375                 *isNull = false;
00376                 break;          /* needn't look at any more rows */
00377             }
00378         }
00379         else if (subLinkType == ALL_SUBLINK)
00380         {
00381             /* combine across rows per AND semantics */
00382             if (rownull)
00383                 *isNull = true;
00384             else if (!DatumGetBool(rowresult))
00385             {
00386                 result = BoolGetDatum(false);
00387                 *isNull = false;
00388                 break;          /* needn't look at any more rows */
00389             }
00390         }
00391         else
00392         {
00393             /* must be ROWCOMPARE_SUBLINK */
00394             result = rowresult;
00395             *isNull = rownull;
00396         }
00397     }
00398 
00399     MemoryContextSwitchTo(oldcontext);
00400 
00401     if (subLinkType == ARRAY_SUBLINK)
00402     {
00403         /* We return the result in the caller's context */
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          * deal with empty subplan result.  result/isNull were previously
00413          * initialized correctly for all sublink types except EXPR and
00414          * ROWCOMPARE; for those, return NULL.
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  * buildSubPlanHash: load hash table by scanning subplan output.
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      * If we already had any hash tables, destroy 'em; then create empty hash
00445      * table(s).
00446      *
00447      * If we need to distinguish accurately between FALSE and UNKNOWN (i.e.,
00448      * NULL) results of the IN operation, then we have to store subplan output
00449      * rows that are partly or wholly NULL.  We store such rows in a separate
00450      * hash table that we expect will be much smaller than the main table. (We
00451      * can use hashing to eliminate partly-null rows that are not distinct. We
00452      * keep them separate to minimize the cost of the inevitable full-table
00453      * searches; see findPartialMatch.)
00454      *
00455      * If it's not necessary to distinguish FALSE and UNKNOWN, then we don't
00456      * need to store subplan output rows that contain NULL.
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;       /* there can only be one entry */
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      * We are probably in a short-lived expression-evaluation context. Switch
00499      * to the per-query context for manipulating the child plan.
00500      */
00501     oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
00502 
00503     /*
00504      * Reset subplan to start.
00505      */
00506     ExecReScan(planstate);
00507 
00508     /*
00509      * Scan the subplan and load the hash table(s).  Note that when there are
00510      * duplicate rows coming out of the sub-select, only one copy is stored.
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          * Load up the Params representing the raw sub-select outputs, then
00522          * form the projection tuple to store in the hashtable.
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          * If result contains any nulls, store separately or not at all.
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          * Reset innerecontext after each inner tuple to free any memory used
00553          * during ExecProject.
00554          */
00555         ResetExprContext(innerecontext);
00556     }
00557 
00558     /*
00559      * Since the projected tuples are in the sub-query's context and not the
00560      * main context, we'd better clear the tuple slot before there's any
00561      * chance of a reset of the sub-query's context.  Else we will have the
00562      * potential for a double free attempt.  (XXX possibly no longer needed,
00563      * but can't hurt.)
00564      */
00565     ExecClearTuple(node->projRight->pi_slot);
00566 
00567     MemoryContextSwitchTo(oldcontext);
00568 }
00569 
00570 /*
00571  * findPartialMatch: does the hashtable contain an entry that is not
00572  * provably distinct from the tuple?
00573  *
00574  * We have to scan the whole hashtable; we can't usefully use hashkeys
00575  * to guide probing, since we might get partial matches on tuples with
00576  * hashkeys quite unrelated to what we'd get from the given tuple.
00577  *
00578  * Caller must provide the equality functions to use, since in cross-type
00579  * cases these are different from the hashtable's internal functions.
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     /* No TermTupleHashIterator call needed here */
00604     return false;
00605 }
00606 
00607 /*
00608  * slotAllNulls: is the slot completely NULL?
00609  *
00610  * This does not test for dropped columns, which is OK because we only
00611  * use it on projected tuples.
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  * slotNoNulls: is the slot entirely not NULL?
00629  *
00630  * This does not test for dropped columns, which is OK because we only
00631  * use it on projected tuples.
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  *      ExecInitSubPlan
00649  *
00650  * Create a SubPlanState for a SubPlan; this is the SubPlan-specific part
00651  * of ExecInitExpr().  We split it out so that it can be used for InitPlans
00652  * as well as regular SubPlans.  Note that we don't link the SubPlan into
00653  * the parent's subPlan list, because that shouldn't happen for InitPlans.
00654  * Instead, ExecInitExpr() does that one part.
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     /* Link the SubPlanState to already-initialized subplan */
00667     sstate->planstate = (PlanState *) list_nth(estate->es_subplanstates,
00668                                                subplan->plan_id - 1);
00669 
00670     /* Initialize subexpressions */
00671     sstate->testexpr = ExecInitExpr((Expr *) subplan->testexpr, parent);
00672     sstate->args = (List *) ExecInitExpr((Expr *) subplan->args, parent);
00673 
00674     /*
00675      * initialize my state
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      * If this plan is un-correlated or undirect correlated one and want to
00694      * set params for parent plan then mark parameters as needing evaluation.
00695      *
00696      * A CTE subplan's output parameter is never to be evaluated in the normal
00697      * way, so skip this in that case.
00698      *
00699      * Note that in the case of un-correlated subqueries we don't care about
00700      * setting parent->chgParam here: indices take care about it, for others -
00701      * it doesn't matter...
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      * If we are going to hash the subquery output, initialize relevant stuff.
00718      * (We don't create the hashtable until needed, though.)
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         /* We need a memory context to hold the hash table(s) */
00734         sstate->hashtablecxt =
00735             AllocSetContextCreate(CurrentMemoryContext,
00736                                   "Subplan HashTable Context",
00737                                   ALLOCSET_DEFAULT_MINSIZE,
00738                                   ALLOCSET_DEFAULT_INITSIZE,
00739                                   ALLOCSET_DEFAULT_MAXSIZE);
00740         /* and a small one for the hash tables to use as temp storage */
00741         sstate->hashtempcxt =
00742             AllocSetContextCreate(CurrentMemoryContext,
00743                                   "Subplan HashTable Temp Context",
00744                                   ALLOCSET_SMALL_MINSIZE,
00745                                   ALLOCSET_SMALL_INITSIZE,
00746                                   ALLOCSET_SMALL_MAXSIZE);
00747         /* and a short-lived exprcontext for function evaluation */
00748         sstate->innerecontext = CreateExprContext(estate);
00749         /* Silly little array of column numbers 1..n */
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          * We use ExecProject to evaluate the lefthand and righthand
00757          * expression lists and form tuples.  (You might think that we could
00758          * use the sub-select's output tuples directly, but that is not the
00759          * case if we had to insert any run-time coercions of the sub-select's
00760          * output datatypes; anyway this avoids storing any resjunk columns
00761          * that might be in the sub-select's output.) Run through the
00762          * combining expressions to build tlists for the lefthand and
00763          * righthand sides.  We need both the ExprState list (for ExecProject)
00764          * and the underlying parse Exprs (for ExecTypeFromTL).
00765          *
00766          * We also extract the combining operators themselves to initialize
00767          * the equality and hashing functions for the hash tables.
00768          */
00769         if (IsA(sstate->testexpr->expr, OpExpr))
00770         {
00771             /* single combining operator */
00772             oplist = list_make1(sstate->testexpr);
00773         }
00774         else if (and_clause((Node *) sstate->testexpr->expr))
00775         {
00776             /* multiple combining operators */
00777             Assert(IsA(sstate->testexpr, BoolExprState));
00778             oplist = ((BoolExprState *) sstate->testexpr)->args;
00779         }
00780         else
00781         {
00782             /* shouldn't see anything else in a hashable subplan */
00783             elog(ERROR, "unrecognized testexpr type: %d",
00784                  (int) nodeTag(sstate->testexpr->expr));
00785             oplist = NIL;       /* keep compiler quiet */
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             /* Process lefthand argument */
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             /* Process righthand argument */
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             /* Lookup the equality function (potentially cross-type) */
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             /* Look up the equality function for the RHS type */
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             /* Lookup the associated hash functions */
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          * Construct tupdescs, slots and projection nodes for left and right
00864          * sides.  The lefthand expressions will be evaluated in the parent
00865          * plan node's exprcontext, which we don't have access to here.
00866          * Fortunately we can just pass NULL for now and fill it in later
00867          * (hack alert!).  The righthand expressions will be evaluated in our
00868          * own innerecontext.
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  *      ExecSetParamPlan
00892  *
00893  *      Executes an InitPlan subplan and sets its output parameters.
00894  *
00895  * This is called from ExecEvalParamExec() when the value of a PARAM_EXEC
00896  * parameter is requested and the param's execPlan field is set (indicating
00897  * that the param has not yet been evaluated).  This allows lazy evaluation
00898  * of initplans: we don't run the subplan until/unless we need its output.
00899  * Note that this routine MUST clear the execPlan fields of the plan's
00900  * output parameters after evaluating them!
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      * Must switch to per-query memory context.
00923      */
00924     oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
00925 
00926     /*
00927      * Run the plan.  (If it needs to be rescanned, the first ExecProcNode
00928      * call will take care of that.)
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             /* There can be only one setParam... */
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             /* stash away current value */
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             /* keep scanning subplan to collect all values */
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          * We need to copy the subplan's tuple into our own context, in case
00976          * any of the params are pass-by-ref type --- the pointers stored in
00977          * the param structs will point at this copied tuple! node->curTuple
00978          * keeps track of the copied tuple for eventual freeing.
00979          */
00980         if (node->curTuple)
00981             heap_freetuple(node->curTuple);
00982         node->curTuple = ExecCopySlotTuple(slot);
00983 
00984         /*
00985          * Now set all the setParam params from the columns of the tuple
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         /* There can be only one setParam... */
01002         int         paramid = linitial_int(subplan->setParam);
01003         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
01004 
01005         /*
01006          * We build the result array in query context so it won't disappear;
01007          * to avoid leaking memory across repeated calls, we have to remember
01008          * the latest value, much as for curTuple above.
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             /* There can be only one setParam... */
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  * Mark an initplan as needing recalculation
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     /* sanity checks */
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      * Don't actually re-scan: it'll happen inside ExecSetParamPlan if needed.
01074      */
01075 
01076     /*
01077      * Mark this subplan's output parameters as needing recalculation.
01078      *
01079      * CTE subplans are never executed via parameter recalculation; instead
01080      * they get run when called by nodeCtescan.c.  So don't mark the output
01081      * parameter of a CTE subplan as dirty, but do set the chgParam bit for it
01082      * so that dependent plan nodes will get told to rescan.
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  * ExecInitAlternativeSubPlan
01099  *
01100  * Initialize for execution of one of a set of alternative subplans.
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      * Initialize subplans.  (Can we get away with only initializing the one
01117      * we're going to use?)
01118      */
01119     asstate->subplans = (List *) ExecInitExpr((Expr *) asplan->subplans,
01120                                               parent);
01121 
01122     /*
01123      * Select the one to be used.  For this, we need an estimate of the number
01124      * of executions of the subplan.  We use the number of output rows
01125      * expected from the parent plan node.  This is a good estimate if we are
01126      * in the parent's targetlist, and an underestimate (but probably not by
01127      * more than a factor of 2) if we are in the qual.
01128      */
01129     num_calls = parent->plan->plan_rows;
01130 
01131     /*
01132      * The planner saved enough info so that we don't have to work very hard
01133      * to estimate the total cost, given the number-of-calls estimate.
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  * ExecAlternativeSubPlan
01152  *
01153  * Execute one of a set of alternative subplans.
01154  *
01155  * Note: in future we might consider changing to different subplans on the
01156  * fly, in case the original rowcount estimate turns out to be way off.
01157  */
01158 static Datum
01159 ExecAlternativeSubPlan(AlternativeSubPlanState *node,
01160                        ExprContext *econtext,
01161                        bool *isNull,
01162                        ExprDoneCond *isDone)
01163 {
01164     /* Just pass control to the active subplan */
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 }