1 /*-------------------------------------------------------------------------
4 * routines to support subselects
6 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.67 2005/03/16 21:38:08 tgl Exp $
12 *-------------------------------------------------------------------------
16 * ExecSubPlan - process a subselect
17 * ExecInitSubPlan - initialize a subselect
18 * ExecEndSubPlan - shut down a subselect
22 #include "access/heapam.h"
23 #include "executor/executor.h"
24 #include "executor/nodeSubplan.h"
25 #include "nodes/makefuncs.h"
26 #include "parser/parse_expr.h"
27 #include "utils/array.h"
28 #include "utils/datum.h"
29 #include "utils/lsyscache.h"
32 static Datum ExecHashSubPlan(SubPlanState *node,
33 ExprContext *econtext,
35 static Datum ExecScanSubPlan(SubPlanState *node,
36 ExprContext *econtext,
38 static void buildSubPlanHash(SubPlanState *node);
39 static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot);
40 static bool slotAllNulls(TupleTableSlot *slot);
41 static bool slotNoNulls(TupleTableSlot *slot);
44 /* ----------------------------------------------------------------
46 * ----------------------------------------------------------------
49 ExecSubPlan(SubPlanState *node,
50 ExprContext *econtext,
54 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
56 /* Set default values for result flags: non-null, not a set result */
59 *isDone = ExprSingleResult;
61 if (subplan->setParam != NIL)
62 elog(ERROR, "cannot set parent params from subquery");
64 if (subplan->useHashTable)
65 return ExecHashSubPlan(node, econtext, isNull);
67 return ExecScanSubPlan(node, econtext, isNull);
71 * ExecHashSubPlan: store subselect result in an in-memory hash table
74 ExecHashSubPlan(SubPlanState *node,
75 ExprContext *econtext,
78 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
79 PlanState *planstate = node->planstate;
80 ExprContext *innerecontext = node->innerecontext;
83 /* Shouldn't have any direct correlation Vars */
84 if (subplan->parParam != NIL || node->args != NIL)
85 elog(ERROR, "hashed subplan with direct correlation not supported");
88 * If first time through or we need to rescan the subplan, build the
91 if (node->hashtable == NULL || planstate->chgParam != NULL)
92 buildSubPlanHash(node);
95 * The result for an empty subplan is always FALSE; no need to
96 * evaluate lefthand side.
99 if (!node->havehashrows && !node->havenullrows)
100 return BoolGetDatum(false);
103 * Evaluate lefthand expressions and form a projection tuple. First we
104 * have to set the econtext to use (hack alert!).
106 node->projLeft->pi_exprContext = econtext;
107 slot = ExecProject(node->projLeft, NULL);
110 * Note: because we are typically called in a per-tuple context, we
111 * have to explicitly clear the projected tuple before returning.
112 * Otherwise, we'll have a double-free situation: the per-tuple
113 * context will probably be reset before we're called again, and then
114 * the tuple slot will think it still needs to free the tuple.
118 * Since the hashtable routines will use innerecontext's per-tuple
119 * memory as working memory, be sure to reset it for each tuple.
121 ResetExprContext(innerecontext);
124 * If the LHS is all non-null, probe for an exact match in the main
125 * hash table. If we find one, the result is TRUE. Otherwise, scan
126 * the partly-null table to see if there are any rows that aren't
127 * provably unequal to the LHS; if so, the result is UNKNOWN. (We
128 * skip that part if we don't care about UNKNOWN.) Otherwise, the
131 * Note: the reason we can avoid a full scan of the main hash table is
132 * that the combining operators are assumed never to yield NULL when
133 * both inputs are non-null. If they were to do so, we might need to
134 * produce UNKNOWN instead of FALSE because of an UNKNOWN result in
135 * comparing the LHS to some main-table entry --- which is a
136 * comparison we will not even make, unless there's a chance match of
139 if (slotNoNulls(slot))
141 if (node->havehashrows &&
142 LookupTupleHashEntry(node->hashtable, slot, NULL) != NULL)
144 ExecClearTuple(slot);
145 return BoolGetDatum(true);
147 if (node->havenullrows &&
148 findPartialMatch(node->hashnulls, slot))
150 ExecClearTuple(slot);
152 return BoolGetDatum(false);
154 ExecClearTuple(slot);
155 return BoolGetDatum(false);
159 * When the LHS is partly or wholly NULL, we can never return TRUE. If
160 * we don't care about UNKNOWN, just return FALSE. Otherwise, if the
161 * LHS is wholly NULL, immediately return UNKNOWN. (Since the
162 * combining operators are strict, the result could only be FALSE if
163 * the sub-select were empty, but we already handled that case.)
164 * Otherwise, we must scan both the main and partly-null tables to see
165 * if there are any rows that aren't provably unequal to the LHS; if
166 * so, the result is UNKNOWN. Otherwise, the result is FALSE.
168 if (node->hashnulls == NULL)
170 ExecClearTuple(slot);
171 return BoolGetDatum(false);
173 if (slotAllNulls(slot))
175 ExecClearTuple(slot);
177 return BoolGetDatum(false);
179 /* Scan partly-null table first, since more likely to get a match */
180 if (node->havenullrows &&
181 findPartialMatch(node->hashnulls, slot))
183 ExecClearTuple(slot);
185 return BoolGetDatum(false);
187 if (node->havehashrows &&
188 findPartialMatch(node->hashtable, slot))
190 ExecClearTuple(slot);
192 return BoolGetDatum(false);
194 ExecClearTuple(slot);
195 return BoolGetDatum(false);
199 * ExecScanSubPlan: default case where we have to rescan subplan each time
202 ExecScanSubPlan(SubPlanState *node,
203 ExprContext *econtext,
206 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
207 PlanState *planstate = node->planstate;
208 SubLinkType subLinkType = subplan->subLinkType;
209 bool useOr = subplan->useOr;
210 MemoryContext oldcontext;
211 TupleTableSlot *slot;
213 bool found = false; /* TRUE if got at least one subplan tuple */
216 ArrayBuildState *astate = NULL;
219 * We are probably in a short-lived expression-evaluation context.
220 * Switch to the child plan's per-query context for manipulating its
221 * chgParam, calling ExecProcNode on it, etc.
223 oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
226 * Set Params of this plan from parent plan correlation values. (Any
227 * calculation we have to do is done in the parent econtext, since the
228 * Param values don't need to have per-query lifetime.)
230 Assert(list_length(subplan->parParam) == list_length(node->args));
232 forboth(l, subplan->parParam, pvar, node->args)
234 int paramid = lfirst_int(l);
235 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
237 prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
241 planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
244 ExecReScan(planstate, NULL);
247 * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the
248 * result is boolean as are the results of the combining operators. We
249 * combine results within a tuple (if there are multiple columns)
250 * using OR semantics if "useOr" is true, AND semantics if not. We
251 * then combine results across tuples (if the subplan produces more
252 * than one) using OR semantics for ANY_SUBLINK or AND semantics for
253 * ALL_SUBLINK. (MULTIEXPR_SUBLINK doesn't allow multiple tuples from
254 * the subplan.) NULL results from the combining operators are handled
255 * according to the usual SQL semantics for OR and AND. The result
256 * for no input tuples is FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK,
257 * NULL for MULTIEXPR_SUBLINK.
259 * For EXPR_SUBLINK we require the subplan to produce no more than one
260 * tuple, else an error is raised. For ARRAY_SUBLINK we allow the
261 * subplan to produce more than one tuple. In either case, if zero
262 * tuples are produced, we return NULL. Assuming we get a tuple, we
263 * just use its first column (there can be only one non-junk column in
266 result = BoolGetDatum(subLinkType == ALL_SUBLINK);
269 for (slot = ExecProcNode(planstate);
271 slot = ExecProcNode(planstate))
273 TupleDesc tdesc = slot->tts_tupleDescriptor;
274 Datum rowresult = BoolGetDatum(!useOr);
275 bool rownull = false;
279 if (subLinkType == EXISTS_SUBLINK)
282 result = BoolGetDatum(true);
286 if (subLinkType == EXPR_SUBLINK)
288 /* cannot allow multiple input tuples for EXPR sublink */
291 (errcode(ERRCODE_CARDINALITY_VIOLATION),
292 errmsg("more than one row returned by a subquery used as an expression")));
296 * We need to copy the subplan's tuple in case the result is
297 * of pass-by-ref type --- our return value will point into
298 * this copied tuple! Can't use the subplan's instance of the
299 * tuple since it won't still be valid after next
300 * ExecProcNode() call. node->curTuple keeps track of the
301 * copied tuple for eventual freeing.
303 MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
305 heap_freetuple(node->curTuple);
306 node->curTuple = ExecCopySlotTuple(slot);
307 MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
309 result = heap_getattr(node->curTuple, col, tdesc, isNull);
310 /* keep scanning subplan to make sure there's only one tuple */
314 if (subLinkType == ARRAY_SUBLINK)
320 /* stash away current value */
321 dvalue = slot_getattr(slot, 1, &disnull);
322 astate = accumArrayResult(astate, dvalue, disnull,
323 tdesc->attrs[0]->atttypid,
325 /* keep scanning subplan to collect all values */
329 /* cannot allow multiple input tuples for MULTIEXPR sublink either */
330 if (subLinkType == MULTIEXPR_SUBLINK && found)
332 (errcode(ERRCODE_CARDINALITY_VIOLATION),
333 errmsg("more than one row returned by a subquery used as an expression")));
338 * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
339 * operators for columns of tuple.
341 Assert(list_length(node->exprs) == list_length(subplan->paramIds));
343 forboth(l, node->exprs, plst, subplan->paramIds)
345 ExprState *exprstate = (ExprState *) lfirst(l);
346 int paramid = lfirst_int(plst);
347 ParamExecData *prmdata;
352 * Load up the Param representing this column of the
355 prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
356 Assert(prmdata->execPlan == NULL);
357 prmdata->value = slot_getattr(slot, col,
361 * Now we can eval the combining operator for this column.
363 expresult = ExecEvalExprSwitchContext(exprstate, econtext,
367 * Combine the result into the row result as appropriate.
371 rowresult = expresult;
376 /* combine within row per OR semantics */
379 else if (DatumGetBool(expresult))
381 rowresult = BoolGetDatum(true);
383 break; /* needn't look at any more columns */
388 /* combine within row per AND semantics */
391 else if (!DatumGetBool(expresult))
393 rowresult = BoolGetDatum(false);
395 break; /* needn't look at any more columns */
402 if (subLinkType == ANY_SUBLINK)
404 /* combine across rows per OR semantics */
407 else if (DatumGetBool(rowresult))
409 result = BoolGetDatum(true);
411 break; /* needn't look at any more rows */
414 else if (subLinkType == ALL_SUBLINK)
416 /* combine across rows per AND semantics */
419 else if (!DatumGetBool(rowresult))
421 result = BoolGetDatum(false);
423 break; /* needn't look at any more rows */
428 /* must be MULTIEXPR_SUBLINK */
437 * deal with empty subplan result. result/isNull were previously
438 * initialized correctly for all sublink types except EXPR, ARRAY,
439 * and MULTIEXPR; for those, return NULL.
441 if (subLinkType == EXPR_SUBLINK ||
442 subLinkType == ARRAY_SUBLINK ||
443 subLinkType == MULTIEXPR_SUBLINK)
449 else if (subLinkType == ARRAY_SUBLINK)
451 Assert(astate != NULL);
452 /* We return the result in the caller's context */
453 result = makeArrayResult(astate, oldcontext);
456 MemoryContextSwitchTo(oldcontext);
462 * buildSubPlanHash: load hash table by scanning subplan output.
465 buildSubPlanHash(SubPlanState *node)
467 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
468 PlanState *planstate = node->planstate;
469 int ncols = list_length(node->exprs);
470 ExprContext *innerecontext = node->innerecontext;
471 MemoryContext tempcxt = innerecontext->ecxt_per_tuple_memory;
472 MemoryContext oldcontext;
474 TupleTableSlot *slot;
476 Assert(subplan->subLinkType == ANY_SUBLINK);
477 Assert(!subplan->useOr);
480 * If we already had any hash tables, destroy 'em; then create empty
483 * If we need to distinguish accurately between FALSE and UNKNOWN (i.e.,
484 * NULL) results of the IN operation, then we have to store subplan
485 * output rows that are partly or wholly NULL. We store such rows in
486 * a separate hash table that we expect will be much smaller than the
487 * main table. (We can use hashing to eliminate partly-null rows that
488 * are not distinct. We keep them separate to minimize the cost of
489 * the inevitable full-table searches; see findPartialMatch.)
491 * If it's not necessary to distinguish FALSE and UNKNOWN, then we don't
492 * need to store subplan output rows that contain NULL.
494 MemoryContextReset(node->tablecxt);
495 node->hashtable = NULL;
496 node->hashnulls = NULL;
497 node->havehashrows = false;
498 node->havenullrows = false;
500 nbuckets = (int) ceil(planstate->plan->plan_rows);
504 node->hashtable = BuildTupleHashTable(ncols,
509 sizeof(TupleHashEntryData),
513 if (!subplan->unknownEqFalse)
516 nbuckets = 1; /* there can only be one entry */
523 node->hashnulls = BuildTupleHashTable(ncols,
528 sizeof(TupleHashEntryData),
534 * We are probably in a short-lived expression-evaluation context.
535 * Switch to the child plan's per-query context for calling
538 oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
541 * Reset subplan to start.
543 ExecReScan(planstate, NULL);
546 * Scan the subplan and load the hash table(s). Note that when there
547 * are duplicate rows coming out of the sub-select, only one copy is
550 for (slot = ExecProcNode(planstate);
552 slot = ExecProcNode(planstate))
559 * Load up the Params representing the raw sub-select outputs,
560 * then form the projection tuple to store in the hashtable.
562 foreach(plst, subplan->paramIds)
564 int paramid = lfirst_int(plst);
565 ParamExecData *prmdata;
567 prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
568 Assert(prmdata->execPlan == NULL);
569 prmdata->value = slot_getattr(slot, col,
573 slot = ExecProject(node->projRight, NULL);
576 * If result contains any nulls, store separately or not at all.
578 if (slotNoNulls(slot))
580 (void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
581 node->havehashrows = true;
583 else if (node->hashnulls)
585 (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
586 node->havenullrows = true;
590 * Reset innerecontext after each inner tuple to free any memory
591 * used in hash computation or comparison routines.
593 ResetExprContext(innerecontext);
597 * Since the projected tuples are in the sub-query's context and not
598 * the main context, we'd better clear the tuple slot before there's
599 * any chance of a reset of the sub-query's context. Else we will
600 * have the potential for a double free attempt. (XXX possibly
601 * no longer needed, but can't hurt.)
603 ExecClearTuple(node->projRight->pi_slot);
605 MemoryContextSwitchTo(oldcontext);
609 * findPartialMatch: does the hashtable contain an entry that is not
610 * provably distinct from the tuple?
612 * We have to scan the whole hashtable; we can't usefully use hashkeys
613 * to guide probing, since we might get partial matches on tuples with
614 * hashkeys quite unrelated to what we'd get from the given tuple.
617 findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot)
619 int numCols = hashtable->numCols;
620 AttrNumber *keyColIdx = hashtable->keyColIdx;
621 TupleHashIterator hashiter;
622 TupleHashEntry entry;
624 ResetTupleHashIterator(hashtable, &hashiter);
625 while ((entry = ScanTupleHashTable(&hashiter)) != NULL)
627 ExecStoreTuple(entry->firstTuple, hashtable->tableslot,
628 InvalidBuffer, false);
629 if (!execTuplesUnequal(hashtable->tableslot, slot,
631 hashtable->eqfunctions,
639 * slotAllNulls: is the slot completely NULL?
641 * This does not test for dropped columns, which is OK because we only
642 * use it on projected tuples.
645 slotAllNulls(TupleTableSlot *slot)
647 int ncols = slot->tts_tupleDescriptor->natts;
650 for (i = 1; i <= ncols; i++)
652 if (!slot_attisnull(slot, i))
659 * slotNoNulls: is the slot entirely not NULL?
661 * This does not test for dropped columns, which is OK because we only
662 * use it on projected tuples.
665 slotNoNulls(TupleTableSlot *slot)
667 int ncols = slot->tts_tupleDescriptor->natts;
670 for (i = 1; i <= ncols; i++)
672 if (slot_attisnull(slot, i))
678 /* ----------------------------------------------------------------
680 * ----------------------------------------------------------------
683 ExecInitSubPlan(SubPlanState *node, EState *estate)
685 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
687 MemoryContext oldcontext;
690 * Do access checking on the rangetable entries in the subquery.
692 ExecCheckRTPerms(subplan->rtable);
695 * initialize my state
697 node->needShutdown = false;
698 node->curTuple = NULL;
699 node->projLeft = NULL;
700 node->projRight = NULL;
701 node->hashtable = NULL;
702 node->hashnulls = NULL;
703 node->tablecxt = NULL;
704 node->innerecontext = NULL;
705 node->keyColIdx = NULL;
706 node->eqfunctions = NULL;
707 node->hashfunctions = NULL;
710 * create an EState for the subplan
712 * The subquery needs its own EState because it has its own rangetable.
713 * It shares our Param ID space, however. XXX if rangetable access
714 * were done differently, the subquery could share our EState, which
715 * would eliminate some thrashing about in this module...
717 sp_estate = CreateExecutorState();
718 node->sub_estate = sp_estate;
720 oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
722 sp_estate->es_range_table = subplan->rtable;
723 sp_estate->es_param_list_info = estate->es_param_list_info;
724 sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
725 sp_estate->es_tupleTable =
726 ExecCreateTupleTable(ExecCountSlotsNode(subplan->plan) + 10);
727 sp_estate->es_snapshot = estate->es_snapshot;
728 sp_estate->es_crosscheck_snapshot = estate->es_crosscheck_snapshot;
729 sp_estate->es_instrument = estate->es_instrument;
732 * Start up the subplan (this is a very cut-down form of InitPlan())
734 node->planstate = ExecInitNode(subplan->plan, sp_estate);
736 node->needShutdown = true; /* now we need to shutdown the subplan */
738 MemoryContextSwitchTo(oldcontext);
741 * If this plan is un-correlated or undirect correlated one and want
742 * to set params for parent plan then mark parameters as needing
745 * Note that in the case of un-correlated subqueries we don't care about
746 * setting parent->chgParam here: indices take care about it, for
747 * others - it doesn't matter...
749 if (subplan->setParam != NIL)
753 foreach(lst, subplan->setParam)
755 int paramid = lfirst_int(lst);
756 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
758 prm->execPlan = node;
763 * If we are going to hash the subquery output, initialize relevant
764 * stuff. (We don't create the hashtable until needed, though.)
766 if (subplan->useHashTable)
772 TupleTableSlot *slot;
779 /* We need a memory context to hold the hash table(s) */
781 AllocSetContextCreate(CurrentMemoryContext,
782 "Subplan HashTable Context",
783 ALLOCSET_DEFAULT_MINSIZE,
784 ALLOCSET_DEFAULT_INITSIZE,
785 ALLOCSET_DEFAULT_MAXSIZE);
786 /* and a short-lived exprcontext for function evaluation */
787 node->innerecontext = CreateExprContext(estate);
788 /* Silly little array of column numbers 1..n */
789 ncols = list_length(node->exprs);
790 node->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber));
791 for (i = 0; i < ncols; i++)
792 node->keyColIdx[i] = i + 1;
795 * We use ExecProject to evaluate the lefthand and righthand
796 * expression lists and form tuples. (You might think that we
797 * could use the sub-select's output tuples directly, but that is
798 * not the case if we had to insert any run-time coercions of the
799 * sub-select's output datatypes; anyway this avoids storing any
800 * resjunk columns that might be in the sub-select's output.) Run
801 * through the combining expressions to build tlists for the
802 * lefthand and righthand sides. We need both the ExprState list
803 * (for ExecProject) and the underlying parse Exprs (for
806 * We also extract the combining operators themselves to initialize
807 * the equality and hashing functions for the hash tables.
809 lefttlist = righttlist = NIL;
810 leftptlist = rightptlist = NIL;
811 node->eqfunctions = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
812 node->hashfunctions = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
814 foreach(lexpr, node->exprs)
816 FuncExprState *fstate = (FuncExprState *) lfirst(lexpr);
817 OpExpr *opexpr = (OpExpr *) fstate->xprstate.expr;
821 GenericExprState *tlestate;
824 Assert(IsA(fstate, FuncExprState));
825 Assert(IsA(opexpr, OpExpr));
826 Assert(list_length(fstate->args) == 2);
828 /* Process lefthand argument */
829 exstate = (ExprState *) linitial(fstate->args);
830 expr = exstate->expr;
831 tle = makeTargetEntry(makeResdom(i,
832 exprType((Node *) expr),
833 exprTypmod((Node *) expr),
837 tlestate = makeNode(GenericExprState);
838 tlestate->xprstate.expr = (Expr *) tle;
839 tlestate->xprstate.evalfunc = NULL;
840 tlestate->arg = exstate;
841 lefttlist = lappend(lefttlist, tlestate);
842 leftptlist = lappend(leftptlist, tle);
844 /* Process righthand argument */
845 exstate = (ExprState *) lsecond(fstate->args);
846 expr = exstate->expr;
847 tle = makeTargetEntry(makeResdom(i,
848 exprType((Node *) expr),
849 exprTypmod((Node *) expr),
853 tlestate = makeNode(GenericExprState);
854 tlestate->xprstate.expr = (Expr *) tle;
855 tlestate->xprstate.evalfunc = NULL;
856 tlestate->arg = exstate;
857 righttlist = lappend(righttlist, tlestate);
858 rightptlist = lappend(rightptlist, tle);
860 /* Lookup the combining function */
861 fmgr_info(opexpr->opfuncid, &node->eqfunctions[i - 1]);
862 node->eqfunctions[i - 1].fn_expr = (Node *) opexpr;
864 /* Lookup the associated hash function */
865 hashfn = get_op_hash_function(opexpr->opno);
866 if (!OidIsValid(hashfn))
867 elog(ERROR, "could not find hash function for hash operator %u",
869 fmgr_info(hashfn, &node->hashfunctions[i - 1]);
875 * Create a tupletable to hold these tuples. (Note: we never
876 * bother to free the tupletable explicitly; that's okay because
877 * it will never store raw disk tuples that might have associated
878 * buffer pins. The only resource involved is memory, which will
879 * be cleaned up by freeing the query context.)
881 tupTable = ExecCreateTupleTable(2);
884 * Construct tupdescs, slots and projection nodes for left and
885 * right sides. The lefthand expressions will be evaluated in the
886 * parent plan node's exprcontext, which we don't have access to
887 * here. Fortunately we can just pass NULL for now and fill it in
888 * later (hack alert!). The righthand expressions will be
889 * evaluated in our own innerecontext.
891 tupDesc = ExecTypeFromTL(leftptlist, false);
892 slot = ExecAllocTableSlot(tupTable);
893 ExecSetSlotDescriptor(slot, tupDesc, true);
894 node->projLeft = ExecBuildProjectionInfo(lefttlist,
898 tupDesc = ExecTypeFromTL(rightptlist, false);
899 slot = ExecAllocTableSlot(tupTable);
900 ExecSetSlotDescriptor(slot, tupDesc, true);
901 node->projRight = ExecBuildProjectionInfo(righttlist,
907 /* ----------------------------------------------------------------
910 * Executes an InitPlan subplan and sets its output parameters.
912 * This is called from ExecEvalParam() when the value of a PARAM_EXEC
913 * parameter is requested and the param's execPlan field is set (indicating
914 * that the param has not yet been evaluated). This allows lazy evaluation
915 * of initplans: we don't run the subplan until/unless we need its output.
916 * Note that this routine MUST clear the execPlan fields of the plan's
917 * output parameters after evaluating them!
918 * ----------------------------------------------------------------
921 ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
923 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
924 PlanState *planstate = node->planstate;
925 SubLinkType subLinkType = subplan->subLinkType;
926 MemoryContext oldcontext;
927 TupleTableSlot *slot;
930 ArrayBuildState *astate = NULL;
933 * Must switch to child query's per-query memory context.
935 oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
937 if (subLinkType == ANY_SUBLINK ||
938 subLinkType == ALL_SUBLINK)
939 elog(ERROR, "ANY/ALL subselect unsupported as initplan");
941 if (planstate->chgParam != NULL)
942 ExecReScan(planstate, NULL);
944 for (slot = ExecProcNode(planstate);
946 slot = ExecProcNode(planstate))
948 TupleDesc tdesc = slot->tts_tupleDescriptor;
951 if (subLinkType == EXISTS_SUBLINK)
953 /* There can be only one param... */
954 int paramid = linitial_int(subplan->setParam);
955 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
957 prm->execPlan = NULL;
958 prm->value = BoolGetDatum(true);
964 if (subLinkType == ARRAY_SUBLINK)
970 /* stash away current value */
971 dvalue = slot_getattr(slot, 1, &disnull);
972 astate = accumArrayResult(astate, dvalue, disnull,
973 tdesc->attrs[0]->atttypid,
975 /* keep scanning subplan to collect all values */
980 (subLinkType == EXPR_SUBLINK ||
981 subLinkType == MULTIEXPR_SUBLINK))
983 (errcode(ERRCODE_CARDINALITY_VIOLATION),
984 errmsg("more than one row returned by a subquery used as an expression")));
989 * We need to copy the subplan's tuple into our own context, in
990 * case any of the params are pass-by-ref type --- the pointers
991 * stored in the param structs will point at this copied tuple!
992 * node->curTuple keeps track of the copied tuple for eventual
995 MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
997 heap_freetuple(node->curTuple);
998 node->curTuple = ExecCopySlotTuple(slot);
999 MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
1002 * Now set all the setParam params from the columns of the tuple
1004 foreach(l, subplan->setParam)
1006 int paramid = lfirst_int(l);
1007 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1009 prm->execPlan = NULL;
1010 prm->value = heap_getattr(node->curTuple, i, tdesc,
1018 if (subLinkType == EXISTS_SUBLINK)
1020 /* There can be only one param... */
1021 int paramid = linitial_int(subplan->setParam);
1022 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1024 prm->execPlan = NULL;
1025 prm->value = BoolGetDatum(false);
1026 prm->isnull = false;
1030 foreach(l, subplan->setParam)
1032 int paramid = lfirst_int(l);
1033 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1035 prm->execPlan = NULL;
1036 prm->value = (Datum) 0;
1041 else if (subLinkType == ARRAY_SUBLINK)
1043 /* There can be only one param... */
1044 int paramid = linitial_int(subplan->setParam);
1045 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1047 Assert(astate != NULL);
1048 prm->execPlan = NULL;
1049 /* We build the result in query context so it won't disappear */
1050 prm->value = makeArrayResult(astate, econtext->ecxt_per_query_memory);
1051 prm->isnull = false;
1054 MemoryContextSwitchTo(oldcontext);
1057 /* ----------------------------------------------------------------
1059 * ----------------------------------------------------------------
1062 ExecEndSubPlan(SubPlanState *node)
1064 if (node->needShutdown)
1066 MemoryContext oldcontext;
1068 oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
1069 ExecEndPlan(node->planstate, node->sub_estate);
1070 MemoryContextSwitchTo(oldcontext);
1071 FreeExecutorState(node->sub_estate);
1072 node->sub_estate = NULL;
1073 node->planstate = NULL;
1074 node->needShutdown = false;
1079 * Mark an initplan as needing recalculation
1082 ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
1084 PlanState *planstate = node->planstate;
1085 SubPlan *subplan = (SubPlan *) node->xprstate.expr;
1086 EState *estate = parent->state;
1090 if (subplan->parParam != NIL)
1091 elog(ERROR, "direct correlated subquery unsupported as initplan");
1092 if (subplan->setParam == NIL)
1093 elog(ERROR, "setParam list of initplan is empty");
1094 if (bms_is_empty(planstate->plan->extParam))
1095 elog(ERROR, "extParam set of initplan is empty");
1098 * Don't actually re-scan: ExecSetParamPlan does it if needed.
1102 * Mark this subplan's output parameters as needing recalculation
1104 foreach(l, subplan->setParam)
1106 int paramid = lfirst_int(l);
1107 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
1109 prm->execPlan = node;
1110 parent->chgParam = bms_add_member(parent->chgParam, paramid);