]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeSubplan.c
Adjust TupleHashTables to use MinimalTuple format for contained tuples.
[postgresql] / src / backend / executor / nodeSubplan.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeSubplan.c
4  *        routines to support subselects
5  *
6  * Portions Copyright (c) 1996-2006, 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.76 2006/06/28 17:05:49 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 "optimizer/clauses.h"
27 #include "parser/parse_expr.h"
28 #include "utils/array.h"
29 #include "utils/datum.h"
30 #include "utils/lsyscache.h"
31 #include "utils/memutils.h"
32
33
34 static Datum ExecHashSubPlan(SubPlanState *node,
35                                 ExprContext *econtext,
36                                 bool *isNull);
37 static Datum ExecScanSubPlan(SubPlanState *node,
38                                 ExprContext *econtext,
39                                 bool *isNull);
40 static void buildSubPlanHash(SubPlanState *node);
41 static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot);
42 static bool slotAllNulls(TupleTableSlot *slot);
43 static bool slotNoNulls(TupleTableSlot *slot);
44
45
46 /* ----------------------------------------------------------------
47  *              ExecSubPlan
48  * ----------------------------------------------------------------
49  */
50 Datum
51 ExecSubPlan(SubPlanState *node,
52                         ExprContext *econtext,
53                         bool *isNull,
54                         ExprDoneCond *isDone)
55 {
56         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
57
58         /* Set default values for result flags: non-null, not a set result */
59         *isNull = false;
60         if (isDone)
61                 *isDone = ExprSingleResult;
62
63         if (subplan->setParam != NIL)
64                 elog(ERROR, "cannot set parent params from subquery");
65
66         if (subplan->useHashTable)
67                 return ExecHashSubPlan(node, econtext, isNull);
68         else
69                 return ExecScanSubPlan(node, econtext, isNull);
70 }
71
72 /*
73  * ExecHashSubPlan: store subselect result in an in-memory hash table
74  */
75 static Datum
76 ExecHashSubPlan(SubPlanState *node,
77                                 ExprContext *econtext,
78                                 bool *isNull)
79 {
80         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
81         PlanState  *planstate = node->planstate;
82         ExprContext *innerecontext = node->innerecontext;
83         TupleTableSlot *slot;
84
85         /* Shouldn't have any direct correlation Vars */
86         if (subplan->parParam != NIL || node->args != NIL)
87                 elog(ERROR, "hashed subplan with direct correlation not supported");
88
89         /*
90          * If first time through or we need to rescan the subplan, build the hash
91          * table.
92          */
93         if (node->hashtable == NULL || planstate->chgParam != NULL)
94                 buildSubPlanHash(node);
95
96         /*
97          * The result for an empty subplan is always FALSE; no need to evaluate
98          * lefthand side.
99          */
100         *isNull = false;
101         if (!node->havehashrows && !node->havenullrows)
102                 return BoolGetDatum(false);
103
104         /*
105          * Evaluate lefthand expressions and form a projection tuple. First we
106          * have to set the econtext to use (hack alert!).
107          */
108         node->projLeft->pi_exprContext = econtext;
109         slot = ExecProject(node->projLeft, NULL);
110
111         /*
112          * Note: because we are typically called in a per-tuple context, we have
113          * to explicitly clear the projected tuple before returning. Otherwise,
114          * we'll have a double-free situation: the per-tuple context will probably
115          * be reset before we're called again, and then the tuple slot will think
116          * it still needs to free the tuple.
117          */
118
119         /*
120          * Since the hashtable routines will use innerecontext's per-tuple memory
121          * as working memory, be sure to reset it for each tuple.
122          */
123         ResetExprContext(innerecontext);
124
125         /*
126          * If the LHS is all non-null, probe for an exact match in the main hash
127          * table.  If we find one, the result is TRUE. Otherwise, scan the
128          * partly-null table to see if there are any rows that aren't provably
129          * unequal to the LHS; if so, the result is UNKNOWN.  (We skip that part
130          * if we don't care about UNKNOWN.) Otherwise, the result is FALSE.
131          *
132          * Note: the reason we can avoid a full scan of the main hash table is
133          * that the combining operators are assumed never to yield NULL when both
134          * inputs are non-null.  If they were to do so, we might need to produce
135          * UNKNOWN instead of FALSE because of an UNKNOWN result in comparing the
136          * LHS to some main-table entry --- which is a comparison we will not even
137          * make, unless there's a chance match of 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 we
160          * don't care about UNKNOWN, just return FALSE.  Otherwise, if the LHS is
161          * wholly NULL, immediately return UNKNOWN.  (Since the combining
162          * operators are strict, the result could only be FALSE if the sub-select
163          * were empty, but we already handled that case.) Otherwise, we must scan
164          * both the main and partly-null tables to see if there are any rows that
165          * aren't provably unequal to the LHS; if so, the result is UNKNOWN.
166          * 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         MemoryContext oldcontext;
210         TupleTableSlot *slot;
211         Datum           result;
212         bool            found = false;  /* TRUE if got at least one subplan tuple */
213         ListCell   *pvar;
214         ListCell   *l;
215         ArrayBuildState *astate = NULL;
216
217         /*
218          * We are probably in a short-lived expression-evaluation context. Switch
219          * to the child plan's per-query context for manipulating its chgParam,
220          * calling ExecProcNode on it, etc.
221          */
222         oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
223
224         /*
225          * Set Params of this plan from parent plan correlation values. (Any
226          * calculation we have to do is done in the parent econtext, since the
227          * Param values don't need to have per-query lifetime.)
228          */
229         Assert(list_length(subplan->parParam) == list_length(node->args));
230
231         forboth(l, subplan->parParam, pvar, node->args)
232         {
233                 int                     paramid = lfirst_int(l);
234                 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
235
236                 prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
237                                                                                            econtext,
238                                                                                            &(prm->isnull),
239                                                                                            NULL);
240                 planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
241         }
242
243         ExecReScan(planstate, NULL);
244
245         /*
246          * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result
247          * is boolean as are the results of the combining operators. We combine
248          * results across tuples (if the subplan produces more than one) using OR
249          * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
250          * (ROWCOMPARE_SUBLINK doesn't allow multiple tuples from the subplan.)
251          * NULL results from the combining operators are handled according to the
252          * usual SQL semantics for OR and AND.  The result for no input tuples is
253          * FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
254          * ROWCOMPARE_SUBLINK.
255          *
256          * For EXPR_SUBLINK we require the subplan to produce no more than one
257          * tuple, else an error is raised. For ARRAY_SUBLINK we allow the subplan
258          * to produce more than one tuple. In either case, if zero tuples are
259          * produced, we return NULL. Assuming we get a tuple, we just use its
260          * first column (there can be only one non-junk column in this case).
261          */
262         result = BoolGetDatum(subLinkType == ALL_SUBLINK);
263         *isNull = false;
264
265         for (slot = ExecProcNode(planstate);
266                  !TupIsNull(slot);
267                  slot = ExecProcNode(planstate))
268         {
269                 TupleDesc       tdesc = slot->tts_tupleDescriptor;
270                 Datum           rowresult;
271                 bool            rownull;
272                 int                     col;
273                 ListCell   *plst;
274
275                 if (subLinkType == EXISTS_SUBLINK)
276                 {
277                         found = true;
278                         result = BoolGetDatum(true);
279                         break;
280                 }
281
282                 if (subLinkType == EXPR_SUBLINK)
283                 {
284                         /* cannot allow multiple input tuples for EXPR sublink */
285                         if (found)
286                                 ereport(ERROR,
287                                                 (errcode(ERRCODE_CARDINALITY_VIOLATION),
288                                                  errmsg("more than one row returned by a subquery used as an expression")));
289                         found = true;
290
291                         /*
292                          * We need to copy the subplan's tuple in case the result is of
293                          * pass-by-ref type --- our return value will point into this
294                          * copied tuple!  Can't use the subplan's instance of the tuple
295                          * since it won't still be valid after next ExecProcNode() call.
296                          * node->curTuple keeps track of the copied tuple for eventual
297                          * freeing.
298                          */
299                         MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
300                         if (node->curTuple)
301                                 heap_freetuple(node->curTuple);
302                         node->curTuple = ExecCopySlotTuple(slot);
303                         MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
304
305                         result = heap_getattr(node->curTuple, 1, tdesc, isNull);
306                         /* keep scanning subplan to make sure there's only one tuple */
307                         continue;
308                 }
309
310                 if (subLinkType == ARRAY_SUBLINK)
311                 {
312                         Datum           dvalue;
313                         bool            disnull;
314
315                         found = true;
316                         /* stash away current value */
317                         dvalue = slot_getattr(slot, 1, &disnull);
318                         astate = accumArrayResult(astate, dvalue, disnull,
319                                                                           tdesc->attrs[0]->atttypid,
320                                                                           oldcontext);
321                         /* keep scanning subplan to collect all values */
322                         continue;
323                 }
324
325                 /* cannot allow multiple input tuples for ROWCOMPARE sublink either */
326                 if (subLinkType == ROWCOMPARE_SUBLINK && found)
327                         ereport(ERROR,
328                                         (errcode(ERRCODE_CARDINALITY_VIOLATION),
329                                          errmsg("more than one row returned by a subquery used as an expression")));
330
331                 found = true;
332
333                 /*
334                  * For ALL, ANY, and ROWCOMPARE sublinks, load up the Params
335                  * representing the columns of the sub-select, and then evaluate
336                  * the combining expression.
337                  */
338                 col = 1;
339                 foreach(plst, subplan->paramIds)
340                 {
341                         int                     paramid = lfirst_int(plst);
342                         ParamExecData *prmdata;
343
344                         prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
345                         Assert(prmdata->execPlan == NULL);
346                         prmdata->value = slot_getattr(slot, col, &(prmdata->isnull));
347                         col++;
348                 }
349
350                 rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext,
351                                                                                           &rownull, NULL);
352
353                 if (subLinkType == ANY_SUBLINK)
354                 {
355                         /* combine across rows per OR semantics */
356                         if (rownull)
357                                 *isNull = true;
358                         else if (DatumGetBool(rowresult))
359                         {
360                                 result = BoolGetDatum(true);
361                                 *isNull = false;
362                                 break;                  /* needn't look at any more rows */
363                         }
364                 }
365                 else if (subLinkType == ALL_SUBLINK)
366                 {
367                         /* combine across rows per AND semantics */
368                         if (rownull)
369                                 *isNull = true;
370                         else if (!DatumGetBool(rowresult))
371                         {
372                                 result = BoolGetDatum(false);
373                                 *isNull = false;
374                                 break;                  /* needn't look at any more rows */
375                         }
376                 }
377                 else
378                 {
379                         /* must be ROWCOMPARE_SUBLINK */
380                         result = rowresult;
381                         *isNull = rownull;
382                 }
383         }
384
385         if (!found)
386         {
387                 /*
388                  * deal with empty subplan result.      result/isNull were previously
389                  * initialized correctly for all sublink types except EXPR, ARRAY, and
390                  * ROWCOMPARE; for those, return NULL.
391                  */
392                 if (subLinkType == EXPR_SUBLINK ||
393                         subLinkType == ARRAY_SUBLINK ||
394                         subLinkType == ROWCOMPARE_SUBLINK)
395                 {
396                         result = (Datum) 0;
397                         *isNull = true;
398                 }
399         }
400         else if (subLinkType == ARRAY_SUBLINK)
401         {
402                 Assert(astate != NULL);
403                 /* We return the result in the caller's context */
404                 result = makeArrayResult(astate, oldcontext);
405         }
406
407         MemoryContextSwitchTo(oldcontext);
408
409         return result;
410 }
411
412 /*
413  * buildSubPlanHash: load hash table by scanning subplan output.
414  */
415 static void
416 buildSubPlanHash(SubPlanState *node)
417 {
418         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
419         PlanState  *planstate = node->planstate;
420         int                     ncols = list_length(subplan->paramIds);
421         ExprContext *innerecontext = node->innerecontext;
422         MemoryContext tempcxt = innerecontext->ecxt_per_tuple_memory;
423         MemoryContext oldcontext;
424         int                     nbuckets;
425         TupleTableSlot *slot;
426
427         Assert(subplan->subLinkType == ANY_SUBLINK);
428
429         /*
430          * If we already had any hash tables, destroy 'em; then create empty hash
431          * table(s).
432          *
433          * If we need to distinguish accurately between FALSE and UNKNOWN (i.e.,
434          * NULL) results of the IN operation, then we have to store subplan output
435          * rows that are partly or wholly NULL.  We store such rows in a separate
436          * hash table that we expect will be much smaller than the main table. (We
437          * can use hashing to eliminate partly-null rows that are not distinct.
438          * We keep them separate to minimize the cost of the inevitable full-table
439          * searches; see findPartialMatch.)
440          *
441          * If it's not necessary to distinguish FALSE and UNKNOWN, then we don't
442          * need to store subplan output rows that contain NULL.
443          */
444         MemoryContextReset(node->tablecxt);
445         node->hashtable = NULL;
446         node->hashnulls = NULL;
447         node->havehashrows = false;
448         node->havenullrows = false;
449
450         nbuckets = (int) ceil(planstate->plan->plan_rows);
451         if (nbuckets < 1)
452                 nbuckets = 1;
453
454         node->hashtable = BuildTupleHashTable(ncols,
455                                                                                   node->keyColIdx,
456                                                                                   node->eqfunctions,
457                                                                                   node->hashfunctions,
458                                                                                   nbuckets,
459                                                                                   sizeof(TupleHashEntryData),
460                                                                                   node->tablecxt,
461                                                                                   tempcxt);
462
463         if (!subplan->unknownEqFalse)
464         {
465                 if (ncols == 1)
466                         nbuckets = 1;           /* there can only be one entry */
467                 else
468                 {
469                         nbuckets /= 16;
470                         if (nbuckets < 1)
471                                 nbuckets = 1;
472                 }
473                 node->hashnulls = BuildTupleHashTable(ncols,
474                                                                                           node->keyColIdx,
475                                                                                           node->eqfunctions,
476                                                                                           node->hashfunctions,
477                                                                                           nbuckets,
478                                                                                           sizeof(TupleHashEntryData),
479                                                                                           node->tablecxt,
480                                                                                           tempcxt);
481         }
482
483         /*
484          * We are probably in a short-lived expression-evaluation context. Switch
485          * to the child plan's per-query context for calling ExecProcNode.
486          */
487         oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
488
489         /*
490          * Reset subplan to start.
491          */
492         ExecReScan(planstate, NULL);
493
494         /*
495          * Scan the subplan and load the hash table(s).  Note that when there are
496          * duplicate rows coming out of the sub-select, only one copy is stored.
497          */
498         for (slot = ExecProcNode(planstate);
499                  !TupIsNull(slot);
500                  slot = ExecProcNode(planstate))
501         {
502                 int                     col = 1;
503                 ListCell   *plst;
504                 bool            isnew;
505
506                 /*
507                  * Load up the Params representing the raw sub-select outputs, then
508                  * form the projection tuple to store in the hashtable.
509                  */
510                 foreach(plst, subplan->paramIds)
511                 {
512                         int                     paramid = lfirst_int(plst);
513                         ParamExecData *prmdata;
514
515                         prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
516                         Assert(prmdata->execPlan == NULL);
517                         prmdata->value = slot_getattr(slot, col,
518                                                                                   &(prmdata->isnull));
519                         col++;
520                 }
521                 slot = ExecProject(node->projRight, NULL);
522
523                 /*
524                  * If result contains any nulls, store separately or not at all.
525                  */
526                 if (slotNoNulls(slot))
527                 {
528                         (void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
529                         node->havehashrows = true;
530                 }
531                 else if (node->hashnulls)
532                 {
533                         (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
534                         node->havenullrows = true;
535                 }
536
537                 /*
538                  * Reset innerecontext after each inner tuple to free any memory used
539                  * in hash computation or comparison routines.
540                  */
541                 ResetExprContext(innerecontext);
542         }
543
544         /*
545          * Since the projected tuples are in the sub-query's context and not the
546          * main context, we'd better clear the tuple slot before there's any
547          * chance of a reset of the sub-query's context.  Else we will have the
548          * potential for a double free attempt.  (XXX possibly no longer needed,
549          * but can't hurt.)
550          */
551         ExecClearTuple(node->projRight->pi_slot);
552
553         MemoryContextSwitchTo(oldcontext);
554 }
555
556 /*
557  * findPartialMatch: does the hashtable contain an entry that is not
558  * provably distinct from the tuple?
559  *
560  * We have to scan the whole hashtable; we can't usefully use hashkeys
561  * to guide probing, since we might get partial matches on tuples with
562  * hashkeys quite unrelated to what we'd get from the given tuple.
563  */
564 static bool
565 findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot)
566 {
567         int                     numCols = hashtable->numCols;
568         AttrNumber *keyColIdx = hashtable->keyColIdx;
569         TupleHashIterator hashiter;
570         TupleHashEntry entry;
571
572         ResetTupleHashIterator(hashtable, &hashiter);
573         while ((entry = ScanTupleHashTable(&hashiter)) != NULL)
574         {
575                 ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
576                 if (!execTuplesUnequal(hashtable->tableslot, slot,
577                                                            numCols, keyColIdx,
578                                                            hashtable->eqfunctions,
579                                                            hashtable->tempcxt))
580                         return true;
581         }
582         return false;
583 }
584
585 /*
586  * slotAllNulls: is the slot completely NULL?
587  *
588  * This does not test for dropped columns, which is OK because we only
589  * use it on projected tuples.
590  */
591 static bool
592 slotAllNulls(TupleTableSlot *slot)
593 {
594         int                     ncols = slot->tts_tupleDescriptor->natts;
595         int                     i;
596
597         for (i = 1; i <= ncols; i++)
598         {
599                 if (!slot_attisnull(slot, i))
600                         return false;
601         }
602         return true;
603 }
604
605 /*
606  * slotNoNulls: is the slot entirely not NULL?
607  *
608  * This does not test for dropped columns, which is OK because we only
609  * use it on projected tuples.
610  */
611 static bool
612 slotNoNulls(TupleTableSlot *slot)
613 {
614         int                     ncols = slot->tts_tupleDescriptor->natts;
615         int                     i;
616
617         for (i = 1; i <= ncols; i++)
618         {
619                 if (slot_attisnull(slot, i))
620                         return false;
621         }
622         return true;
623 }
624
625 /* ----------------------------------------------------------------
626  *              ExecInitSubPlan
627  *
628  * Note: the eflags are those passed to the parent plan node of this
629  * subplan; they don't directly describe the execution conditions the
630  * subplan will face.
631  * ----------------------------------------------------------------
632  */
633 void
634 ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
635 {
636         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
637         EState     *sp_estate;
638         MemoryContext oldcontext;
639
640         /*
641          * Do access checking on the rangetable entries in the subquery.
642          */
643         ExecCheckRTPerms(subplan->rtable);
644
645         /*
646          * initialize my state
647          */
648         node->needShutdown = false;
649         node->curTuple = NULL;
650         node->projLeft = NULL;
651         node->projRight = NULL;
652         node->hashtable = NULL;
653         node->hashnulls = NULL;
654         node->tablecxt = NULL;
655         node->innerecontext = NULL;
656         node->keyColIdx = NULL;
657         node->eqfunctions = NULL;
658         node->hashfunctions = NULL;
659
660         /*
661          * create an EState for the subplan
662          *
663          * The subquery needs its own EState because it has its own rangetable. It
664          * shares our Param ID space, however.  XXX if rangetable access were done
665          * differently, the subquery could share our EState, which would eliminate
666          * some thrashing about in this module...
667          */
668         sp_estate = CreateExecutorState();
669         node->sub_estate = sp_estate;
670
671         oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
672
673         sp_estate->es_range_table = subplan->rtable;
674         sp_estate->es_param_list_info = estate->es_param_list_info;
675         sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
676         sp_estate->es_tupleTable =
677                 ExecCreateTupleTable(ExecCountSlotsNode(subplan->plan) + 10);
678         sp_estate->es_snapshot = estate->es_snapshot;
679         sp_estate->es_crosscheck_snapshot = estate->es_crosscheck_snapshot;
680         sp_estate->es_instrument = estate->es_instrument;
681
682         /*
683          * Start up the subplan (this is a very cut-down form of InitPlan())
684          *
685          * The subplan will never need to do BACKWARD scan or MARK/RESTORE.
686          * If it is a parameterless subplan (not initplan), we suggest that it
687          * be prepared to handle REWIND efficiently; otherwise there is no need.
688          */
689         eflags &= EXEC_FLAG_EXPLAIN_ONLY;
690         if (subplan->parParam == NIL && subplan->setParam == NIL)
691                 eflags |= EXEC_FLAG_REWIND;
692
693         node->planstate = ExecInitNode(subplan->plan, sp_estate, eflags);
694
695         node->needShutdown = true;      /* now we need to shutdown the subplan */
696
697         MemoryContextSwitchTo(oldcontext);
698
699         /*
700          * If this plan is un-correlated or undirect correlated one and want to
701          * set params for parent plan then mark parameters as needing evaluation.
702          *
703          * Note that in the case of un-correlated subqueries we don't care about
704          * setting parent->chgParam here: indices take care about it, for others -
705          * it doesn't matter...
706          */
707         if (subplan->setParam != NIL)
708         {
709                 ListCell   *lst;
710
711                 foreach(lst, subplan->setParam)
712                 {
713                         int                     paramid = lfirst_int(lst);
714                         ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
715
716                         prm->execPlan = node;
717                 }
718         }
719
720         /*
721          * If we are going to hash the subquery output, initialize relevant stuff.
722          * (We don't create the hashtable until needed, though.)
723          */
724         if (subplan->useHashTable)
725         {
726                 int                     ncols,
727                                         i;
728                 TupleDesc       tupDesc;
729                 TupleTable      tupTable;
730                 TupleTableSlot *slot;
731                 List       *oplist,
732                                    *lefttlist,
733                                    *righttlist,
734                                    *leftptlist,
735                                    *rightptlist;
736                 ListCell   *l;
737
738                 /* We need a memory context to hold the hash table(s) */
739                 node->tablecxt =
740                         AllocSetContextCreate(CurrentMemoryContext,
741                                                                   "Subplan HashTable Context",
742                                                                   ALLOCSET_DEFAULT_MINSIZE,
743                                                                   ALLOCSET_DEFAULT_INITSIZE,
744                                                                   ALLOCSET_DEFAULT_MAXSIZE);
745                 /* and a short-lived exprcontext for function evaluation */
746                 node->innerecontext = CreateExprContext(estate);
747                 /* Silly little array of column numbers 1..n */
748                 ncols = list_length(subplan->paramIds);
749                 node->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber));
750                 for (i = 0; i < ncols; i++)
751                         node->keyColIdx[i] = i + 1;
752
753                 /*
754                  * We use ExecProject to evaluate the lefthand and righthand
755                  * expression lists and form tuples.  (You might think that we could
756                  * use the sub-select's output tuples directly, but that is not the
757                  * case if we had to insert any run-time coercions of the sub-select's
758                  * output datatypes; anyway this avoids storing any resjunk columns
759                  * that might be in the sub-select's output.) Run through the
760                  * combining expressions to build tlists for the lefthand and
761                  * righthand sides.  We need both the ExprState list (for ExecProject)
762                  * and the underlying parse Exprs (for ExecTypeFromTL).
763                  *
764                  * We also extract the combining operators themselves to initialize
765                  * the equality and hashing functions for the hash tables.
766                  */
767                 if (IsA(node->testexpr->expr, OpExpr))
768                 {
769                         /* single combining operator */
770                         oplist = list_make1(node->testexpr);
771                 }
772                 else if (and_clause((Node *) node->testexpr->expr))
773                 {
774                         /* multiple combining operators */
775                         Assert(IsA(node->testexpr, BoolExprState));
776                         oplist = ((BoolExprState *) node->testexpr)->args;
777                 }
778                 else
779                 {
780                         /* shouldn't see anything else in a hashable subplan */
781                         elog(ERROR, "unrecognized testexpr type: %d",
782                                  (int) nodeTag(node->testexpr->expr));
783                         oplist = NIL;           /* keep compiler quiet */
784                 }
785                 Assert(list_length(oplist) == ncols);
786
787                 lefttlist = righttlist = NIL;
788                 leftptlist = rightptlist = NIL;
789                 node->eqfunctions = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
790                 node->hashfunctions = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
791                 i = 1;
792                 foreach(l, oplist)
793                 {
794                         FuncExprState *fstate = (FuncExprState *) lfirst(l);
795                         OpExpr     *opexpr = (OpExpr *) fstate->xprstate.expr;
796                         ExprState  *exstate;
797                         Expr       *expr;
798                         TargetEntry *tle;
799                         GenericExprState *tlestate;
800                         Oid                     hashfn;
801
802                         Assert(IsA(fstate, FuncExprState));
803                         Assert(IsA(opexpr, OpExpr));
804                         Assert(list_length(fstate->args) == 2);
805
806                         /* Process lefthand argument */
807                         exstate = (ExprState *) linitial(fstate->args);
808                         expr = exstate->expr;
809                         tle = makeTargetEntry(expr,
810                                                                   i,
811                                                                   NULL,
812                                                                   false);
813                         tlestate = makeNode(GenericExprState);
814                         tlestate->xprstate.expr = (Expr *) tle;
815                         tlestate->xprstate.evalfunc = NULL;
816                         tlestate->arg = exstate;
817                         lefttlist = lappend(lefttlist, tlestate);
818                         leftptlist = lappend(leftptlist, tle);
819
820                         /* Process righthand argument */
821                         exstate = (ExprState *) lsecond(fstate->args);
822                         expr = exstate->expr;
823                         tle = makeTargetEntry(expr,
824                                                                   i,
825                                                                   NULL,
826                                                                   false);
827                         tlestate = makeNode(GenericExprState);
828                         tlestate->xprstate.expr = (Expr *) tle;
829                         tlestate->xprstate.evalfunc = NULL;
830                         tlestate->arg = exstate;
831                         righttlist = lappend(righttlist, tlestate);
832                         rightptlist = lappend(rightptlist, tle);
833
834                         /* Lookup the combining function */
835                         fmgr_info(opexpr->opfuncid, &node->eqfunctions[i - 1]);
836                         node->eqfunctions[i - 1].fn_expr = (Node *) opexpr;
837
838                         /* Lookup the associated hash function */
839                         hashfn = get_op_hash_function(opexpr->opno);
840                         if (!OidIsValid(hashfn))
841                                 elog(ERROR, "could not find hash function for hash operator %u",
842                                          opexpr->opno);
843                         fmgr_info(hashfn, &node->hashfunctions[i - 1]);
844
845                         i++;
846                 }
847
848                 /*
849                  * Create a tupletable to hold these tuples.  (Note: we never bother
850                  * to free the tupletable explicitly; that's okay because it will
851                  * never store raw disk tuples that might have associated buffer pins.
852                  * The only resource involved is memory, which will be cleaned up by
853                  * freeing the query context.)
854                  */
855                 tupTable = ExecCreateTupleTable(2);
856
857                 /*
858                  * Construct tupdescs, slots and projection nodes for left and right
859                  * sides.  The lefthand expressions will be evaluated in the parent
860                  * plan node's exprcontext, which we don't have access to here.
861                  * Fortunately we can just pass NULL for now and fill it in later
862                  * (hack alert!).  The righthand expressions will be evaluated in our
863                  * own innerecontext.
864                  */
865                 tupDesc = ExecTypeFromTL(leftptlist, false);
866                 slot = ExecAllocTableSlot(tupTable);
867                 ExecSetSlotDescriptor(slot, tupDesc);
868                 node->projLeft = ExecBuildProjectionInfo(lefttlist,
869                                                                                                  NULL,
870                                                                                                  slot);
871
872                 tupDesc = ExecTypeFromTL(rightptlist, false);
873                 slot = ExecAllocTableSlot(tupTable);
874                 ExecSetSlotDescriptor(slot, tupDesc);
875                 node->projRight = ExecBuildProjectionInfo(righttlist,
876                                                                                                   node->innerecontext,
877                                                                                                   slot);
878         }
879 }
880
881 /* ----------------------------------------------------------------
882  *              ExecSetParamPlan
883  *
884  *              Executes an InitPlan subplan and sets its output parameters.
885  *
886  * This is called from ExecEvalParam() when the value of a PARAM_EXEC
887  * parameter is requested and the param's execPlan field is set (indicating
888  * that the param has not yet been evaluated).  This allows lazy evaluation
889  * of initplans: we don't run the subplan until/unless we need its output.
890  * Note that this routine MUST clear the execPlan fields of the plan's
891  * output parameters after evaluating them!
892  * ----------------------------------------------------------------
893  */
894 void
895 ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
896 {
897         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
898         PlanState  *planstate = node->planstate;
899         SubLinkType subLinkType = subplan->subLinkType;
900         MemoryContext oldcontext;
901         TupleTableSlot *slot;
902         ListCell   *l;
903         bool            found = false;
904         ArrayBuildState *astate = NULL;
905
906         /*
907          * Must switch to child query's per-query memory context.
908          */
909         oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
910
911         if (subLinkType == ANY_SUBLINK ||
912                 subLinkType == ALL_SUBLINK)
913                 elog(ERROR, "ANY/ALL subselect unsupported as initplan");
914
915         if (planstate->chgParam != NULL)
916                 ExecReScan(planstate, NULL);
917
918         for (slot = ExecProcNode(planstate);
919                  !TupIsNull(slot);
920                  slot = ExecProcNode(planstate))
921         {
922                 TupleDesc       tdesc = slot->tts_tupleDescriptor;
923                 int                     i = 1;
924
925                 if (subLinkType == EXISTS_SUBLINK)
926                 {
927                         /* There can be only one param... */
928                         int                     paramid = linitial_int(subplan->setParam);
929                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
930
931                         prm->execPlan = NULL;
932                         prm->value = BoolGetDatum(true);
933                         prm->isnull = false;
934                         found = true;
935                         break;
936                 }
937
938                 if (subLinkType == ARRAY_SUBLINK)
939                 {
940                         Datum           dvalue;
941                         bool            disnull;
942
943                         found = true;
944                         /* stash away current value */
945                         dvalue = slot_getattr(slot, 1, &disnull);
946                         astate = accumArrayResult(astate, dvalue, disnull,
947                                                                           tdesc->attrs[0]->atttypid,
948                                                                           oldcontext);
949                         /* keep scanning subplan to collect all values */
950                         continue;
951                 }
952
953                 if (found &&
954                         (subLinkType == EXPR_SUBLINK ||
955                          subLinkType == ROWCOMPARE_SUBLINK))
956                         ereport(ERROR,
957                                         (errcode(ERRCODE_CARDINALITY_VIOLATION),
958                                          errmsg("more than one row returned by a subquery used as an expression")));
959
960                 found = true;
961
962                 /*
963                  * We need to copy the subplan's tuple into our own context, in case
964                  * any of the params are pass-by-ref type --- the pointers stored in
965                  * the param structs will point at this copied tuple! node->curTuple
966                  * keeps track of the copied tuple for eventual freeing.
967                  */
968                 MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
969                 if (node->curTuple)
970                         heap_freetuple(node->curTuple);
971                 node->curTuple = ExecCopySlotTuple(slot);
972                 MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
973
974                 /*
975                  * Now set all the setParam params from the columns of the tuple
976                  */
977                 foreach(l, subplan->setParam)
978                 {
979                         int                     paramid = lfirst_int(l);
980                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
981
982                         prm->execPlan = NULL;
983                         prm->value = heap_getattr(node->curTuple, i, tdesc,
984                                                                           &(prm->isnull));
985                         i++;
986                 }
987         }
988
989         if (!found)
990         {
991                 if (subLinkType == EXISTS_SUBLINK)
992                 {
993                         /* There can be only one param... */
994                         int                     paramid = linitial_int(subplan->setParam);
995                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
996
997                         prm->execPlan = NULL;
998                         prm->value = BoolGetDatum(false);
999                         prm->isnull = false;
1000                 }
1001                 else
1002                 {
1003                         foreach(l, subplan->setParam)
1004                         {
1005                                 int                     paramid = lfirst_int(l);
1006                                 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1007
1008                                 prm->execPlan = NULL;
1009                                 prm->value = (Datum) 0;
1010                                 prm->isnull = true;
1011                         }
1012                 }
1013         }
1014         else if (subLinkType == ARRAY_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                 Assert(astate != NULL);
1021                 prm->execPlan = NULL;
1022                 /* We build the result in query context so it won't disappear */
1023                 prm->value = makeArrayResult(astate, econtext->ecxt_per_query_memory);
1024                 prm->isnull = false;
1025         }
1026
1027         MemoryContextSwitchTo(oldcontext);
1028 }
1029
1030 /* ----------------------------------------------------------------
1031  *              ExecEndSubPlan
1032  * ----------------------------------------------------------------
1033  */
1034 void
1035 ExecEndSubPlan(SubPlanState *node)
1036 {
1037         if (node->needShutdown)
1038         {
1039                 MemoryContext oldcontext;
1040
1041                 oldcontext = MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
1042                 ExecEndPlan(node->planstate, node->sub_estate);
1043                 MemoryContextSwitchTo(oldcontext);
1044                 FreeExecutorState(node->sub_estate);
1045                 node->sub_estate = NULL;
1046                 node->planstate = NULL;
1047                 node->needShutdown = false;
1048         }
1049 }
1050
1051 /*
1052  * Mark an initplan as needing recalculation
1053  */
1054 void
1055 ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
1056 {
1057         PlanState  *planstate = node->planstate;
1058         SubPlan    *subplan = (SubPlan *) node->xprstate.expr;
1059         EState     *estate = parent->state;
1060         ListCell   *l;
1061
1062         /* sanity checks */
1063         if (subplan->parParam != NIL)
1064                 elog(ERROR, "direct correlated subquery unsupported as initplan");
1065         if (subplan->setParam == NIL)
1066                 elog(ERROR, "setParam list of initplan is empty");
1067         if (bms_is_empty(planstate->plan->extParam))
1068                 elog(ERROR, "extParam set of initplan is empty");
1069
1070         /*
1071          * Don't actually re-scan: ExecSetParamPlan does it if needed.
1072          */
1073
1074         /*
1075          * Mark this subplan's output parameters as needing recalculation
1076          */
1077         foreach(l, subplan->setParam)
1078         {
1079                 int                     paramid = lfirst_int(l);
1080                 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
1081
1082                 prm->execPlan = node;
1083                 parent->chgParam = bms_add_member(parent->chgParam, paramid);
1084         }
1085 }