Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * nodeSubplan.c
4 : * routines to support sub-selects appearing in expressions
5 : *
6 : * This module is concerned with executing SubPlan expression nodes, which
7 : * should not be confused with sub-SELECTs appearing in FROM. SubPlans are
8 : * divided into "initplans", which are those that need only one evaluation per
9 : * query (among other restrictions, this requires that they don't use any
10 : * direct correlation variables from the parent plan level), and "regular"
11 : * subplans, which are re-evaluated every time their result is required.
12 : *
13 : *
14 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
15 : * Portions Copyright (c) 1994, Regents of the University of California
16 : *
17 : * IDENTIFICATION
18 : * src/backend/executor/nodeSubplan.c
19 : *
20 : *-------------------------------------------------------------------------
21 : */
22 : /*
23 : * INTERFACE ROUTINES
24 : * ExecSubPlan - process a subselect
25 : * ExecInitSubPlan - initialize a subselect
26 : */
27 : #include "postgres.h"
28 :
29 : #include <math.h>
30 :
31 : #include "access/htup_details.h"
32 : #include "executor/executor.h"
33 : #include "executor/nodeSubplan.h"
34 : #include "miscadmin.h"
35 : #include "nodes/makefuncs.h"
36 : #include "nodes/nodeFuncs.h"
37 : #include "optimizer/optimizer.h"
38 : #include "utils/array.h"
39 : #include "utils/lsyscache.h"
40 : #include "utils/memutils.h"
41 :
42 : static Datum ExecHashSubPlan(SubPlanState *node,
43 : ExprContext *econtext,
44 : bool *isNull);
45 : static Datum ExecScanSubPlan(SubPlanState *node,
46 : ExprContext *econtext,
47 : bool *isNull);
48 : static void buildSubPlanHash(SubPlanState *node, ExprContext *econtext);
49 : static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
50 : FmgrInfo *eqfunctions);
51 : static bool slotAllNulls(TupleTableSlot *slot);
52 : static bool slotNoNulls(TupleTableSlot *slot);
53 :
54 :
55 : /* ----------------------------------------------------------------
56 : * ExecSubPlan
57 : *
58 : * This is the main entry point for execution of a regular SubPlan.
59 : * ----------------------------------------------------------------
60 : */
61 : Datum
62 3556620 : ExecSubPlan(SubPlanState *node,
63 : ExprContext *econtext,
64 : bool *isNull)
65 : {
66 3556620 : SubPlan *subplan = node->subplan;
67 3556620 : EState *estate = node->planstate->state;
68 3556620 : ScanDirection dir = estate->es_direction;
69 : Datum retval;
70 :
71 3556620 : CHECK_FOR_INTERRUPTS();
72 :
73 : /* Set non-null as default */
74 3556620 : *isNull = false;
75 :
76 : /* Sanity checks */
77 3556620 : if (subplan->subLinkType == CTE_SUBLINK)
78 0 : elog(ERROR, "CTE subplans should not be executed via ExecSubPlan");
79 3556620 : if (subplan->setParam != NIL && subplan->subLinkType != MULTIEXPR_SUBLINK)
80 0 : elog(ERROR, "cannot set parent params from subquery");
81 :
82 : /* Force forward-scan mode for evaluation */
83 3556620 : estate->es_direction = ForwardScanDirection;
84 :
85 : /* Select appropriate evaluation strategy */
86 3556620 : if (subplan->useHashTable)
87 1872400 : retval = ExecHashSubPlan(node, econtext, isNull);
88 : else
89 1684220 : retval = ExecScanSubPlan(node, econtext, isNull);
90 :
91 : /* restore scan direction */
92 3556614 : estate->es_direction = dir;
93 :
94 3556614 : return retval;
95 : }
96 :
97 : /*
98 : * ExecHashSubPlan: store subselect result in an in-memory hash table
99 : */
100 : static Datum
101 1872400 : ExecHashSubPlan(SubPlanState *node,
102 : ExprContext *econtext,
103 : bool *isNull)
104 : {
105 1872400 : bool result = false;
106 1872400 : SubPlan *subplan = node->subplan;
107 1872400 : PlanState *planstate = node->planstate;
108 : TupleTableSlot *slot;
109 :
110 : /* Shouldn't have any direct correlation Vars */
111 1872400 : if (subplan->parParam != NIL || subplan->args != NIL)
112 0 : elog(ERROR, "hashed subplan with direct correlation not supported");
113 :
114 : /*
115 : * If first time through or we need to rescan the subplan, build the hash
116 : * table.
117 : */
118 1872400 : if (node->hashtable == NULL || planstate->chgParam != NULL)
119 1546 : buildSubPlanHash(node, econtext);
120 :
121 : /*
122 : * The result for an empty subplan is always FALSE; no need to evaluate
123 : * lefthand side.
124 : */
125 1872394 : *isNull = false;
126 1872394 : if (!node->havehashrows && !node->havenullrows)
127 820186 : return BoolGetDatum(false);
128 :
129 : /*
130 : * Evaluate lefthand expressions and form a projection tuple. First we
131 : * have to set the econtext to use (hack alert!).
132 : */
133 1052208 : node->projLeft->pi_exprContext = econtext;
134 1052208 : slot = ExecProject(node->projLeft);
135 :
136 : /*
137 : * If the LHS is all non-null, probe for an exact match in the main hash
138 : * table. If we find one, the result is TRUE. Otherwise, scan the
139 : * partly-null table to see if there are any rows that aren't provably
140 : * unequal to the LHS; if so, the result is UNKNOWN. (We skip that part
141 : * if we don't care about UNKNOWN.) Otherwise, the result is FALSE.
142 : *
143 : * Note: the reason we can avoid a full scan of the main hash table is
144 : * that the combining operators are assumed never to yield NULL when both
145 : * inputs are non-null. If they were to do so, we might need to produce
146 : * UNKNOWN instead of FALSE because of an UNKNOWN result in comparing the
147 : * LHS to some main-table entry --- which is a comparison we will not even
148 : * make, unless there's a chance match of hash keys.
149 : */
150 1052208 : if (slotNoNulls(slot))
151 : {
152 2104320 : if (node->havehashrows &&
153 1052148 : FindTupleHashEntry(node->hashtable,
154 : slot,
155 : node->cur_eq_comp,
156 : node->lhs_hash_expr) != NULL)
157 63282 : result = true;
158 988926 : else if (node->havenullrows &&
159 36 : findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
160 18 : *isNull = true;
161 : }
162 :
163 : /*
164 : * When the LHS is partly or wholly NULL, we can never return TRUE. If we
165 : * don't care about UNKNOWN, just return FALSE. Otherwise, if the LHS is
166 : * wholly NULL, immediately return UNKNOWN. (Since the combining
167 : * operators are strict, the result could only be FALSE if the sub-select
168 : * were empty, but we already handled that case.) Otherwise, we must scan
169 : * both the main and partly-null tables to see if there are any rows that
170 : * aren't provably unequal to the LHS; if so, the result is UNKNOWN.
171 : * Otherwise, the result is FALSE.
172 : */
173 36 : else if (node->hashnulls == NULL)
174 : /* just return FALSE */ ;
175 36 : else if (slotAllNulls(slot))
176 0 : *isNull = true;
177 : /* Scan partly-null table first, since more likely to get a match */
178 72 : else if (node->havenullrows &&
179 36 : findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
180 18 : *isNull = true;
181 24 : else if (node->havehashrows &&
182 6 : findPartialMatch(node->hashtable, slot, node->cur_eq_funcs))
183 0 : *isNull = true;
184 :
185 : /*
186 : * Note: because we are typically called in a per-tuple context, we have
187 : * to explicitly clear the projected tuple before returning. Otherwise,
188 : * we'll have a double-free situation: the per-tuple context will probably
189 : * be reset before we're called again, and then the tuple slot will think
190 : * it still needs to free the tuple.
191 : */
192 1052208 : ExecClearTuple(slot);
193 :
194 : /* Also must reset the innerecontext after each hashtable lookup. */
195 1052208 : ResetExprContext(node->innerecontext);
196 :
197 1052208 : return BoolGetDatum(result);
198 : }
199 :
200 : /*
201 : * ExecScanSubPlan: default case where we have to rescan subplan each time
202 : */
203 : static Datum
204 1684220 : ExecScanSubPlan(SubPlanState *node,
205 : ExprContext *econtext,
206 : bool *isNull)
207 : {
208 1684220 : SubPlan *subplan = node->subplan;
209 1684220 : PlanState *planstate = node->planstate;
210 1684220 : SubLinkType subLinkType = subplan->subLinkType;
211 : MemoryContext oldcontext;
212 : TupleTableSlot *slot;
213 : Datum result;
214 1684220 : bool found = false; /* true if got at least one subplan tuple */
215 : ListCell *l;
216 1684220 : ArrayBuildStateAny *astate = NULL;
217 :
218 : /* Initialize ArrayBuildStateAny in caller's context, if needed */
219 1684220 : if (subLinkType == ARRAY_SUBLINK)
220 56556 : astate = initArrayResultAny(subplan->firstColType,
221 : CurrentMemoryContext, true);
222 :
223 : /*
224 : * We are probably in a short-lived expression-evaluation context. Switch
225 : * to the per-query context for manipulating the child plan's chgParam,
226 : * calling ExecProcNode on it, etc.
227 : */
228 1684220 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
229 :
230 : /*
231 : * We rely on the caller to evaluate plan correlation values, if
232 : * necessary. However we still need to record the fact that the values
233 : * (might have) changed, otherwise the ExecReScan() below won't know that
234 : * nodes need to be rescanned.
235 : */
236 3398330 : foreach(l, subplan->parParam)
237 : {
238 1714110 : int paramid = lfirst_int(l);
239 :
240 1714110 : planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
241 : }
242 :
243 : /* with that done, we can reset the subplan */
244 1684220 : ExecReScan(planstate);
245 :
246 : /*
247 : * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result
248 : * is boolean as are the results of the combining operators. We combine
249 : * results across tuples (if the subplan produces more than one) using OR
250 : * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
251 : * (ROWCOMPARE_SUBLINK doesn't allow multiple tuples from the subplan.)
252 : * NULL results from the combining operators are handled according to the
253 : * usual SQL semantics for OR and AND. The result for no input tuples is
254 : * FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
255 : * ROWCOMPARE_SUBLINK.
256 : *
257 : * For EXPR_SUBLINK we require the subplan to produce no more than one
258 : * tuple, else an error is raised. If zero tuples are produced, we return
259 : * NULL. Assuming we get a tuple, we just use its first column (there can
260 : * be only one non-junk column in this case).
261 : *
262 : * For MULTIEXPR_SUBLINK, we push the per-column subplan outputs out to
263 : * the setParams and then return a dummy false value. There must not be
264 : * multiple tuples returned from the subplan; if zero tuples are produced,
265 : * set the setParams to NULL.
266 : *
267 : * For ARRAY_SUBLINK we allow the subplan to produce any number of tuples,
268 : * and form an array of the first column's values. Note in particular
269 : * that we produce a zero-element array if no tuples are produced (this is
270 : * a change from pre-8.3 behavior of returning NULL).
271 : */
272 1684220 : result = BoolGetDatum(subLinkType == ALL_SUBLINK);
273 1684220 : *isNull = false;
274 :
275 1684220 : for (slot = ExecProcNode(planstate);
276 2046600 : !TupIsNull(slot);
277 362380 : slot = ExecProcNode(planstate))
278 : {
279 363260 : TupleDesc tdesc = slot->tts_tupleDescriptor;
280 : Datum rowresult;
281 : bool rownull;
282 : int col;
283 : ListCell *plst;
284 :
285 363260 : if (subLinkType == EXISTS_SUBLINK)
286 : {
287 732 : found = true;
288 732 : result = BoolGetDatum(true);
289 880 : break;
290 : }
291 :
292 362528 : if (subLinkType == EXPR_SUBLINK)
293 : {
294 : /* cannot allow multiple input tuples for EXPR sublink */
295 346322 : if (found)
296 0 : ereport(ERROR,
297 : (errcode(ERRCODE_CARDINALITY_VIOLATION),
298 : errmsg("more than one row returned by a subquery used as an expression")));
299 346322 : found = true;
300 :
301 : /*
302 : * We need to copy the subplan's tuple in case the result is of
303 : * pass-by-ref type --- our return value will point into this
304 : * copied tuple! Can't use the subplan's instance of the tuple
305 : * since it won't still be valid after next ExecProcNode() call.
306 : * node->curTuple keeps track of the copied tuple for eventual
307 : * freeing.
308 : */
309 346322 : if (node->curTuple)
310 340130 : heap_freetuple(node->curTuple);
311 346322 : node->curTuple = ExecCopySlotHeapTuple(slot);
312 :
313 346322 : result = heap_getattr(node->curTuple, 1, tdesc, isNull);
314 : /* keep scanning subplan to make sure there's only one tuple */
315 351424 : continue;
316 : }
317 :
318 16206 : if (subLinkType == MULTIEXPR_SUBLINK)
319 : {
320 : /* cannot allow multiple input tuples for MULTIEXPR sublink */
321 240 : if (found)
322 0 : ereport(ERROR,
323 : (errcode(ERRCODE_CARDINALITY_VIOLATION),
324 : errmsg("more than one row returned by a subquery used as an expression")));
325 240 : found = true;
326 :
327 : /*
328 : * We need to copy the subplan's tuple in case any result is of
329 : * pass-by-ref type --- our output values will point into this
330 : * copied tuple! Can't use the subplan's instance of the tuple
331 : * since it won't still be valid after next ExecProcNode() call.
332 : * node->curTuple keeps track of the copied tuple for eventual
333 : * freeing.
334 : */
335 240 : if (node->curTuple)
336 152 : heap_freetuple(node->curTuple);
337 240 : node->curTuple = ExecCopySlotHeapTuple(slot);
338 :
339 : /*
340 : * Now set all the setParam params from the columns of the tuple
341 : */
342 240 : col = 1;
343 714 : foreach(plst, subplan->setParam)
344 : {
345 474 : int paramid = lfirst_int(plst);
346 : ParamExecData *prmdata;
347 :
348 474 : prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
349 : Assert(prmdata->execPlan == NULL);
350 474 : prmdata->value = heap_getattr(node->curTuple, col, tdesc,
351 : &(prmdata->isnull));
352 474 : col++;
353 : }
354 :
355 : /* keep scanning subplan to make sure there's only one tuple */
356 240 : continue;
357 : }
358 :
359 15966 : if (subLinkType == ARRAY_SUBLINK)
360 4862 : {
361 : Datum dvalue;
362 : bool disnull;
363 :
364 4862 : found = true;
365 : /* stash away current value */
366 : Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
367 4862 : dvalue = slot_getattr(slot, 1, &disnull);
368 4862 : astate = accumArrayResultAny(astate, dvalue, disnull,
369 : subplan->firstColType, oldcontext);
370 : /* keep scanning subplan to collect all values */
371 4862 : continue;
372 : }
373 :
374 : /* cannot allow multiple input tuples for ROWCOMPARE sublink either */
375 11104 : if (subLinkType == ROWCOMPARE_SUBLINK && found)
376 0 : ereport(ERROR,
377 : (errcode(ERRCODE_CARDINALITY_VIOLATION),
378 : errmsg("more than one row returned by a subquery used as an expression")));
379 :
380 11104 : found = true;
381 :
382 : /*
383 : * For ALL, ANY, and ROWCOMPARE sublinks, load up the Params
384 : * representing the columns of the sub-select, and then evaluate the
385 : * combining expression.
386 : */
387 11104 : col = 1;
388 32966 : foreach(plst, subplan->paramIds)
389 : {
390 21862 : int paramid = lfirst_int(plst);
391 : ParamExecData *prmdata;
392 :
393 21862 : prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
394 : Assert(prmdata->execPlan == NULL);
395 21862 : prmdata->value = slot_getattr(slot, col, &(prmdata->isnull));
396 21862 : col++;
397 : }
398 :
399 11104 : rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext,
400 : &rownull);
401 :
402 11104 : if (subLinkType == ANY_SUBLINK)
403 : {
404 : /* combine across rows per OR semantics */
405 10966 : if (rownull)
406 0 : *isNull = true;
407 10966 : else if (DatumGetBool(rowresult))
408 : {
409 124 : result = BoolGetDatum(true);
410 124 : *isNull = false;
411 124 : break; /* needn't look at any more rows */
412 : }
413 : }
414 138 : else if (subLinkType == ALL_SUBLINK)
415 : {
416 : /* combine across rows per AND semantics */
417 90 : if (rownull)
418 0 : *isNull = true;
419 90 : else if (!DatumGetBool(rowresult))
420 : {
421 24 : result = BoolGetDatum(false);
422 24 : *isNull = false;
423 24 : break; /* needn't look at any more rows */
424 : }
425 : }
426 : else
427 : {
428 : /* must be ROWCOMPARE_SUBLINK */
429 48 : result = rowresult;
430 48 : *isNull = rownull;
431 : }
432 : }
433 :
434 1684220 : MemoryContextSwitchTo(oldcontext);
435 :
436 1684220 : if (subLinkType == ARRAY_SUBLINK)
437 : {
438 : /* We return the result in the caller's context */
439 56556 : result = makeArrayResultAny(astate, oldcontext, true);
440 : }
441 1627664 : else if (!found)
442 : {
443 : /*
444 : * deal with empty subplan result. result/isNull were previously
445 : * initialized correctly for all sublink types except EXPR and
446 : * ROWCOMPARE; for those, return NULL.
447 : */
448 1274748 : if (subLinkType == EXPR_SUBLINK ||
449 : subLinkType == ROWCOMPARE_SUBLINK)
450 : {
451 76434 : result = (Datum) 0;
452 76434 : *isNull = true;
453 : }
454 1198314 : else if (subLinkType == MULTIEXPR_SUBLINK)
455 : {
456 : /* We don't care about function result, but set the setParams */
457 18 : foreach(l, subplan->setParam)
458 : {
459 12 : int paramid = lfirst_int(l);
460 : ParamExecData *prmdata;
461 :
462 12 : prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
463 : Assert(prmdata->execPlan == NULL);
464 12 : prmdata->value = (Datum) 0;
465 12 : prmdata->isnull = true;
466 : }
467 : }
468 : }
469 :
470 1684220 : return result;
471 : }
472 :
473 : /*
474 : * buildSubPlanHash: load hash table by scanning subplan output.
475 : */
476 : static void
477 1546 : buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
478 : {
479 1546 : SubPlan *subplan = node->subplan;
480 1546 : PlanState *planstate = node->planstate;
481 1546 : int ncols = node->numCols;
482 1546 : ExprContext *innerecontext = node->innerecontext;
483 : MemoryContext oldcontext;
484 : long nbuckets;
485 : TupleTableSlot *slot;
486 :
487 : Assert(subplan->subLinkType == ANY_SUBLINK);
488 :
489 : /*
490 : * If we already had any hash tables, reset 'em; otherwise create empty
491 : * hash table(s).
492 : *
493 : * If we need to distinguish accurately between FALSE and UNKNOWN (i.e.,
494 : * NULL) results of the IN operation, then we have to store subplan output
495 : * rows that are partly or wholly NULL. We store such rows in a separate
496 : * hash table that we expect will be much smaller than the main table. (We
497 : * can use hashing to eliminate partly-null rows that are not distinct. We
498 : * keep them separate to minimize the cost of the inevitable full-table
499 : * searches; see findPartialMatch.)
500 : *
501 : * If it's not necessary to distinguish FALSE and UNKNOWN, then we don't
502 : * need to store subplan output rows that contain NULL.
503 : *
504 : * Because the input slot for each hash table is always the slot resulting
505 : * from an ExecProject(), we can use TTSOpsVirtual for the input ops. This
506 : * saves a needless fetch inner op step for the hashing ExprState created
507 : * in BuildTupleHashTable().
508 : */
509 1546 : MemoryContextReset(node->hashtablecxt);
510 1546 : node->havehashrows = false;
511 1546 : node->havenullrows = false;
512 :
513 1546 : nbuckets = clamp_cardinality_to_long(planstate->plan->plan_rows);
514 1546 : if (nbuckets < 1)
515 0 : nbuckets = 1;
516 :
517 1546 : if (node->hashtable)
518 594 : ResetTupleHashTable(node->hashtable);
519 : else
520 952 : node->hashtable = BuildTupleHashTable(node->parent,
521 : node->descRight,
522 : &TTSOpsVirtual,
523 : ncols,
524 : node->keyColIdx,
525 952 : node->tab_eq_funcoids,
526 : node->tab_hash_funcs,
527 : node->tab_collations,
528 : nbuckets,
529 : 0,
530 952 : node->planstate->state->es_query_cxt,
531 : node->hashtablecxt,
532 : innerecontext->ecxt_per_tuple_memory,
533 : false);
534 :
535 1546 : if (!subplan->unknownEqFalse)
536 : {
537 776 : if (ncols == 1)
538 722 : nbuckets = 1; /* there can only be one entry */
539 : else
540 : {
541 54 : nbuckets /= 16;
542 54 : if (nbuckets < 1)
543 0 : nbuckets = 1;
544 : }
545 :
546 776 : if (node->hashnulls)
547 594 : ResetTupleHashTable(node->hashnulls);
548 : else
549 182 : node->hashnulls = BuildTupleHashTable(node->parent,
550 : node->descRight,
551 : &TTSOpsVirtual,
552 : ncols,
553 : node->keyColIdx,
554 182 : node->tab_eq_funcoids,
555 : node->tab_hash_funcs,
556 : node->tab_collations,
557 : nbuckets,
558 : 0,
559 182 : node->planstate->state->es_query_cxt,
560 : node->hashtablecxt,
561 : innerecontext->ecxt_per_tuple_memory,
562 : false);
563 : }
564 : else
565 770 : node->hashnulls = NULL;
566 :
567 : /*
568 : * We are probably in a short-lived expression-evaluation context. Switch
569 : * to the per-query context for manipulating the child plan.
570 : */
571 1546 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
572 :
573 : /*
574 : * Reset subplan to start.
575 : */
576 1546 : ExecReScan(planstate);
577 :
578 : /*
579 : * Scan the subplan and load the hash table(s). Note that when there are
580 : * duplicate rows coming out of the sub-select, only one copy is stored.
581 : */
582 1546 : for (slot = ExecProcNode(planstate);
583 238832 : !TupIsNull(slot);
584 237286 : slot = ExecProcNode(planstate))
585 : {
586 237292 : int col = 1;
587 : ListCell *plst;
588 : bool isnew;
589 :
590 : /*
591 : * Load up the Params representing the raw sub-select outputs, then
592 : * form the projection tuple to store in the hashtable.
593 : */
594 582560 : foreach(plst, subplan->paramIds)
595 : {
596 345268 : int paramid = lfirst_int(plst);
597 : ParamExecData *prmdata;
598 :
599 345268 : prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
600 : Assert(prmdata->execPlan == NULL);
601 345268 : prmdata->value = slot_getattr(slot, col,
602 : &(prmdata->isnull));
603 345268 : col++;
604 : }
605 237292 : slot = ExecProject(node->projRight);
606 :
607 : /*
608 : * If result contains any nulls, store separately or not at all.
609 : */
610 237292 : if (slotNoNulls(slot))
611 : {
612 237268 : (void) LookupTupleHashEntry(node->hashtable, slot, &isnew, NULL);
613 237262 : node->havehashrows = true;
614 : }
615 24 : else if (node->hashnulls)
616 : {
617 24 : (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew, NULL);
618 24 : node->havenullrows = true;
619 : }
620 :
621 : /*
622 : * Reset innerecontext after each inner tuple to free any memory used
623 : * during ExecProject and hashtable lookup.
624 : */
625 237286 : ResetExprContext(innerecontext);
626 : }
627 :
628 : /*
629 : * Since the projected tuples are in the sub-query's context and not the
630 : * main context, we'd better clear the tuple slot before there's any
631 : * chance of a reset of the sub-query's context. Else we will have the
632 : * potential for a double free attempt. (XXX possibly no longer needed,
633 : * but can't hurt.)
634 : */
635 1540 : ExecClearTuple(node->projRight->pi_state.resultslot);
636 :
637 1540 : MemoryContextSwitchTo(oldcontext);
638 1540 : }
639 :
640 : /*
641 : * execTuplesUnequal
642 : * Return true if two tuples are definitely unequal in the indicated
643 : * fields.
644 : *
645 : * Nulls are neither equal nor unequal to anything else. A true result
646 : * is obtained only if there are non-null fields that compare not-equal.
647 : *
648 : * slot1, slot2: the tuples to compare (must have same columns!)
649 : * numCols: the number of attributes to be examined
650 : * matchColIdx: array of attribute column numbers
651 : * eqFunctions: array of fmgr lookup info for the equality functions to use
652 : * evalContext: short-term memory context for executing the functions
653 : */
654 : static bool
655 78 : execTuplesUnequal(TupleTableSlot *slot1,
656 : TupleTableSlot *slot2,
657 : int numCols,
658 : AttrNumber *matchColIdx,
659 : FmgrInfo *eqfunctions,
660 : const Oid *collations,
661 : MemoryContext evalContext)
662 : {
663 : MemoryContext oldContext;
664 : bool result;
665 : int i;
666 :
667 : /* Reset and switch into the temp context. */
668 78 : MemoryContextReset(evalContext);
669 78 : oldContext = MemoryContextSwitchTo(evalContext);
670 :
671 : /*
672 : * We cannot report a match without checking all the fields, but we can
673 : * report a non-match as soon as we find unequal fields. So, start
674 : * comparing at the last field (least significant sort key). That's the
675 : * most likely to be different if we are dealing with sorted input.
676 : */
677 78 : result = false;
678 :
679 192 : for (i = numCols; --i >= 0;)
680 : {
681 156 : AttrNumber att = matchColIdx[i];
682 : Datum attr1,
683 : attr2;
684 : bool isNull1,
685 : isNull2;
686 :
687 156 : attr1 = slot_getattr(slot1, att, &isNull1);
688 :
689 156 : if (isNull1)
690 78 : continue; /* can't prove anything here */
691 :
692 114 : attr2 = slot_getattr(slot2, att, &isNull2);
693 :
694 114 : if (isNull2)
695 36 : continue; /* can't prove anything here */
696 :
697 : /* Apply the type-specific equality function */
698 78 : if (!DatumGetBool(FunctionCall2Coll(&eqfunctions[i],
699 78 : collations[i],
700 : attr1, attr2)))
701 : {
702 42 : result = true; /* they are unequal */
703 42 : break;
704 : }
705 : }
706 :
707 78 : MemoryContextSwitchTo(oldContext);
708 :
709 78 : return result;
710 : }
711 :
712 : /*
713 : * findPartialMatch: does the hashtable contain an entry that is not
714 : * provably distinct from the tuple?
715 : *
716 : * We have to scan the whole hashtable; we can't usefully use hashkeys
717 : * to guide probing, since we might get partial matches on tuples with
718 : * hashkeys quite unrelated to what we'd get from the given tuple.
719 : *
720 : * Caller must provide the equality functions to use, since in cross-type
721 : * cases these are different from the hashtable's internal functions.
722 : */
723 : static bool
724 78 : findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
725 : FmgrInfo *eqfunctions)
726 : {
727 78 : int numCols = hashtable->numCols;
728 78 : AttrNumber *keyColIdx = hashtable->keyColIdx;
729 : TupleHashIterator hashiter;
730 : TupleHashEntry entry;
731 :
732 78 : InitTupleHashIterator(hashtable, &hashiter);
733 120 : while ((entry = ScanTupleHashTable(hashtable, &hashiter)) != NULL)
734 : {
735 78 : CHECK_FOR_INTERRUPTS();
736 :
737 78 : ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry), hashtable->tableslot, false);
738 78 : if (!execTuplesUnequal(slot, hashtable->tableslot,
739 : numCols, keyColIdx,
740 : eqfunctions,
741 78 : hashtable->tab_collations,
742 : hashtable->tempcxt))
743 : {
744 : TermTupleHashIterator(&hashiter);
745 36 : return true;
746 : }
747 : }
748 : /* No TermTupleHashIterator call needed here */
749 42 : return false;
750 : }
751 :
752 : /*
753 : * slotAllNulls: is the slot completely NULL?
754 : *
755 : * This does not test for dropped columns, which is OK because we only
756 : * use it on projected tuples.
757 : */
758 : static bool
759 36 : slotAllNulls(TupleTableSlot *slot)
760 : {
761 36 : int ncols = slot->tts_tupleDescriptor->natts;
762 : int i;
763 :
764 36 : for (i = 1; i <= ncols; i++)
765 : {
766 36 : if (!slot_attisnull(slot, i))
767 36 : return false;
768 : }
769 0 : return true;
770 : }
771 :
772 : /*
773 : * slotNoNulls: is the slot entirely not NULL?
774 : *
775 : * This does not test for dropped columns, which is OK because we only
776 : * use it on projected tuples.
777 : */
778 : static bool
779 1289500 : slotNoNulls(TupleTableSlot *slot)
780 : {
781 1289500 : int ncols = slot->tts_tupleDescriptor->natts;
782 : int i;
783 :
784 2747102 : for (i = 1; i <= ncols; i++)
785 : {
786 1457662 : if (slot_attisnull(slot, i))
787 60 : return false;
788 : }
789 1289440 : return true;
790 : }
791 :
792 : /* ----------------------------------------------------------------
793 : * ExecInitSubPlan
794 : *
795 : * Create a SubPlanState for a SubPlan; this is the SubPlan-specific part
796 : * of ExecInitExpr(). We split it out so that it can be used for InitPlans
797 : * as well as regular SubPlans. Note that we don't link the SubPlan into
798 : * the parent's subPlan list, because that shouldn't happen for InitPlans.
799 : * Instead, ExecInitExpr() does that one part.
800 : *
801 : * We also rely on ExecInitExpr(), more precisely ExecInitSubPlanExpr(), to
802 : * evaluate input parameters, as that allows them to be evaluated as part of
803 : * the expression referencing the SubPlan.
804 : * ----------------------------------------------------------------
805 : */
806 : SubPlanState *
807 43710 : ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
808 : {
809 43710 : SubPlanState *sstate = makeNode(SubPlanState);
810 43710 : EState *estate = parent->state;
811 :
812 43710 : sstate->subplan = subplan;
813 :
814 : /* Link the SubPlanState to already-initialized subplan */
815 87420 : sstate->planstate = (PlanState *) list_nth(estate->es_subplanstates,
816 43710 : subplan->plan_id - 1);
817 :
818 : /*
819 : * This check can fail if the planner mistakenly puts a parallel-unsafe
820 : * subplan into a parallelized subquery; see ExecSerializePlan.
821 : */
822 43710 : if (sstate->planstate == NULL)
823 0 : elog(ERROR, "subplan \"%s\" was not initialized",
824 : subplan->plan_name);
825 :
826 : /* Link to parent's state, too */
827 43710 : sstate->parent = parent;
828 :
829 : /* Initialize subexpressions */
830 43710 : sstate->testexpr = ExecInitExpr((Expr *) subplan->testexpr, parent);
831 :
832 : /*
833 : * initialize my state
834 : */
835 43710 : sstate->curTuple = NULL;
836 43710 : sstate->curArray = PointerGetDatum(NULL);
837 43710 : sstate->projLeft = NULL;
838 43710 : sstate->projRight = NULL;
839 43710 : sstate->hashtable = NULL;
840 43710 : sstate->hashnulls = NULL;
841 43710 : sstate->hashtablecxt = NULL;
842 43710 : sstate->innerecontext = NULL;
843 43710 : sstate->keyColIdx = NULL;
844 43710 : sstate->tab_eq_funcoids = NULL;
845 43710 : sstate->tab_hash_funcs = NULL;
846 43710 : sstate->tab_collations = NULL;
847 43710 : sstate->cur_eq_funcs = NULL;
848 :
849 : /*
850 : * If this is an initplan, it has output parameters that the parent plan
851 : * will use, so mark those parameters as needing evaluation. We don't
852 : * actually run the subplan until we first need one of its outputs.
853 : *
854 : * A CTE subplan's output parameter is never to be evaluated in the normal
855 : * way, so skip this in that case.
856 : *
857 : * Note that we don't set parent->chgParam here: the parent plan hasn't
858 : * been run yet, so no need to force it to re-run.
859 : */
860 43710 : if (subplan->setParam != NIL && subplan->parParam == NIL &&
861 14362 : subplan->subLinkType != CTE_SUBLINK)
862 : {
863 : ListCell *lst;
864 :
865 23792 : foreach(lst, subplan->setParam)
866 : {
867 11920 : int paramid = lfirst_int(lst);
868 11920 : ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
869 :
870 11920 : prm->execPlan = sstate;
871 : }
872 : }
873 :
874 : /*
875 : * If we are going to hash the subquery output, initialize relevant stuff.
876 : * (We don't create the hashtable until needed, though.)
877 : */
878 43710 : if (subplan->useHashTable)
879 : {
880 : int ncols,
881 : i;
882 : TupleDesc tupDescLeft;
883 : TupleDesc tupDescRight;
884 : Oid *cross_eq_funcoids;
885 : TupleTableSlot *slot;
886 : FmgrInfo *lhs_hash_funcs;
887 : List *oplist,
888 : *lefttlist,
889 : *righttlist;
890 : ListCell *l;
891 :
892 : /* We need a memory context to hold the hash table(s) */
893 1142 : sstate->hashtablecxt =
894 1142 : AllocSetContextCreate(CurrentMemoryContext,
895 : "Subplan HashTable Context",
896 : ALLOCSET_DEFAULT_SIZES);
897 : /* and a short-lived exprcontext for function evaluation */
898 1142 : sstate->innerecontext = CreateExprContext(estate);
899 :
900 : /*
901 : * We use ExecProject to evaluate the lefthand and righthand
902 : * expression lists and form tuples. (You might think that we could
903 : * use the sub-select's output tuples directly, but that is not the
904 : * case if we had to insert any run-time coercions of the sub-select's
905 : * output datatypes; anyway this avoids storing any resjunk columns
906 : * that might be in the sub-select's output.) Run through the
907 : * combining expressions to build tlists for the lefthand and
908 : * righthand sides.
909 : *
910 : * We also extract the combining operators themselves to initialize
911 : * the equality and hashing functions for the hash tables.
912 : */
913 1142 : if (IsA(subplan->testexpr, OpExpr))
914 : {
915 : /* single combining operator */
916 1044 : oplist = list_make1(subplan->testexpr);
917 : }
918 98 : else if (is_andclause(subplan->testexpr))
919 : {
920 : /* multiple combining operators */
921 98 : oplist = castNode(BoolExpr, subplan->testexpr)->args;
922 : }
923 : else
924 : {
925 : /* shouldn't see anything else in a hashable subplan */
926 0 : elog(ERROR, "unrecognized testexpr type: %d",
927 : (int) nodeTag(subplan->testexpr));
928 : oplist = NIL; /* keep compiler quiet */
929 : }
930 1142 : ncols = list_length(oplist);
931 :
932 1142 : lefttlist = righttlist = NIL;
933 1142 : sstate->numCols = ncols;
934 1142 : sstate->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber));
935 1142 : sstate->tab_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
936 1142 : sstate->tab_collations = (Oid *) palloc(ncols * sizeof(Oid));
937 1142 : sstate->tab_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
938 1142 : lhs_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
939 1142 : sstate->cur_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
940 : /* we'll need the cross-type equality fns below, but not in sstate */
941 1142 : cross_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
942 :
943 1142 : i = 1;
944 2382 : foreach(l, oplist)
945 : {
946 1240 : OpExpr *opexpr = lfirst_node(OpExpr, l);
947 : Expr *expr;
948 : TargetEntry *tle;
949 : Oid rhs_eq_oper;
950 : Oid left_hashfn;
951 : Oid right_hashfn;
952 :
953 : Assert(list_length(opexpr->args) == 2);
954 :
955 : /* Process lefthand argument */
956 1240 : expr = (Expr *) linitial(opexpr->args);
957 1240 : tle = makeTargetEntry(expr,
958 : i,
959 : NULL,
960 : false);
961 1240 : lefttlist = lappend(lefttlist, tle);
962 :
963 : /* Process righthand argument */
964 1240 : expr = (Expr *) lsecond(opexpr->args);
965 1240 : tle = makeTargetEntry(expr,
966 : i,
967 : NULL,
968 : false);
969 1240 : righttlist = lappend(righttlist, tle);
970 :
971 : /* Lookup the equality function (potentially cross-type) */
972 1240 : cross_eq_funcoids[i - 1] = opexpr->opfuncid;
973 1240 : fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
974 1240 : fmgr_info_set_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
975 :
976 : /* Look up the equality function for the RHS type */
977 1240 : if (!get_compatible_hash_operators(opexpr->opno,
978 : NULL, &rhs_eq_oper))
979 0 : elog(ERROR, "could not find compatible hash operator for operator %u",
980 : opexpr->opno);
981 1240 : sstate->tab_eq_funcoids[i - 1] = get_opcode(rhs_eq_oper);
982 :
983 : /* Lookup the associated hash functions */
984 1240 : if (!get_op_hash_functions(opexpr->opno,
985 : &left_hashfn, &right_hashfn))
986 0 : elog(ERROR, "could not find hash function for hash operator %u",
987 : opexpr->opno);
988 1240 : fmgr_info(left_hashfn, &lhs_hash_funcs[i - 1]);
989 1240 : fmgr_info(right_hashfn, &sstate->tab_hash_funcs[i - 1]);
990 :
991 : /* Set collation */
992 1240 : sstate->tab_collations[i - 1] = opexpr->inputcollid;
993 :
994 : /* keyColIdx is just column numbers 1..n */
995 1240 : sstate->keyColIdx[i - 1] = i;
996 :
997 1240 : i++;
998 : }
999 :
1000 : /*
1001 : * Construct tupdescs, slots and projection nodes for left and right
1002 : * sides. The lefthand expressions will be evaluated in the parent
1003 : * plan node's exprcontext, which we don't have access to here.
1004 : * Fortunately we can just pass NULL for now and fill it in later
1005 : * (hack alert!). The righthand expressions will be evaluated in our
1006 : * own innerecontext.
1007 : */
1008 1142 : tupDescLeft = ExecTypeFromTL(lefttlist);
1009 1142 : slot = ExecInitExtraTupleSlot(estate, tupDescLeft, &TTSOpsVirtual);
1010 1142 : sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
1011 : NULL,
1012 : slot,
1013 : parent,
1014 : NULL);
1015 :
1016 1142 : sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist);
1017 1142 : slot = ExecInitExtraTupleSlot(estate, tupDescRight, &TTSOpsVirtual);
1018 1142 : sstate->projRight = ExecBuildProjectionInfo(righttlist,
1019 : sstate->innerecontext,
1020 : slot,
1021 : sstate->planstate,
1022 : NULL);
1023 :
1024 : /* Build the ExprState for generating hash values */
1025 1142 : sstate->lhs_hash_expr = ExecBuildHash32FromAttrs(tupDescLeft,
1026 : &TTSOpsVirtual,
1027 : lhs_hash_funcs,
1028 : sstate->tab_collations,
1029 : sstate->numCols,
1030 : sstate->keyColIdx,
1031 : parent,
1032 : 0);
1033 :
1034 : /*
1035 : * Create comparator for lookups of rows in the table (potentially
1036 : * cross-type comparisons).
1037 : */
1038 1142 : sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
1039 : &TTSOpsVirtual, &TTSOpsMinimalTuple,
1040 : ncols,
1041 1142 : sstate->keyColIdx,
1042 : cross_eq_funcoids,
1043 1142 : sstate->tab_collations,
1044 : parent);
1045 : }
1046 :
1047 43710 : return sstate;
1048 : }
1049 :
1050 : /* ----------------------------------------------------------------
1051 : * ExecSetParamPlan
1052 : *
1053 : * Executes a subplan and sets its output parameters.
1054 : *
1055 : * This is called from ExecEvalParamExec() when the value of a PARAM_EXEC
1056 : * parameter is requested and the param's execPlan field is set (indicating
1057 : * that the param has not yet been evaluated). This allows lazy evaluation
1058 : * of initplans: we don't run the subplan until/unless we need its output.
1059 : * Note that this routine MUST clear the execPlan fields of the plan's
1060 : * output parameters after evaluating them!
1061 : *
1062 : * The results of this function are stored in the EState associated with the
1063 : * ExprContext (particularly, its ecxt_param_exec_vals); any pass-by-ref
1064 : * result Datums are allocated in the EState's per-query memory. The passed
1065 : * econtext can be any ExprContext belonging to that EState; which one is
1066 : * important only to the extent that the ExprContext's per-tuple memory
1067 : * context is used to evaluate any parameters passed down to the subplan.
1068 : * (Thus in principle, the shorter-lived the ExprContext the better, since
1069 : * that data isn't needed after we return. In practice, because initplan
1070 : * parameters are never more complex than Vars, Aggrefs, etc, evaluating them
1071 : * currently never leaks any memory anyway.)
1072 : * ----------------------------------------------------------------
1073 : */
1074 : void
1075 9602 : ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
1076 : {
1077 9602 : SubPlan *subplan = node->subplan;
1078 9602 : PlanState *planstate = node->planstate;
1079 9602 : SubLinkType subLinkType = subplan->subLinkType;
1080 9602 : EState *estate = planstate->state;
1081 9602 : ScanDirection dir = estate->es_direction;
1082 : MemoryContext oldcontext;
1083 : TupleTableSlot *slot;
1084 : ListCell *l;
1085 9602 : bool found = false;
1086 9602 : ArrayBuildStateAny *astate = NULL;
1087 :
1088 9602 : if (subLinkType == ANY_SUBLINK ||
1089 : subLinkType == ALL_SUBLINK)
1090 0 : elog(ERROR, "ANY/ALL subselect unsupported as initplan");
1091 9602 : if (subLinkType == CTE_SUBLINK)
1092 0 : elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
1093 9602 : if (subplan->parParam || subplan->args)
1094 0 : elog(ERROR, "correlated subplans should not be executed via ExecSetParamPlan");
1095 :
1096 : /*
1097 : * Enforce forward scan direction regardless of caller. It's hard but not
1098 : * impossible to get here in backward scan, so make it work anyway.
1099 : */
1100 9602 : estate->es_direction = ForwardScanDirection;
1101 :
1102 : /* Initialize ArrayBuildStateAny in caller's context, if needed */
1103 9602 : if (subLinkType == ARRAY_SUBLINK)
1104 122 : astate = initArrayResultAny(subplan->firstColType,
1105 : CurrentMemoryContext, true);
1106 :
1107 : /*
1108 : * Must switch to per-query memory context.
1109 : */
1110 9602 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
1111 :
1112 : /*
1113 : * Run the plan. (If it needs to be rescanned, the first ExecProcNode
1114 : * call will take care of that.)
1115 : */
1116 9602 : for (slot = ExecProcNode(planstate);
1117 30564 : !TupIsNull(slot);
1118 20962 : slot = ExecProcNode(planstate))
1119 : {
1120 21114 : TupleDesc tdesc = slot->tts_tupleDescriptor;
1121 21114 : int i = 1;
1122 :
1123 21114 : if (subLinkType == EXISTS_SUBLINK)
1124 : {
1125 : /* There can be only one setParam... */
1126 134 : int paramid = linitial_int(subplan->setParam);
1127 134 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1128 :
1129 134 : prm->execPlan = NULL;
1130 134 : prm->value = BoolGetDatum(true);
1131 134 : prm->isnull = false;
1132 134 : found = true;
1133 134 : break;
1134 : }
1135 :
1136 20980 : if (subLinkType == ARRAY_SUBLINK)
1137 12334 : {
1138 : Datum dvalue;
1139 : bool disnull;
1140 :
1141 12334 : found = true;
1142 : /* stash away current value */
1143 : Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
1144 12334 : dvalue = slot_getattr(slot, 1, &disnull);
1145 12334 : astate = accumArrayResultAny(astate, dvalue, disnull,
1146 : subplan->firstColType, oldcontext);
1147 : /* keep scanning subplan to collect all values */
1148 12334 : continue;
1149 : }
1150 :
1151 8646 : if (found &&
1152 12 : (subLinkType == EXPR_SUBLINK ||
1153 6 : subLinkType == MULTIEXPR_SUBLINK ||
1154 : subLinkType == ROWCOMPARE_SUBLINK))
1155 18 : ereport(ERROR,
1156 : (errcode(ERRCODE_CARDINALITY_VIOLATION),
1157 : errmsg("more than one row returned by a subquery used as an expression")));
1158 :
1159 8628 : found = true;
1160 :
1161 : /*
1162 : * We need to copy the subplan's tuple into our own context, in case
1163 : * any of the params are pass-by-ref type --- the pointers stored in
1164 : * the param structs will point at this copied tuple! node->curTuple
1165 : * keeps track of the copied tuple for eventual freeing.
1166 : */
1167 8628 : if (node->curTuple)
1168 544 : heap_freetuple(node->curTuple);
1169 8628 : node->curTuple = ExecCopySlotHeapTuple(slot);
1170 :
1171 : /*
1172 : * Now set all the setParam params from the columns of the tuple
1173 : */
1174 17292 : foreach(l, subplan->setParam)
1175 : {
1176 8664 : int paramid = lfirst_int(l);
1177 8664 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1178 :
1179 8664 : prm->execPlan = NULL;
1180 8664 : prm->value = heap_getattr(node->curTuple, i, tdesc,
1181 : &(prm->isnull));
1182 8664 : i++;
1183 : }
1184 : }
1185 :
1186 9584 : if (subLinkType == ARRAY_SUBLINK)
1187 : {
1188 : /* There can be only one setParam... */
1189 122 : int paramid = linitial_int(subplan->setParam);
1190 122 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1191 :
1192 : /*
1193 : * We build the result array in query context so it won't disappear;
1194 : * to avoid leaking memory across repeated calls, we have to remember
1195 : * the latest value, much as for curTuple above.
1196 : */
1197 122 : if (node->curArray != PointerGetDatum(NULL))
1198 0 : pfree(DatumGetPointer(node->curArray));
1199 122 : node->curArray = makeArrayResultAny(astate,
1200 : econtext->ecxt_per_query_memory,
1201 : true);
1202 122 : prm->execPlan = NULL;
1203 122 : prm->value = node->curArray;
1204 122 : prm->isnull = false;
1205 : }
1206 9462 : else if (!found)
1207 : {
1208 718 : if (subLinkType == EXISTS_SUBLINK)
1209 : {
1210 : /* There can be only one setParam... */
1211 668 : int paramid = linitial_int(subplan->setParam);
1212 668 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1213 :
1214 668 : prm->execPlan = NULL;
1215 668 : prm->value = BoolGetDatum(false);
1216 668 : prm->isnull = false;
1217 : }
1218 : else
1219 : {
1220 : /* For other sublink types, set all the output params to NULL */
1221 106 : foreach(l, subplan->setParam)
1222 : {
1223 56 : int paramid = lfirst_int(l);
1224 56 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1225 :
1226 56 : prm->execPlan = NULL;
1227 56 : prm->value = (Datum) 0;
1228 56 : prm->isnull = true;
1229 : }
1230 : }
1231 : }
1232 :
1233 9584 : MemoryContextSwitchTo(oldcontext);
1234 :
1235 : /* restore scan direction */
1236 9584 : estate->es_direction = dir;
1237 9584 : }
1238 :
1239 : /*
1240 : * ExecSetParamPlanMulti
1241 : *
1242 : * Apply ExecSetParamPlan to evaluate any not-yet-evaluated initplan output
1243 : * parameters whose ParamIDs are listed in "params". Any listed params that
1244 : * are not initplan outputs are ignored.
1245 : *
1246 : * As with ExecSetParamPlan, any ExprContext belonging to the current EState
1247 : * can be used, but in principle a shorter-lived ExprContext is better than a
1248 : * longer-lived one.
1249 : */
1250 : void
1251 1376 : ExecSetParamPlanMulti(const Bitmapset *params, ExprContext *econtext)
1252 : {
1253 : int paramid;
1254 :
1255 1376 : paramid = -1;
1256 1818 : while ((paramid = bms_next_member(params, paramid)) >= 0)
1257 : {
1258 442 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1259 :
1260 442 : if (prm->execPlan != NULL)
1261 : {
1262 : /* Parameter not evaluated yet, so go do it */
1263 34 : ExecSetParamPlan(prm->execPlan, econtext);
1264 : /* ExecSetParamPlan should have processed this param... */
1265 : Assert(prm->execPlan == NULL);
1266 : }
1267 : }
1268 1376 : }
1269 :
1270 : /*
1271 : * Mark an initplan as needing recalculation
1272 : */
1273 : void
1274 1392 : ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
1275 : {
1276 1392 : PlanState *planstate = node->planstate;
1277 1392 : SubPlan *subplan = node->subplan;
1278 1392 : EState *estate = parent->state;
1279 : ListCell *l;
1280 :
1281 : /* sanity checks */
1282 1392 : if (subplan->parParam != NIL)
1283 0 : elog(ERROR, "direct correlated subquery unsupported as initplan");
1284 1392 : if (subplan->setParam == NIL)
1285 0 : elog(ERROR, "setParam list of initplan is empty");
1286 1392 : if (bms_is_empty(planstate->plan->extParam))
1287 0 : elog(ERROR, "extParam set of initplan is empty");
1288 :
1289 : /*
1290 : * Don't actually re-scan: it'll happen inside ExecSetParamPlan if needed.
1291 : */
1292 :
1293 : /*
1294 : * Mark this subplan's output parameters as needing recalculation.
1295 : *
1296 : * CTE subplans are never executed via parameter recalculation; instead
1297 : * they get run when called by nodeCtescan.c. So don't mark the output
1298 : * parameter of a CTE subplan as dirty, but do set the chgParam bit for it
1299 : * so that dependent plan nodes will get told to rescan.
1300 : */
1301 2784 : foreach(l, subplan->setParam)
1302 : {
1303 1392 : int paramid = lfirst_int(l);
1304 1392 : ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
1305 :
1306 1392 : if (subplan->subLinkType != CTE_SUBLINK)
1307 856 : prm->execPlan = node;
1308 :
1309 1392 : parent->chgParam = bms_add_member(parent->chgParam, paramid);
1310 : }
1311 1392 : }
|