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