]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeSubplan.c
Update misleading comment about the use of lanpltrusted ... it is
[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.68 2005/04/06 16:34:04 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(expr,
832                                                                   i,
833                                                                   NULL,
834                                                                   false);
835                         tlestate = makeNode(GenericExprState);
836                         tlestate->xprstate.expr = (Expr *) tle;
837                         tlestate->xprstate.evalfunc = NULL;
838                         tlestate->arg = exstate;
839                         lefttlist = lappend(lefttlist, tlestate);
840                         leftptlist = lappend(leftptlist, tle);
841
842                         /* Process righthand argument */
843                         exstate = (ExprState *) lsecond(fstate->args);
844                         expr = exstate->expr;
845                         tle = makeTargetEntry(expr,
846                                                                   i,
847                                                                   NULL,
848                                                                   false);
849                         tlestate = makeNode(GenericExprState);
850                         tlestate->xprstate.expr = (Expr *) tle;
851                         tlestate->xprstate.evalfunc = NULL;
852                         tlestate->arg = exstate;
853                         righttlist = lappend(righttlist, tlestate);
854                         rightptlist = lappend(rightptlist, tle);
855
856                         /* Lookup the combining function */
857                         fmgr_info(opexpr->opfuncid, &node->eqfunctions[i - 1]);
858                         node->eqfunctions[i - 1].fn_expr = (Node *) opexpr;
859
860                         /* Lookup the associated hash function */
861                         hashfn = get_op_hash_function(opexpr->opno);
862                         if (!OidIsValid(hashfn))
863                                 elog(ERROR, "could not find hash function for hash operator %u",
864                                          opexpr->opno);
865                         fmgr_info(hashfn, &node->hashfunctions[i - 1]);
866
867                         i++;
868                 }
869
870                 /*
871                  * Create a tupletable to hold these tuples.  (Note: we never
872                  * bother to free the tupletable explicitly; that's okay because
873                  * it will never store raw disk tuples that might have associated
874                  * buffer pins.  The only resource involved is memory, which will
875                  * be cleaned up by freeing the query context.)
876                  */
877                 tupTable = ExecCreateTupleTable(2);
878
879                 /*
880                  * Construct tupdescs, slots and projection nodes for left and
881                  * right sides.  The lefthand expressions will be evaluated in the
882                  * parent plan node's exprcontext, which we don't have access to
883                  * here.  Fortunately we can just pass NULL for now and fill it in
884                  * later (hack alert!).  The righthand expressions will be
885                  * evaluated in our own innerecontext.
886                  */
887                 tupDesc = ExecTypeFromTL(leftptlist, false);
888                 slot = ExecAllocTableSlot(tupTable);
889                 ExecSetSlotDescriptor(slot, tupDesc, true);
890                 node->projLeft = ExecBuildProjectionInfo(lefttlist,
891                                                                                                  NULL,
892                                                                                                  slot);
893
894                 tupDesc = ExecTypeFromTL(rightptlist, false);
895                 slot = ExecAllocTableSlot(tupTable);
896                 ExecSetSlotDescriptor(slot, tupDesc, true);
897                 node->projRight = ExecBuildProjectionInfo(righttlist,
898                                                                                                   node->innerecontext,
899                                                                                                   slot);
900         }
901 }
902
903 /* ----------------------------------------------------------------
904  *              ExecSetParamPlan
905  *
906  *              Executes an InitPlan subplan and sets its output parameters.
907  *
908  * This is called from ExecEvalParam() when the value of a PARAM_EXEC
909  * parameter is requested and the param's execPlan field is set (indicating
910  * that the param has not yet been evaluated).  This allows lazy evaluation
911  * of initplans: we don't run the subplan until/unless we need its output.
912  * Note that this routine MUST clear the execPlan fields of the plan's
913  * output parameters after evaluating them!
914  * ----------------------------------------------------------------
915  */
916 void
917 ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
918 {
919         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
920         PlanState  *planstate = node->planstate;
921         SubLinkType subLinkType = subplan->subLinkType;
922         MemoryContext oldcontext;
923         TupleTableSlot *slot;
924         ListCell   *l;
925         bool            found = false;
926         ArrayBuildState *astate = NULL;
927
928         /*
929          * Must switch to child query's per-query memory context.
930          */
931         oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
932
933         if (subLinkType == ANY_SUBLINK ||
934                 subLinkType == ALL_SUBLINK)
935                 elog(ERROR, "ANY/ALL subselect unsupported as initplan");
936
937         if (planstate->chgParam != NULL)
938                 ExecReScan(planstate, NULL);
939
940         for (slot = ExecProcNode(planstate);
941                  !TupIsNull(slot);
942                  slot = ExecProcNode(planstate))
943         {
944                 TupleDesc       tdesc = slot->tts_tupleDescriptor;
945                 int                     i = 1;
946
947                 if (subLinkType == EXISTS_SUBLINK)
948                 {
949                         /* There can be only one param... */
950                         int                     paramid = linitial_int(subplan->setParam);
951                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
952
953                         prm->execPlan = NULL;
954                         prm->value = BoolGetDatum(true);
955                         prm->isnull = false;
956                         found = true;
957                         break;
958                 }
959
960                 if (subLinkType == ARRAY_SUBLINK)
961                 {
962                         Datum           dvalue;
963                         bool            disnull;
964
965                         found = true;
966                         /* stash away current value */
967                         dvalue = slot_getattr(slot, 1, &disnull);
968                         astate = accumArrayResult(astate, dvalue, disnull,
969                                                                           tdesc->attrs[0]->atttypid,
970                                                                           oldcontext);
971                         /* keep scanning subplan to collect all values */
972                         continue;
973                 }
974
975                 if (found &&
976                         (subLinkType == EXPR_SUBLINK ||
977                          subLinkType == MULTIEXPR_SUBLINK))
978                         ereport(ERROR,
979                                         (errcode(ERRCODE_CARDINALITY_VIOLATION),
980                                          errmsg("more than one row returned by a subquery used as an expression")));
981
982                 found = true;
983
984                 /*
985                  * We need to copy the subplan's tuple into our own context, in
986                  * case any of the params are pass-by-ref type --- the pointers
987                  * stored in the param structs will point at this copied tuple!
988                  * node->curTuple keeps track of the copied tuple for eventual
989                  * freeing.
990                  */
991                 MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
992                 if (node->curTuple)
993                         heap_freetuple(node->curTuple);
994                 node->curTuple = ExecCopySlotTuple(slot);
995                 MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
996
997                 /*
998                  * Now set all the setParam params from the columns of the tuple
999                  */
1000                 foreach(l, subplan->setParam)
1001                 {
1002                         int                     paramid = lfirst_int(l);
1003                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1004
1005                         prm->execPlan = NULL;
1006                         prm->value = heap_getattr(node->curTuple, i, tdesc,
1007                                                                           &(prm->isnull));
1008                         i++;
1009                 }
1010         }
1011
1012         if (!found)
1013         {
1014                 if (subLinkType == EXISTS_SUBLINK)
1015                 {
1016                         /* There can be only one param... */
1017                         int                     paramid = linitial_int(subplan->setParam);
1018                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1019
1020                         prm->execPlan = NULL;
1021                         prm->value = BoolGetDatum(false);
1022                         prm->isnull = false;
1023                 }
1024                 else
1025                 {
1026                         foreach(l, subplan->setParam)
1027                         {
1028                                 int                     paramid = lfirst_int(l);
1029                                 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1030
1031                                 prm->execPlan = NULL;
1032                                 prm->value = (Datum) 0;
1033                                 prm->isnull = true;
1034                         }
1035                 }
1036         }
1037         else if (subLinkType == ARRAY_SUBLINK)
1038         {
1039                 /* There can be only one param... */
1040                 int                     paramid = linitial_int(subplan->setParam);
1041                 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1042
1043                 Assert(astate != NULL);
1044                 prm->execPlan = NULL;
1045                 /* We build the result in query context so it won't disappear */
1046                 prm->value = makeArrayResult(astate, econtext->ecxt_per_query_memory);
1047                 prm->isnull = false;
1048         }
1049
1050         MemoryContextSwitchTo(oldcontext);
1051 }
1052
1053 /* ----------------------------------------------------------------
1054  *              ExecEndSubPlan
1055  * ----------------------------------------------------------------
1056  */
1057 void
1058 ExecEndSubPlan(SubPlanState *node)
1059 {
1060         if (node->needShutdown)
1061         {
1062                 MemoryContext oldcontext;
1063
1064                 oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
1065                 ExecEndPlan(node->planstate, node->sub_estate);
1066                 MemoryContextSwitchTo(oldcontext);
1067                 FreeExecutorState(node->sub_estate);
1068                 node->sub_estate = NULL;
1069                 node->planstate = NULL;
1070                 node->needShutdown = false;
1071         }
1072 }
1073
1074 /*
1075  * Mark an initplan as needing recalculation
1076  */
1077 void
1078 ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
1079 {
1080         PlanState  *planstate = node->planstate;
1081         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
1082         EState     *estate = parent->state;
1083         ListCell   *l;
1084
1085         /* sanity checks */
1086         if (subplan->parParam != NIL)
1087                 elog(ERROR, "direct correlated subquery unsupported as initplan");
1088         if (subplan->setParam == NIL)
1089                 elog(ERROR, "setParam list of initplan is empty");
1090         if (bms_is_empty(planstate->plan->extParam))
1091                 elog(ERROR, "extParam set of initplan is empty");
1092
1093         /*
1094          * Don't actually re-scan: ExecSetParamPlan does it if needed.
1095          */
1096
1097         /*
1098          * Mark this subplan's output parameters as needing recalculation
1099          */
1100         foreach(l, subplan->setParam)
1101         {
1102                 int                     paramid = lfirst_int(l);
1103                 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
1104
1105                 prm->execPlan = node;
1106                 parent->chgParam = bms_add_member(parent->chgParam, paramid);
1107         }
1108 }