]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeSubplan.c
7d40fe8b1ed9f70aad6398c8cba9f2a597bbdb24
[postgresql] / src / backend / executor / nodeSubplan.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeSubplan.c
4  *        routines to support subselects
5  *
6  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  *        $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.67 2005/03/16 21:38:08 tgl Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /*
15  *       INTERFACE ROUTINES
16  *              ExecSubPlan  - process a subselect
17  *              ExecInitSubPlan - initialize a subselect
18  *              ExecEndSubPlan  - shut down a subselect
19  */
20 #include "postgres.h"
21
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"
30
31
32 static Datum ExecHashSubPlan(SubPlanState *node,
33                                 ExprContext *econtext,
34                                 bool *isNull);
35 static Datum ExecScanSubPlan(SubPlanState *node,
36                                 ExprContext *econtext,
37                                 bool *isNull);
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);
42
43
44 /* ----------------------------------------------------------------
45  *              ExecSubPlan
46  * ----------------------------------------------------------------
47  */
48 Datum
49 ExecSubPlan(SubPlanState *node,
50                         ExprContext *econtext,
51                         bool *isNull,
52                         ExprDoneCond *isDone)
53 {
54         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
55
56         /* Set default values for result flags: non-null, not a set result */
57         *isNull = false;
58         if (isDone)
59                 *isDone = ExprSingleResult;
60
61         if (subplan->setParam != NIL)
62                 elog(ERROR, "cannot set parent params from subquery");
63
64         if (subplan->useHashTable)
65                 return ExecHashSubPlan(node, econtext, isNull);
66         else
67                 return ExecScanSubPlan(node, econtext, isNull);
68 }
69
70 /*
71  * ExecHashSubPlan: store subselect result in an in-memory hash table
72  */
73 static Datum
74 ExecHashSubPlan(SubPlanState *node,
75                                 ExprContext *econtext,
76                                 bool *isNull)
77 {
78         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
79         PlanState  *planstate = node->planstate;
80         ExprContext *innerecontext = node->innerecontext;
81         TupleTableSlot *slot;
82
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");
86
87         /*
88          * If first time through or we need to rescan the subplan, build the
89          * hash table.
90          */
91         if (node->hashtable == NULL || planstate->chgParam != NULL)
92                 buildSubPlanHash(node);
93
94         /*
95          * The result for an empty subplan is always FALSE; no need to
96          * evaluate lefthand side.
97          */
98         *isNull = false;
99         if (!node->havehashrows && !node->havenullrows)
100                 return BoolGetDatum(false);
101
102         /*
103          * Evaluate lefthand expressions and form a projection tuple. First we
104          * have to set the econtext to use (hack alert!).
105          */
106         node->projLeft->pi_exprContext = econtext;
107         slot = ExecProject(node->projLeft, NULL);
108
109         /*
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.
115          */
116
117         /*
118          * Since the hashtable routines will use innerecontext's per-tuple
119          * memory as working memory, be sure to reset it for each tuple.
120          */
121         ResetExprContext(innerecontext);
122
123         /*
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
129          * result is FALSE.
130          *
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
137          * hash keys.
138          */
139         if (slotNoNulls(slot))
140         {
141                 if (node->havehashrows &&
142                         LookupTupleHashEntry(node->hashtable, slot, NULL) != NULL)
143                 {
144                         ExecClearTuple(slot);
145                         return BoolGetDatum(true);
146                 }
147                 if (node->havenullrows &&
148                         findPartialMatch(node->hashnulls, slot))
149                 {
150                         ExecClearTuple(slot);
151                         *isNull = true;
152                         return BoolGetDatum(false);
153                 }
154                 ExecClearTuple(slot);
155                 return BoolGetDatum(false);
156         }
157
158         /*
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.
167          */
168         if (node->hashnulls == NULL)
169         {
170                 ExecClearTuple(slot);
171                 return BoolGetDatum(false);
172         }
173         if (slotAllNulls(slot))
174         {
175                 ExecClearTuple(slot);
176                 *isNull = true;
177                 return BoolGetDatum(false);
178         }
179         /* Scan partly-null table first, since more likely to get a match */
180         if (node->havenullrows &&
181                 findPartialMatch(node->hashnulls, slot))
182         {
183                 ExecClearTuple(slot);
184                 *isNull = true;
185                 return BoolGetDatum(false);
186         }
187         if (node->havehashrows &&
188                 findPartialMatch(node->hashtable, slot))
189         {
190                 ExecClearTuple(slot);
191                 *isNull = true;
192                 return BoolGetDatum(false);
193         }
194         ExecClearTuple(slot);
195         return BoolGetDatum(false);
196 }
197
198 /*
199  * ExecScanSubPlan: default case where we have to rescan subplan each time
200  */
201 static Datum
202 ExecScanSubPlan(SubPlanState *node,
203                                 ExprContext *econtext,
204                                 bool *isNull)
205 {
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;
212         Datum           result;
213         bool            found = false;  /* TRUE if got at least one subplan tuple */
214         ListCell   *pvar;
215         ListCell   *l;
216         ArrayBuildState *astate = NULL;
217
218         /*
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.
222          */
223         oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
224
225         /*
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.)
229          */
230         Assert(list_length(subplan->parParam) == list_length(node->args));
231
232         forboth(l, subplan->parParam, pvar, node->args)
233         {
234                 int                     paramid = lfirst_int(l);
235                 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
236
237                 prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
238                                                                                            econtext,
239                                                                                            &(prm->isnull),
240                                                                                            NULL);
241                 planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
242         }
243
244         ExecReScan(planstate, NULL);
245
246         /*
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.
258          *
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
264          * this case).
265          */
266         result = BoolGetDatum(subLinkType == ALL_SUBLINK);
267         *isNull = false;
268
269         for (slot = ExecProcNode(planstate);
270                  !TupIsNull(slot);
271                  slot = ExecProcNode(planstate))
272         {
273                 TupleDesc       tdesc = slot->tts_tupleDescriptor;
274                 Datum           rowresult = BoolGetDatum(!useOr);
275                 bool            rownull = false;
276                 int                     col = 1;
277                 ListCell   *plst;
278
279                 if (subLinkType == EXISTS_SUBLINK)
280                 {
281                         found = true;
282                         result = BoolGetDatum(true);
283                         break;
284                 }
285
286                 if (subLinkType == EXPR_SUBLINK)
287                 {
288                         /* cannot allow multiple input tuples for EXPR sublink */
289                         if (found)
290                                 ereport(ERROR,
291                                                 (errcode(ERRCODE_CARDINALITY_VIOLATION),
292                                                  errmsg("more than one row returned by a subquery used as an expression")));
293                         found = true;
294
295                         /*
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.
302                          */
303                         MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
304                         if (node->curTuple)
305                                 heap_freetuple(node->curTuple);
306                         node->curTuple = ExecCopySlotTuple(slot);
307                         MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
308
309                         result = heap_getattr(node->curTuple, col, tdesc, isNull);
310                         /* keep scanning subplan to make sure there's only one tuple */
311                         continue;
312                 }
313
314                 if (subLinkType == ARRAY_SUBLINK)
315                 {
316                         Datum           dvalue;
317                         bool            disnull;
318
319                         found = true;
320                         /* stash away current value */
321                         dvalue = slot_getattr(slot, 1, &disnull);
322                         astate = accumArrayResult(astate, dvalue, disnull,
323                                                                           tdesc->attrs[0]->atttypid,
324                                                                           oldcontext);
325                         /* keep scanning subplan to collect all values */
326                         continue;
327                 }
328
329                 /* cannot allow multiple input tuples for MULTIEXPR sublink either */
330                 if (subLinkType == MULTIEXPR_SUBLINK && found)
331                         ereport(ERROR,
332                                         (errcode(ERRCODE_CARDINALITY_VIOLATION),
333                                          errmsg("more than one row returned by a subquery used as an expression")));
334
335                 found = true;
336
337                 /*
338                  * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
339                  * operators for columns of tuple.
340                  */
341                 Assert(list_length(node->exprs) == list_length(subplan->paramIds));
342
343                 forboth(l, node->exprs, plst, subplan->paramIds)
344                 {
345                         ExprState  *exprstate = (ExprState *) lfirst(l);
346                         int                     paramid = lfirst_int(plst);
347                         ParamExecData *prmdata;
348                         Datum           expresult;
349                         bool            expnull;
350
351                         /*
352                          * Load up the Param representing this column of the
353                          * sub-select.
354                          */
355                         prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
356                         Assert(prmdata->execPlan == NULL);
357                         prmdata->value = slot_getattr(slot, col,
358                                                                                   &(prmdata->isnull));
359
360                         /*
361                          * Now we can eval the combining operator for this column.
362                          */
363                         expresult = ExecEvalExprSwitchContext(exprstate, econtext,
364                                                                                                   &expnull, NULL);
365
366                         /*
367                          * Combine the result into the row result as appropriate.
368                          */
369                         if (col == 1)
370                         {
371                                 rowresult = expresult;
372                                 rownull = expnull;
373                         }
374                         else if (useOr)
375                         {
376                                 /* combine within row per OR semantics */
377                                 if (expnull)
378                                         rownull = true;
379                                 else if (DatumGetBool(expresult))
380                                 {
381                                         rowresult = BoolGetDatum(true);
382                                         rownull = false;
383                                         break;          /* needn't look at any more columns */
384                                 }
385                         }
386                         else
387                         {
388                                 /* combine within row per AND semantics */
389                                 if (expnull)
390                                         rownull = true;
391                                 else if (!DatumGetBool(expresult))
392                                 {
393                                         rowresult = BoolGetDatum(false);
394                                         rownull = false;
395                                         break;          /* needn't look at any more columns */
396                                 }
397                         }
398
399                         col++;
400                 }
401
402                 if (subLinkType == ANY_SUBLINK)
403                 {
404                         /* combine across rows per OR semantics */
405                         if (rownull)
406                                 *isNull = true;
407                         else if (DatumGetBool(rowresult))
408                         {
409                                 result = BoolGetDatum(true);
410                                 *isNull = false;
411                                 break;                  /* needn't look at any more rows */
412                         }
413                 }
414                 else if (subLinkType == ALL_SUBLINK)
415                 {
416                         /* combine across rows per AND semantics */
417                         if (rownull)
418                                 *isNull = true;
419                         else if (!DatumGetBool(rowresult))
420                         {
421                                 result = BoolGetDatum(false);
422                                 *isNull = false;
423                                 break;                  /* needn't look at any more rows */
424                         }
425                 }
426                 else
427                 {
428                         /* must be MULTIEXPR_SUBLINK */
429                         result = rowresult;
430                         *isNull = rownull;
431                 }
432         }
433
434         if (!found)
435         {
436                 /*
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.
440                  */
441                 if (subLinkType == EXPR_SUBLINK ||
442                         subLinkType == ARRAY_SUBLINK ||
443                         subLinkType == MULTIEXPR_SUBLINK)
444                 {
445                         result = (Datum) 0;
446                         *isNull = true;
447                 }
448         }
449         else if (subLinkType == ARRAY_SUBLINK)
450         {
451                 Assert(astate != NULL);
452                 /* We return the result in the caller's context */
453                 result = makeArrayResult(astate, oldcontext);
454         }
455
456         MemoryContextSwitchTo(oldcontext);
457
458         return result;
459 }
460
461 /*
462  * buildSubPlanHash: load hash table by scanning subplan output.
463  */
464 static void
465 buildSubPlanHash(SubPlanState *node)
466 {
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;
473         int                     nbuckets;
474         TupleTableSlot *slot;
475
476         Assert(subplan->subLinkType == ANY_SUBLINK);
477         Assert(!subplan->useOr);
478
479         /*
480          * If we already had any hash tables, destroy 'em; then create empty
481          * hash table(s).
482          *
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.)
490          *
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.
493          */
494         MemoryContextReset(node->tablecxt);
495         node->hashtable = NULL;
496         node->hashnulls = NULL;
497         node->havehashrows = false;
498         node->havenullrows = false;
499
500         nbuckets = (int) ceil(planstate->plan->plan_rows);
501         if (nbuckets < 1)
502                 nbuckets = 1;
503
504         node->hashtable = BuildTupleHashTable(ncols,
505                                                                                   node->keyColIdx,
506                                                                                   node->eqfunctions,
507                                                                                   node->hashfunctions,
508                                                                                   nbuckets,
509                                                                                   sizeof(TupleHashEntryData),
510                                                                                   node->tablecxt,
511                                                                                   tempcxt);
512
513         if (!subplan->unknownEqFalse)
514         {
515                 if (ncols == 1)
516                         nbuckets = 1;           /* there can only be one entry */
517                 else
518                 {
519                         nbuckets /= 16;
520                         if (nbuckets < 1)
521                                 nbuckets = 1;
522                 }
523                 node->hashnulls = BuildTupleHashTable(ncols,
524                                                                                           node->keyColIdx,
525                                                                                           node->eqfunctions,
526                                                                                           node->hashfunctions,
527                                                                                           nbuckets,
528                                                                                           sizeof(TupleHashEntryData),
529                                                                                           node->tablecxt,
530                                                                                           tempcxt);
531         }
532
533         /*
534          * We are probably in a short-lived expression-evaluation context.
535          * Switch to the child plan's per-query context for calling
536          * ExecProcNode.
537          */
538         oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
539
540         /*
541          * Reset subplan to start.
542          */
543         ExecReScan(planstate, NULL);
544
545         /*
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
548          * stored.
549          */
550         for (slot = ExecProcNode(planstate);
551                  !TupIsNull(slot);
552                  slot = ExecProcNode(planstate))
553         {
554                 int                     col = 1;
555                 ListCell   *plst;
556                 bool            isnew;
557
558                 /*
559                  * Load up the Params representing the raw sub-select outputs,
560                  * then form the projection tuple to store in the hashtable.
561                  */
562                 foreach(plst, subplan->paramIds)
563                 {
564                         int                     paramid = lfirst_int(plst);
565                         ParamExecData *prmdata;
566
567                         prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
568                         Assert(prmdata->execPlan == NULL);
569                         prmdata->value = slot_getattr(slot, col,
570                                                                                   &(prmdata->isnull));
571                         col++;
572                 }
573                 slot = ExecProject(node->projRight, NULL);
574
575                 /*
576                  * If result contains any nulls, store separately or not at all.
577                  */
578                 if (slotNoNulls(slot))
579                 {
580                         (void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
581                         node->havehashrows = true;
582                 }
583                 else if (node->hashnulls)
584                 {
585                         (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
586                         node->havenullrows = true;
587                 }
588
589                 /*
590                  * Reset innerecontext after each inner tuple to free any memory
591                  * used in hash computation or comparison routines.
592                  */
593                 ResetExprContext(innerecontext);
594         }
595
596         /*
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.)
602          */
603         ExecClearTuple(node->projRight->pi_slot);
604
605         MemoryContextSwitchTo(oldcontext);
606 }
607
608 /*
609  * findPartialMatch: does the hashtable contain an entry that is not
610  * provably distinct from the tuple?
611  *
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.
615  */
616 static bool
617 findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot)
618 {
619         int                     numCols = hashtable->numCols;
620         AttrNumber *keyColIdx = hashtable->keyColIdx;
621         TupleHashIterator hashiter;
622         TupleHashEntry entry;
623
624         ResetTupleHashIterator(hashtable, &hashiter);
625         while ((entry = ScanTupleHashTable(&hashiter)) != NULL)
626         {
627                 ExecStoreTuple(entry->firstTuple, hashtable->tableslot,
628                                            InvalidBuffer, false);
629                 if (!execTuplesUnequal(hashtable->tableslot, slot,
630                                                            numCols, keyColIdx,
631                                                            hashtable->eqfunctions,
632                                                            hashtable->tempcxt))
633                         return true;
634         }
635         return false;
636 }
637
638 /*
639  * slotAllNulls: is the slot completely NULL?
640  *
641  * This does not test for dropped columns, which is OK because we only
642  * use it on projected tuples.
643  */
644 static bool
645 slotAllNulls(TupleTableSlot *slot)
646 {
647         int                     ncols = slot->tts_tupleDescriptor->natts;
648         int                     i;
649
650         for (i = 1; i <= ncols; i++)
651         {
652                 if (!slot_attisnull(slot, i))
653                         return false;
654         }
655         return true;
656 }
657
658 /*
659  * slotNoNulls: is the slot entirely not NULL?
660  *
661  * This does not test for dropped columns, which is OK because we only
662  * use it on projected tuples.
663  */
664 static bool
665 slotNoNulls(TupleTableSlot *slot)
666 {
667         int                     ncols = slot->tts_tupleDescriptor->natts;
668         int                     i;
669
670         for (i = 1; i <= ncols; i++)
671         {
672                 if (slot_attisnull(slot, i))
673                         return false;
674         }
675         return true;
676 }
677
678 /* ----------------------------------------------------------------
679  *              ExecInitSubPlan
680  * ----------------------------------------------------------------
681  */
682 void
683 ExecInitSubPlan(SubPlanState *node, EState *estate)
684 {
685         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
686         EState     *sp_estate;
687         MemoryContext oldcontext;
688
689         /*
690          * Do access checking on the rangetable entries in the subquery.
691          */
692         ExecCheckRTPerms(subplan->rtable);
693
694         /*
695          * initialize my state
696          */
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;
708
709         /*
710          * create an EState for the subplan
711          *
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...
716          */
717         sp_estate = CreateExecutorState();
718         node->sub_estate = sp_estate;
719
720         oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
721
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;
730
731         /*
732          * Start up the subplan (this is a very cut-down form of InitPlan())
733          */
734         node->planstate = ExecInitNode(subplan->plan, sp_estate);
735
736         node->needShutdown = true;      /* now we need to shutdown the subplan */
737
738         MemoryContextSwitchTo(oldcontext);
739
740         /*
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
743          * evaluation.
744          *
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...
748          */
749         if (subplan->setParam != NIL)
750         {
751                 ListCell   *lst;
752
753                 foreach(lst, subplan->setParam)
754                 {
755                         int                     paramid = lfirst_int(lst);
756                         ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
757
758                         prm->execPlan = node;
759                 }
760         }
761
762         /*
763          * If we are going to hash the subquery output, initialize relevant
764          * stuff.  (We don't create the hashtable until needed, though.)
765          */
766         if (subplan->useHashTable)
767         {
768                 int                     ncols,
769                                         i;
770                 TupleDesc       tupDesc;
771                 TupleTable      tupTable;
772                 TupleTableSlot *slot;
773                 List       *lefttlist,
774                                    *righttlist,
775                                    *leftptlist,
776                                    *rightptlist;
777                 ListCell   *lexpr;
778
779                 /* We need a memory context to hold the hash table(s) */
780                 node->tablecxt =
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;
793
794                 /*
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
804                  * ExecTypeFromTL).
805                  *
806                  * We also extract the combining operators themselves to initialize
807                  * the equality and hashing functions for the hash tables.
808                  */
809                 lefttlist = righttlist = NIL;
810                 leftptlist = rightptlist = NIL;
811                 node->eqfunctions = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
812                 node->hashfunctions = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
813                 i = 1;
814                 foreach(lexpr, node->exprs)
815                 {
816                         FuncExprState *fstate = (FuncExprState *) lfirst(lexpr);
817                         OpExpr     *opexpr = (OpExpr *) fstate->xprstate.expr;
818                         ExprState  *exstate;
819                         Expr       *expr;
820                         TargetEntry *tle;
821                         GenericExprState *tlestate;
822                         Oid                     hashfn;
823
824                         Assert(IsA(fstate, FuncExprState));
825                         Assert(IsA(opexpr, OpExpr));
826                         Assert(list_length(fstate->args) == 2);
827
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),
834                                                                                          NULL,
835                                                                                          false),
836                                                                   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);
843
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),
850                                                                                          NULL,
851                                                                                          false),
852                                                                   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);
859
860                         /* Lookup the combining function */
861                         fmgr_info(opexpr->opfuncid, &node->eqfunctions[i - 1]);
862                         node->eqfunctions[i - 1].fn_expr = (Node *) opexpr;
863
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",
868                                          opexpr->opno);
869                         fmgr_info(hashfn, &node->hashfunctions[i - 1]);
870
871                         i++;
872                 }
873
874                 /*
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.)
880                  */
881                 tupTable = ExecCreateTupleTable(2);
882
883                 /*
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.
890                  */
891                 tupDesc = ExecTypeFromTL(leftptlist, false);
892                 slot = ExecAllocTableSlot(tupTable);
893                 ExecSetSlotDescriptor(slot, tupDesc, true);
894                 node->projLeft = ExecBuildProjectionInfo(lefttlist,
895                                                                                                  NULL,
896                                                                                                  slot);
897
898                 tupDesc = ExecTypeFromTL(rightptlist, false);
899                 slot = ExecAllocTableSlot(tupTable);
900                 ExecSetSlotDescriptor(slot, tupDesc, true);
901                 node->projRight = ExecBuildProjectionInfo(righttlist,
902                                                                                                   node->innerecontext,
903                                                                                                   slot);
904         }
905 }
906
907 /* ----------------------------------------------------------------
908  *              ExecSetParamPlan
909  *
910  *              Executes an InitPlan subplan and sets its output parameters.
911  *
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  * ----------------------------------------------------------------
919  */
920 void
921 ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
922 {
923         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
924         PlanState  *planstate = node->planstate;
925         SubLinkType subLinkType = subplan->subLinkType;
926         MemoryContext oldcontext;
927         TupleTableSlot *slot;
928         ListCell   *l;
929         bool            found = false;
930         ArrayBuildState *astate = NULL;
931
932         /*
933          * Must switch to child query's per-query memory context.
934          */
935         oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
936
937         if (subLinkType == ANY_SUBLINK ||
938                 subLinkType == ALL_SUBLINK)
939                 elog(ERROR, "ANY/ALL subselect unsupported as initplan");
940
941         if (planstate->chgParam != NULL)
942                 ExecReScan(planstate, NULL);
943
944         for (slot = ExecProcNode(planstate);
945                  !TupIsNull(slot);
946                  slot = ExecProcNode(planstate))
947         {
948                 TupleDesc       tdesc = slot->tts_tupleDescriptor;
949                 int                     i = 1;
950
951                 if (subLinkType == EXISTS_SUBLINK)
952                 {
953                         /* There can be only one param... */
954                         int                     paramid = linitial_int(subplan->setParam);
955                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
956
957                         prm->execPlan = NULL;
958                         prm->value = BoolGetDatum(true);
959                         prm->isnull = false;
960                         found = true;
961                         break;
962                 }
963
964                 if (subLinkType == ARRAY_SUBLINK)
965                 {
966                         Datum           dvalue;
967                         bool            disnull;
968
969                         found = true;
970                         /* stash away current value */
971                         dvalue = slot_getattr(slot, 1, &disnull);
972                         astate = accumArrayResult(astate, dvalue, disnull,
973                                                                           tdesc->attrs[0]->atttypid,
974                                                                           oldcontext);
975                         /* keep scanning subplan to collect all values */
976                         continue;
977                 }
978
979                 if (found &&
980                         (subLinkType == EXPR_SUBLINK ||
981                          subLinkType == MULTIEXPR_SUBLINK))
982                         ereport(ERROR,
983                                         (errcode(ERRCODE_CARDINALITY_VIOLATION),
984                                          errmsg("more than one row returned by a subquery used as an expression")));
985
986                 found = true;
987
988                 /*
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
993                  * freeing.
994                  */
995                 MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
996                 if (node->curTuple)
997                         heap_freetuple(node->curTuple);
998                 node->curTuple = ExecCopySlotTuple(slot);
999                 MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
1000
1001                 /*
1002                  * Now set all the setParam params from the columns of the tuple
1003                  */
1004                 foreach(l, subplan->setParam)
1005                 {
1006                         int                     paramid = lfirst_int(l);
1007                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1008
1009                         prm->execPlan = NULL;
1010                         prm->value = heap_getattr(node->curTuple, i, tdesc,
1011                                                                           &(prm->isnull));
1012                         i++;
1013                 }
1014         }
1015
1016         if (!found)
1017         {
1018                 if (subLinkType == EXISTS_SUBLINK)
1019                 {
1020                         /* There can be only one param... */
1021                         int                     paramid = linitial_int(subplan->setParam);
1022                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1023
1024                         prm->execPlan = NULL;
1025                         prm->value = BoolGetDatum(false);
1026                         prm->isnull = false;
1027                 }
1028                 else
1029                 {
1030                         foreach(l, subplan->setParam)
1031                         {
1032                                 int                     paramid = lfirst_int(l);
1033                                 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1034
1035                                 prm->execPlan = NULL;
1036                                 prm->value = (Datum) 0;
1037                                 prm->isnull = true;
1038                         }
1039                 }
1040         }
1041         else if (subLinkType == ARRAY_SUBLINK)
1042         {
1043                 /* There can be only one param... */
1044                 int                     paramid = linitial_int(subplan->setParam);
1045                 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1046
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;
1052         }
1053
1054         MemoryContextSwitchTo(oldcontext);
1055 }
1056
1057 /* ----------------------------------------------------------------
1058  *              ExecEndSubPlan
1059  * ----------------------------------------------------------------
1060  */
1061 void
1062 ExecEndSubPlan(SubPlanState *node)
1063 {
1064         if (node->needShutdown)
1065         {
1066                 MemoryContext oldcontext;
1067
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;
1075         }
1076 }
1077
1078 /*
1079  * Mark an initplan as needing recalculation
1080  */
1081 void
1082 ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
1083 {
1084         PlanState  *planstate = node->planstate;
1085         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
1086         EState     *estate = parent->state;
1087         ListCell   *l;
1088
1089         /* sanity checks */
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");
1096
1097         /*
1098          * Don't actually re-scan: ExecSetParamPlan does it if needed.
1099          */
1100
1101         /*
1102          * Mark this subplan's output parameters as needing recalculation
1103          */
1104         foreach(l, subplan->setParam)
1105         {
1106                 int                     paramid = lfirst_int(l);
1107                 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
1108
1109                 prm->execPlan = node;
1110                 parent->chgParam = bms_add_member(parent->chgParam, paramid);
1111         }
1112 }