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 2860070 : ExecSubPlan(SubPlanState *node,
63 : ExprContext *econtext,
64 : bool *isNull)
65 : {
66 2860070 : SubPlan *subplan = node->subplan;
67 2860070 : EState *estate = node->planstate->state;
68 2860070 : ScanDirection dir = estate->es_direction;
69 : Datum retval;
70 :
71 2860070 : CHECK_FOR_INTERRUPTS();
72 :
73 : /* Set non-null as default */
74 2860070 : *isNull = false;
75 :
76 : /* Sanity checks */
77 2860070 : if (subplan->subLinkType == CTE_SUBLINK)
78 0 : elog(ERROR, "CTE subplans should not be executed via ExecSubPlan");
79 2860070 : 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 2860070 : estate->es_direction = ForwardScanDirection;
84 :
85 : /* Select appropriate evaluation strategy */
86 2860070 : if (subplan->useHashTable)
87 1504068 : retval = ExecHashSubPlan(node, econtext, isNull);
88 : else
89 1356002 : retval = ExecScanSubPlan(node, econtext, isNull);
90 :
91 : /* restore scan direction */
92 2860064 : estate->es_direction = dir;
93 :
94 2860064 : return retval;
95 : }
96 :
97 : /*
98 : * ExecHashSubPlan: store subselect result in an in-memory hash table
99 : */
100 : static Datum
101 1504068 : ExecHashSubPlan(SubPlanState *node,
102 : ExprContext *econtext,
103 : bool *isNull)
104 : {
105 1504068 : SubPlan *subplan = node->subplan;
106 1504068 : PlanState *planstate = node->planstate;
107 : TupleTableSlot *slot;
108 :
109 : /* Shouldn't have any direct correlation Vars */
110 1504068 : 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 1504068 : if (node->hashtable == NULL || planstate->chgParam != NULL)
118 1376 : buildSubPlanHash(node, econtext);
119 :
120 : /*
121 : * The result for an empty subplan is always FALSE; no need to evaluate
122 : * lefthand side.
123 : */
124 1504062 : *isNull = false;
125 1504062 : if (!node->havehashrows && !node->havenullrows)
126 661054 : 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 843008 : node->projLeft->pi_exprContext = econtext;
133 843008 : 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 843008 : if (slotNoNulls(slot))
158 : {
159 1685920 : if (node->havehashrows &&
160 842948 : FindTupleHashEntry(node->hashtable,
161 : slot,
162 : node->cur_eq_comp,
163 : node->lhs_hash_expr) != NULL)
164 : {
165 63104 : ExecClearTuple(slot);
166 63104 : return BoolGetDatum(true);
167 : }
168 779904 : 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 779850 : ExecClearTuple(slot);
176 779850 : 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 1356002 : ExecScanSubPlan(SubPlanState *node,
224 : ExprContext *econtext,
225 : bool *isNull)
226 : {
227 1356002 : SubPlan *subplan = node->subplan;
228 1356002 : PlanState *planstate = node->planstate;
229 1356002 : SubLinkType subLinkType = subplan->subLinkType;
230 : MemoryContext oldcontext;
231 : TupleTableSlot *slot;
232 : Datum result;
233 1356002 : bool found = false; /* true if got at least one subplan tuple */
234 : ListCell *l;
235 1356002 : ArrayBuildStateAny *astate = NULL;
236 :
237 : /* Initialize ArrayBuildStateAny in caller's context, if needed */
238 1356002 : if (subLinkType == ARRAY_SUBLINK)
239 50770 : 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 1356002 : 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 2739178 : foreach(l, subplan->parParam)
256 : {
257 1383176 : int paramid = lfirst_int(l);
258 :
259 1383176 : planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
260 : }
261 :
262 : /* with that done, we can reset the subplan */
263 1356002 : 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 1356002 : result = BoolGetDatum(subLinkType == ALL_SUBLINK);
292 1356002 : *isNull = false;
293 :
294 1667736 : for (slot = ExecProcNode(planstate);
295 1610218 : !TupIsNull(slot);
296 311734 : slot = ExecProcNode(planstate))
297 : {
298 312568 : TupleDesc tdesc = slot->tts_tupleDescriptor;
299 : Datum rowresult;
300 : bool rownull;
301 : int col;
302 : ListCell *plst;
303 :
304 312568 : if (subLinkType == EXISTS_SUBLINK)
305 : {
306 690 : found = true;
307 690 : result = BoolGetDatum(true);
308 834 : break;
309 : }
310 :
311 311878 : if (subLinkType == EXPR_SUBLINK)
312 : {
313 : /* cannot allow multiple input tuples for EXPR sublink */
314 295788 : 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 295788 : 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 295788 : if (node->curTuple)
329 290294 : heap_freetuple(node->curTuple);
330 295788 : node->curTuple = ExecCopySlotHeapTuple(slot);
331 :
332 295788 : result = heap_getattr(node->curTuple, 1, tdesc, isNull);
333 : /* keep scanning subplan to make sure there's only one tuple */
334 300784 : continue;
335 : }
336 :
337 16090 : 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 15850 : if (subLinkType == ARRAY_SUBLINK)
379 : {
380 : Datum dvalue;
381 : bool disnull;
382 :
383 4756 : found = true;
384 : /* stash away current value */
385 : Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
386 4756 : dvalue = slot_getattr(slot, 1, &disnull);
387 4756 : astate = accumArrayResultAny(astate, dvalue, disnull,
388 : subplan->firstColType, oldcontext);
389 : /* keep scanning subplan to collect all values */
390 4756 : continue;
391 : }
392 :
393 : /* cannot allow multiple input tuples for ROWCOMPARE sublink either */
394 11094 : 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 11094 : 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 11094 : col = 1;
407 32946 : foreach(plst, subplan->paramIds)
408 : {
409 21852 : int paramid = lfirst_int(plst);
410 : ParamExecData *prmdata;
411 :
412 21852 : prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
413 : Assert(prmdata->execPlan == NULL);
414 21852 : prmdata->value = slot_getattr(slot, col, &(prmdata->isnull));
415 21852 : col++;
416 : }
417 :
418 11094 : rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext,
419 : &rownull);
420 :
421 11094 : if (subLinkType == ANY_SUBLINK)
422 : {
423 : /* combine across rows per OR semantics */
424 10956 : if (rownull)
425 0 : *isNull = true;
426 10956 : else if (DatumGetBool(rowresult))
427 : {
428 120 : result = BoolGetDatum(true);
429 120 : *isNull = false;
430 120 : 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 1356002 : MemoryContextSwitchTo(oldcontext);
454 :
455 1356002 : if (subLinkType == ARRAY_SUBLINK)
456 : {
457 : /* We return the result in the caller's context */
458 50770 : result = makeArrayResultAny(astate, oldcontext, true);
459 : }
460 1305232 : 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 1002898 : if (subLinkType == EXPR_SUBLINK ||
468 : subLinkType == ROWCOMPARE_SUBLINK)
469 : {
470 20438 : result = (Datum) 0;
471 20438 : *isNull = true;
472 : }
473 982460 : 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 1356002 : return result;
490 : }
491 :
492 : /*
493 : * buildSubPlanHash: load hash table by scanning subplan output.
494 : */
495 : static void
496 1376 : buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
497 : {
498 1376 : SubPlan *subplan = node->subplan;
499 1376 : PlanState *planstate = node->planstate;
500 1376 : int ncols = node->numCols;
501 1376 : 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 : * Because the input slot for each hash table is always the slot resulting
524 : * from an ExecProject(), we can use TTSOpsVirtual for the input ops. This
525 : * saves a needless fetch inner op step for the hashing ExprState created
526 : * in BuildTupleHashTable().
527 : */
528 1376 : MemoryContextReset(node->hashtablecxt);
529 1376 : node->havehashrows = false;
530 1376 : node->havenullrows = false;
531 :
532 1376 : nbuckets = clamp_cardinality_to_long(planstate->plan->plan_rows);
533 1376 : if (nbuckets < 1)
534 0 : nbuckets = 1;
535 :
536 1376 : if (node->hashtable)
537 594 : ResetTupleHashTable(node->hashtable);
538 : else
539 782 : node->hashtable = BuildTupleHashTable(node->parent,
540 : node->descRight,
541 : &TTSOpsVirtual,
542 : ncols,
543 : node->keyColIdx,
544 782 : node->tab_eq_funcoids,
545 : node->tab_hash_funcs,
546 : node->tab_collations,
547 : nbuckets,
548 : 0,
549 782 : node->planstate->state->es_query_cxt,
550 : node->hashtablecxt,
551 : node->hashtempcxt,
552 : false);
553 :
554 1376 : if (!subplan->unknownEqFalse)
555 : {
556 762 : if (ncols == 1)
557 714 : nbuckets = 1; /* there can only be one entry */
558 : else
559 : {
560 48 : nbuckets /= 16;
561 48 : if (nbuckets < 1)
562 0 : nbuckets = 1;
563 : }
564 :
565 762 : if (node->hashnulls)
566 594 : ResetTupleHashTable(node->hashnulls);
567 : else
568 168 : node->hashnulls = BuildTupleHashTable(node->parent,
569 : node->descRight,
570 : &TTSOpsVirtual,
571 : ncols,
572 : node->keyColIdx,
573 168 : node->tab_eq_funcoids,
574 : node->tab_hash_funcs,
575 : node->tab_collations,
576 : nbuckets,
577 : 0,
578 168 : node->planstate->state->es_query_cxt,
579 : node->hashtablecxt,
580 : node->hashtempcxt,
581 : false);
582 : }
583 : else
584 614 : node->hashnulls = NULL;
585 :
586 : /*
587 : * We are probably in a short-lived expression-evaluation context. Switch
588 : * to the per-query context for manipulating the child plan.
589 : */
590 1376 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
591 :
592 : /*
593 : * Reset subplan to start.
594 : */
595 1376 : ExecReScan(planstate);
596 :
597 : /*
598 : * Scan the subplan and load the hash table(s). Note that when there are
599 : * duplicate rows coming out of the sub-select, only one copy is stored.
600 : */
601 183286 : for (slot = ExecProcNode(planstate);
602 182608 : !TupIsNull(slot);
603 181910 : slot = ExecProcNode(planstate))
604 : {
605 181916 : int col = 1;
606 : ListCell *plst;
607 : bool isnew;
608 :
609 : /*
610 : * Load up the Params representing the raw sub-select outputs, then
611 : * form the projection tuple to store in the hashtable.
612 : */
613 417868 : foreach(plst, subplan->paramIds)
614 : {
615 235952 : int paramid = lfirst_int(plst);
616 : ParamExecData *prmdata;
617 :
618 235952 : prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
619 : Assert(prmdata->execPlan == NULL);
620 235952 : prmdata->value = slot_getattr(slot, col,
621 : &(prmdata->isnull));
622 235952 : col++;
623 : }
624 181916 : slot = ExecProject(node->projRight);
625 :
626 : /*
627 : * If result contains any nulls, store separately or not at all.
628 : */
629 181916 : if (slotNoNulls(slot))
630 : {
631 181892 : (void) LookupTupleHashEntry(node->hashtable, slot, &isnew, NULL);
632 181886 : node->havehashrows = true;
633 : }
634 24 : else if (node->hashnulls)
635 : {
636 24 : (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew, NULL);
637 24 : node->havenullrows = true;
638 : }
639 :
640 : /*
641 : * Reset innerecontext after each inner tuple to free any memory used
642 : * during ExecProject.
643 : */
644 181910 : ResetExprContext(innerecontext);
645 : }
646 :
647 : /*
648 : * Since the projected tuples are in the sub-query's context and not the
649 : * main context, we'd better clear the tuple slot before there's any
650 : * chance of a reset of the sub-query's context. Else we will have the
651 : * potential for a double free attempt. (XXX possibly no longer needed,
652 : * but can't hurt.)
653 : */
654 1370 : ExecClearTuple(node->projRight->pi_state.resultslot);
655 :
656 1370 : MemoryContextSwitchTo(oldcontext);
657 1370 : }
658 :
659 : /*
660 : * execTuplesUnequal
661 : * Return true if two tuples are definitely unequal in the indicated
662 : * fields.
663 : *
664 : * Nulls are neither equal nor unequal to anything else. A true result
665 : * is obtained only if there are non-null fields that compare not-equal.
666 : *
667 : * slot1, slot2: the tuples to compare (must have same columns!)
668 : * numCols: the number of attributes to be examined
669 : * matchColIdx: array of attribute column numbers
670 : * eqFunctions: array of fmgr lookup info for the equality functions to use
671 : * evalContext: short-term memory context for executing the functions
672 : */
673 : static bool
674 78 : execTuplesUnequal(TupleTableSlot *slot1,
675 : TupleTableSlot *slot2,
676 : int numCols,
677 : AttrNumber *matchColIdx,
678 : FmgrInfo *eqfunctions,
679 : const Oid *collations,
680 : MemoryContext evalContext)
681 : {
682 : MemoryContext oldContext;
683 : bool result;
684 : int i;
685 :
686 : /* Reset and switch into the temp context. */
687 78 : MemoryContextReset(evalContext);
688 78 : oldContext = MemoryContextSwitchTo(evalContext);
689 :
690 : /*
691 : * We cannot report a match without checking all the fields, but we can
692 : * report a non-match as soon as we find unequal fields. So, start
693 : * comparing at the last field (least significant sort key). That's the
694 : * most likely to be different if we are dealing with sorted input.
695 : */
696 78 : result = false;
697 :
698 192 : for (i = numCols; --i >= 0;)
699 : {
700 156 : AttrNumber att = matchColIdx[i];
701 : Datum attr1,
702 : attr2;
703 : bool isNull1,
704 : isNull2;
705 :
706 156 : attr1 = slot_getattr(slot1, att, &isNull1);
707 :
708 156 : if (isNull1)
709 78 : continue; /* can't prove anything here */
710 :
711 114 : attr2 = slot_getattr(slot2, att, &isNull2);
712 :
713 114 : if (isNull2)
714 36 : continue; /* can't prove anything here */
715 :
716 : /* Apply the type-specific equality function */
717 78 : if (!DatumGetBool(FunctionCall2Coll(&eqfunctions[i],
718 78 : collations[i],
719 : attr1, attr2)))
720 : {
721 42 : result = true; /* they are unequal */
722 42 : break;
723 : }
724 : }
725 :
726 78 : MemoryContextSwitchTo(oldContext);
727 :
728 78 : return result;
729 : }
730 :
731 : /*
732 : * findPartialMatch: does the hashtable contain an entry that is not
733 : * provably distinct from the tuple?
734 : *
735 : * We have to scan the whole hashtable; we can't usefully use hashkeys
736 : * to guide probing, since we might get partial matches on tuples with
737 : * hashkeys quite unrelated to what we'd get from the given tuple.
738 : *
739 : * Caller must provide the equality functions to use, since in cross-type
740 : * cases these are different from the hashtable's internal functions.
741 : */
742 : static bool
743 78 : findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
744 : FmgrInfo *eqfunctions)
745 : {
746 78 : int numCols = hashtable->numCols;
747 78 : AttrNumber *keyColIdx = hashtable->keyColIdx;
748 : TupleHashIterator hashiter;
749 : TupleHashEntry entry;
750 :
751 78 : InitTupleHashIterator(hashtable, &hashiter);
752 120 : while ((entry = ScanTupleHashTable(hashtable, &hashiter)) != NULL)
753 : {
754 78 : CHECK_FOR_INTERRUPTS();
755 :
756 78 : ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
757 78 : if (!execTuplesUnequal(slot, hashtable->tableslot,
758 : numCols, keyColIdx,
759 : eqfunctions,
760 78 : hashtable->tab_collations,
761 : hashtable->tempcxt))
762 : {
763 : TermTupleHashIterator(&hashiter);
764 36 : return true;
765 : }
766 : }
767 : /* No TermTupleHashIterator call needed here */
768 42 : return false;
769 : }
770 :
771 : /*
772 : * slotAllNulls: is the slot completely NULL?
773 : *
774 : * This does not test for dropped columns, which is OK because we only
775 : * use it on projected tuples.
776 : */
777 : static bool
778 36 : slotAllNulls(TupleTableSlot *slot)
779 : {
780 36 : int ncols = slot->tts_tupleDescriptor->natts;
781 : int i;
782 :
783 36 : for (i = 1; i <= ncols; i++)
784 : {
785 36 : if (!slot_attisnull(slot, i))
786 36 : return false;
787 : }
788 0 : return true;
789 : }
790 :
791 : /*
792 : * slotNoNulls: is the slot entirely not NULL?
793 : *
794 : * This does not test for dropped columns, which is OK because we only
795 : * use it on projected tuples.
796 : */
797 : static bool
798 1024924 : slotNoNulls(TupleTableSlot *slot)
799 : {
800 1024924 : int ncols = slot->tts_tupleDescriptor->natts;
801 : int i;
802 :
803 2164010 : for (i = 1; i <= ncols; i++)
804 : {
805 1139146 : if (slot_attisnull(slot, i))
806 60 : return false;
807 : }
808 1024864 : return true;
809 : }
810 :
811 : /* ----------------------------------------------------------------
812 : * ExecInitSubPlan
813 : *
814 : * Create a SubPlanState for a SubPlan; this is the SubPlan-specific part
815 : * of ExecInitExpr(). We split it out so that it can be used for InitPlans
816 : * as well as regular SubPlans. Note that we don't link the SubPlan into
817 : * the parent's subPlan list, because that shouldn't happen for InitPlans.
818 : * Instead, ExecInitExpr() does that one part.
819 : *
820 : * We also rely on ExecInitExpr(), more precisely ExecInitSubPlanExpr(), to
821 : * evaluate input parameters, as that allows them to be evaluated as part of
822 : * the expression referencing the SubPlan.
823 : * ----------------------------------------------------------------
824 : */
825 : SubPlanState *
826 39128 : ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
827 : {
828 39128 : SubPlanState *sstate = makeNode(SubPlanState);
829 39128 : EState *estate = parent->state;
830 :
831 39128 : sstate->subplan = subplan;
832 :
833 : /* Link the SubPlanState to already-initialized subplan */
834 78256 : sstate->planstate = (PlanState *) list_nth(estate->es_subplanstates,
835 39128 : subplan->plan_id - 1);
836 :
837 : /*
838 : * This check can fail if the planner mistakenly puts a parallel-unsafe
839 : * subplan into a parallelized subquery; see ExecSerializePlan.
840 : */
841 39128 : if (sstate->planstate == NULL)
842 0 : elog(ERROR, "subplan \"%s\" was not initialized",
843 : subplan->plan_name);
844 :
845 : /* Link to parent's state, too */
846 39128 : sstate->parent = parent;
847 :
848 : /* Initialize subexpressions */
849 39128 : sstate->testexpr = ExecInitExpr((Expr *) subplan->testexpr, parent);
850 :
851 : /*
852 : * initialize my state
853 : */
854 39128 : sstate->curTuple = NULL;
855 39128 : sstate->curArray = PointerGetDatum(NULL);
856 39128 : sstate->projLeft = NULL;
857 39128 : sstate->projRight = NULL;
858 39128 : sstate->hashtable = NULL;
859 39128 : sstate->hashnulls = NULL;
860 39128 : sstate->hashtablecxt = NULL;
861 39128 : sstate->hashtempcxt = NULL;
862 39128 : sstate->innerecontext = NULL;
863 39128 : sstate->keyColIdx = NULL;
864 39128 : sstate->tab_eq_funcoids = NULL;
865 39128 : sstate->tab_hash_funcs = NULL;
866 39128 : sstate->tab_collations = NULL;
867 39128 : sstate->cur_eq_funcs = NULL;
868 :
869 : /*
870 : * If this is an initplan, it has output parameters that the parent plan
871 : * will use, so mark those parameters as needing evaluation. We don't
872 : * actually run the subplan until we first need one of its outputs.
873 : *
874 : * A CTE subplan's output parameter is never to be evaluated in the normal
875 : * way, so skip this in that case.
876 : *
877 : * Note that we don't set parent->chgParam here: the parent plan hasn't
878 : * been run yet, so no need to force it to re-run.
879 : */
880 39128 : if (subplan->setParam != NIL && subplan->parParam == NIL &&
881 12704 : subplan->subLinkType != CTE_SUBLINK)
882 : {
883 : ListCell *lst;
884 :
885 21376 : foreach(lst, subplan->setParam)
886 : {
887 10712 : int paramid = lfirst_int(lst);
888 10712 : ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
889 :
890 10712 : prm->execPlan = sstate;
891 : }
892 : }
893 :
894 : /*
895 : * If we are going to hash the subquery output, initialize relevant stuff.
896 : * (We don't create the hashtable until needed, though.)
897 : */
898 39128 : if (subplan->useHashTable)
899 : {
900 : int ncols,
901 : i;
902 : TupleDesc tupDescLeft;
903 : TupleDesc tupDescRight;
904 : Oid *cross_eq_funcoids;
905 : TupleTableSlot *slot;
906 : FmgrInfo *lhs_hash_funcs;
907 : List *oplist,
908 : *lefttlist,
909 : *righttlist;
910 : ListCell *l;
911 :
912 : /* We need a memory context to hold the hash table(s) */
913 960 : sstate->hashtablecxt =
914 960 : AllocSetContextCreate(CurrentMemoryContext,
915 : "Subplan HashTable Context",
916 : ALLOCSET_DEFAULT_SIZES);
917 : /* and a small one for the hash tables to use as temp storage */
918 960 : sstate->hashtempcxt =
919 960 : AllocSetContextCreate(CurrentMemoryContext,
920 : "Subplan HashTable Temp Context",
921 : ALLOCSET_SMALL_SIZES);
922 : /* and a short-lived exprcontext for function evaluation */
923 960 : sstate->innerecontext = CreateExprContext(estate);
924 :
925 : /*
926 : * We use ExecProject to evaluate the lefthand and righthand
927 : * expression lists and form tuples. (You might think that we could
928 : * use the sub-select's output tuples directly, but that is not the
929 : * case if we had to insert any run-time coercions of the sub-select's
930 : * output datatypes; anyway this avoids storing any resjunk columns
931 : * that might be in the sub-select's output.) Run through the
932 : * combining expressions to build tlists for the lefthand and
933 : * righthand sides.
934 : *
935 : * We also extract the combining operators themselves to initialize
936 : * the equality and hashing functions for the hash tables.
937 : */
938 960 : if (IsA(subplan->testexpr, OpExpr))
939 : {
940 : /* single combining operator */
941 862 : oplist = list_make1(subplan->testexpr);
942 : }
943 98 : else if (is_andclause(subplan->testexpr))
944 : {
945 : /* multiple combining operators */
946 98 : oplist = castNode(BoolExpr, subplan->testexpr)->args;
947 : }
948 : else
949 : {
950 : /* shouldn't see anything else in a hashable subplan */
951 0 : elog(ERROR, "unrecognized testexpr type: %d",
952 : (int) nodeTag(subplan->testexpr));
953 : oplist = NIL; /* keep compiler quiet */
954 : }
955 960 : ncols = list_length(oplist);
956 :
957 960 : lefttlist = righttlist = NIL;
958 960 : sstate->numCols = ncols;
959 960 : sstate->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber));
960 960 : sstate->tab_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
961 960 : sstate->tab_collations = (Oid *) palloc(ncols * sizeof(Oid));
962 960 : sstate->tab_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
963 960 : lhs_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
964 960 : sstate->cur_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
965 : /* we'll need the cross-type equality fns below, but not in sstate */
966 960 : cross_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
967 :
968 960 : i = 1;
969 2018 : foreach(l, oplist)
970 : {
971 1058 : OpExpr *opexpr = lfirst_node(OpExpr, l);
972 : Expr *expr;
973 : TargetEntry *tle;
974 : Oid rhs_eq_oper;
975 : Oid left_hashfn;
976 : Oid right_hashfn;
977 :
978 : Assert(list_length(opexpr->args) == 2);
979 :
980 : /* Process lefthand argument */
981 1058 : expr = (Expr *) linitial(opexpr->args);
982 1058 : tle = makeTargetEntry(expr,
983 : i,
984 : NULL,
985 : false);
986 1058 : lefttlist = lappend(lefttlist, tle);
987 :
988 : /* Process righthand argument */
989 1058 : expr = (Expr *) lsecond(opexpr->args);
990 1058 : tle = makeTargetEntry(expr,
991 : i,
992 : NULL,
993 : false);
994 1058 : righttlist = lappend(righttlist, tle);
995 :
996 : /* Lookup the equality function (potentially cross-type) */
997 1058 : cross_eq_funcoids[i - 1] = opexpr->opfuncid;
998 1058 : fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
999 1058 : fmgr_info_set_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
1000 :
1001 : /* Look up the equality function for the RHS type */
1002 1058 : if (!get_compatible_hash_operators(opexpr->opno,
1003 : NULL, &rhs_eq_oper))
1004 0 : elog(ERROR, "could not find compatible hash operator for operator %u",
1005 : opexpr->opno);
1006 1058 : sstate->tab_eq_funcoids[i - 1] = get_opcode(rhs_eq_oper);
1007 :
1008 : /* Lookup the associated hash functions */
1009 1058 : if (!get_op_hash_functions(opexpr->opno,
1010 : &left_hashfn, &right_hashfn))
1011 0 : elog(ERROR, "could not find hash function for hash operator %u",
1012 : opexpr->opno);
1013 1058 : fmgr_info(left_hashfn, &lhs_hash_funcs[i - 1]);
1014 1058 : fmgr_info(right_hashfn, &sstate->tab_hash_funcs[i - 1]);
1015 :
1016 : /* Set collation */
1017 1058 : sstate->tab_collations[i - 1] = opexpr->inputcollid;
1018 :
1019 : /* keyColIdx is just column numbers 1..n */
1020 1058 : sstate->keyColIdx[i - 1] = i;
1021 :
1022 1058 : i++;
1023 : }
1024 :
1025 : /*
1026 : * Construct tupdescs, slots and projection nodes for left and right
1027 : * sides. The lefthand expressions will be evaluated in the parent
1028 : * plan node's exprcontext, which we don't have access to here.
1029 : * Fortunately we can just pass NULL for now and fill it in later
1030 : * (hack alert!). The righthand expressions will be evaluated in our
1031 : * own innerecontext.
1032 : */
1033 960 : tupDescLeft = ExecTypeFromTL(lefttlist);
1034 960 : slot = ExecInitExtraTupleSlot(estate, tupDescLeft, &TTSOpsVirtual);
1035 960 : sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
1036 : NULL,
1037 : slot,
1038 : parent,
1039 : NULL);
1040 :
1041 960 : sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist);
1042 960 : slot = ExecInitExtraTupleSlot(estate, tupDescRight, &TTSOpsVirtual);
1043 1920 : sstate->projRight = ExecBuildProjectionInfo(righttlist,
1044 : sstate->innerecontext,
1045 : slot,
1046 960 : sstate->planstate,
1047 : NULL);
1048 :
1049 : /* Build the ExprState for generating hash values */
1050 960 : sstate->lhs_hash_expr = ExecBuildHash32FromAttrs(tupDescLeft,
1051 : &TTSOpsVirtual,
1052 : lhs_hash_funcs,
1053 : sstate->tab_collations,
1054 : sstate->numCols,
1055 : sstate->keyColIdx,
1056 : parent,
1057 : 0);
1058 :
1059 : /*
1060 : * Create comparator for lookups of rows in the table (potentially
1061 : * cross-type comparisons).
1062 : */
1063 960 : sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
1064 : &TTSOpsVirtual, &TTSOpsMinimalTuple,
1065 : ncols,
1066 960 : sstate->keyColIdx,
1067 : cross_eq_funcoids,
1068 960 : sstate->tab_collations,
1069 : parent);
1070 : }
1071 :
1072 39128 : return sstate;
1073 : }
1074 :
1075 : /* ----------------------------------------------------------------
1076 : * ExecSetParamPlan
1077 : *
1078 : * Executes a subplan and sets its output parameters.
1079 : *
1080 : * This is called from ExecEvalParamExec() when the value of a PARAM_EXEC
1081 : * parameter is requested and the param's execPlan field is set (indicating
1082 : * that the param has not yet been evaluated). This allows lazy evaluation
1083 : * of initplans: we don't run the subplan until/unless we need its output.
1084 : * Note that this routine MUST clear the execPlan fields of the plan's
1085 : * output parameters after evaluating them!
1086 : *
1087 : * The results of this function are stored in the EState associated with the
1088 : * ExprContext (particularly, its ecxt_param_exec_vals); any pass-by-ref
1089 : * result Datums are allocated in the EState's per-query memory. The passed
1090 : * econtext can be any ExprContext belonging to that EState; which one is
1091 : * important only to the extent that the ExprContext's per-tuple memory
1092 : * context is used to evaluate any parameters passed down to the subplan.
1093 : * (Thus in principle, the shorter-lived the ExprContext the better, since
1094 : * that data isn't needed after we return. In practice, because initplan
1095 : * parameters are never more complex than Vars, Aggrefs, etc, evaluating them
1096 : * currently never leaks any memory anyway.)
1097 : * ----------------------------------------------------------------
1098 : */
1099 : void
1100 8804 : ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
1101 : {
1102 8804 : SubPlan *subplan = node->subplan;
1103 8804 : PlanState *planstate = node->planstate;
1104 8804 : SubLinkType subLinkType = subplan->subLinkType;
1105 8804 : EState *estate = planstate->state;
1106 8804 : ScanDirection dir = estate->es_direction;
1107 : MemoryContext oldcontext;
1108 : TupleTableSlot *slot;
1109 : ListCell *l;
1110 8804 : bool found = false;
1111 8804 : ArrayBuildStateAny *astate = NULL;
1112 :
1113 8804 : if (subLinkType == ANY_SUBLINK ||
1114 : subLinkType == ALL_SUBLINK)
1115 0 : elog(ERROR, "ANY/ALL subselect unsupported as initplan");
1116 8804 : if (subLinkType == CTE_SUBLINK)
1117 0 : elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
1118 8804 : if (subplan->parParam || subplan->args)
1119 0 : elog(ERROR, "correlated subplans should not be executed via ExecSetParamPlan");
1120 :
1121 : /*
1122 : * Enforce forward scan direction regardless of caller. It's hard but not
1123 : * impossible to get here in backward scan, so make it work anyway.
1124 : */
1125 8804 : estate->es_direction = ForwardScanDirection;
1126 :
1127 : /* Initialize ArrayBuildStateAny in caller's context, if needed */
1128 8804 : if (subLinkType == ARRAY_SUBLINK)
1129 80 : astate = initArrayResultAny(subplan->firstColType,
1130 : CurrentMemoryContext, true);
1131 :
1132 : /*
1133 : * Must switch to per-query memory context.
1134 : */
1135 8804 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
1136 :
1137 : /*
1138 : * Run the plan. (If it needs to be rescanned, the first ExecProcNode
1139 : * call will take care of that.)
1140 : */
1141 28840 : for (slot = ExecProcNode(planstate);
1142 26280 : !TupIsNull(slot);
1143 20036 : slot = ExecProcNode(planstate))
1144 : {
1145 20172 : TupleDesc tdesc = slot->tts_tupleDescriptor;
1146 20172 : int i = 1;
1147 :
1148 20172 : if (subLinkType == EXISTS_SUBLINK)
1149 : {
1150 : /* There can be only one setParam... */
1151 118 : int paramid = linitial_int(subplan->setParam);
1152 118 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1153 :
1154 118 : prm->execPlan = NULL;
1155 118 : prm->value = BoolGetDatum(true);
1156 118 : prm->isnull = false;
1157 118 : found = true;
1158 118 : break;
1159 : }
1160 :
1161 20054 : if (subLinkType == ARRAY_SUBLINK)
1162 : {
1163 : Datum dvalue;
1164 : bool disnull;
1165 :
1166 12142 : found = true;
1167 : /* stash away current value */
1168 : Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
1169 12142 : dvalue = slot_getattr(slot, 1, &disnull);
1170 12142 : astate = accumArrayResultAny(astate, dvalue, disnull,
1171 : subplan->firstColType, oldcontext);
1172 : /* keep scanning subplan to collect all values */
1173 12142 : continue;
1174 : }
1175 :
1176 7912 : if (found &&
1177 12 : (subLinkType == EXPR_SUBLINK ||
1178 6 : subLinkType == MULTIEXPR_SUBLINK ||
1179 : subLinkType == ROWCOMPARE_SUBLINK))
1180 18 : ereport(ERROR,
1181 : (errcode(ERRCODE_CARDINALITY_VIOLATION),
1182 : errmsg("more than one row returned by a subquery used as an expression")));
1183 :
1184 7894 : found = true;
1185 :
1186 : /*
1187 : * We need to copy the subplan's tuple into our own context, in case
1188 : * any of the params are pass-by-ref type --- the pointers stored in
1189 : * the param structs will point at this copied tuple! node->curTuple
1190 : * keeps track of the copied tuple for eventual freeing.
1191 : */
1192 7894 : if (node->curTuple)
1193 520 : heap_freetuple(node->curTuple);
1194 7894 : node->curTuple = ExecCopySlotHeapTuple(slot);
1195 :
1196 : /*
1197 : * Now set all the setParam params from the columns of the tuple
1198 : */
1199 15824 : foreach(l, subplan->setParam)
1200 : {
1201 7930 : int paramid = lfirst_int(l);
1202 7930 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1203 :
1204 7930 : prm->execPlan = NULL;
1205 7930 : prm->value = heap_getattr(node->curTuple, i, tdesc,
1206 : &(prm->isnull));
1207 7930 : i++;
1208 : }
1209 : }
1210 :
1211 8786 : if (subLinkType == ARRAY_SUBLINK)
1212 : {
1213 : /* There can be only one setParam... */
1214 80 : int paramid = linitial_int(subplan->setParam);
1215 80 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1216 :
1217 : /*
1218 : * We build the result array in query context so it won't disappear;
1219 : * to avoid leaking memory across repeated calls, we have to remember
1220 : * the latest value, much as for curTuple above.
1221 : */
1222 80 : if (node->curArray != PointerGetDatum(NULL))
1223 0 : pfree(DatumGetPointer(node->curArray));
1224 80 : node->curArray = makeArrayResultAny(astate,
1225 : econtext->ecxt_per_query_memory,
1226 : true);
1227 80 : prm->execPlan = NULL;
1228 80 : prm->value = node->curArray;
1229 80 : prm->isnull = false;
1230 : }
1231 8706 : else if (!found)
1232 : {
1233 712 : if (subLinkType == EXISTS_SUBLINK)
1234 : {
1235 : /* There can be only one setParam... */
1236 662 : int paramid = linitial_int(subplan->setParam);
1237 662 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1238 :
1239 662 : prm->execPlan = NULL;
1240 662 : prm->value = BoolGetDatum(false);
1241 662 : prm->isnull = false;
1242 : }
1243 : else
1244 : {
1245 : /* For other sublink types, set all the output params to NULL */
1246 106 : foreach(l, subplan->setParam)
1247 : {
1248 56 : int paramid = lfirst_int(l);
1249 56 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1250 :
1251 56 : prm->execPlan = NULL;
1252 56 : prm->value = (Datum) 0;
1253 56 : prm->isnull = true;
1254 : }
1255 : }
1256 : }
1257 :
1258 8786 : MemoryContextSwitchTo(oldcontext);
1259 :
1260 : /* restore scan direction */
1261 8786 : estate->es_direction = dir;
1262 8786 : }
1263 :
1264 : /*
1265 : * ExecSetParamPlanMulti
1266 : *
1267 : * Apply ExecSetParamPlan to evaluate any not-yet-evaluated initplan output
1268 : * parameters whose ParamIDs are listed in "params". Any listed params that
1269 : * are not initplan outputs are ignored.
1270 : *
1271 : * As with ExecSetParamPlan, any ExprContext belonging to the current EState
1272 : * can be used, but in principle a shorter-lived ExprContext is better than a
1273 : * longer-lived one.
1274 : */
1275 : void
1276 1336 : ExecSetParamPlanMulti(const Bitmapset *params, ExprContext *econtext)
1277 : {
1278 : int paramid;
1279 :
1280 1336 : paramid = -1;
1281 1750 : while ((paramid = bms_next_member(params, paramid)) >= 0)
1282 : {
1283 414 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1284 :
1285 414 : if (prm->execPlan != NULL)
1286 : {
1287 : /* Parameter not evaluated yet, so go do it */
1288 34 : ExecSetParamPlan(prm->execPlan, econtext);
1289 : /* ExecSetParamPlan should have processed this param... */
1290 : Assert(prm->execPlan == NULL);
1291 : }
1292 : }
1293 1336 : }
1294 :
1295 : /*
1296 : * Mark an initplan as needing recalculation
1297 : */
1298 : void
1299 1100 : ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
1300 : {
1301 1100 : PlanState *planstate = node->planstate;
1302 1100 : SubPlan *subplan = node->subplan;
1303 1100 : EState *estate = parent->state;
1304 : ListCell *l;
1305 :
1306 : /* sanity checks */
1307 1100 : if (subplan->parParam != NIL)
1308 0 : elog(ERROR, "direct correlated subquery unsupported as initplan");
1309 1100 : if (subplan->setParam == NIL)
1310 0 : elog(ERROR, "setParam list of initplan is empty");
1311 1100 : if (bms_is_empty(planstate->plan->extParam))
1312 0 : elog(ERROR, "extParam set of initplan is empty");
1313 :
1314 : /*
1315 : * Don't actually re-scan: it'll happen inside ExecSetParamPlan if needed.
1316 : */
1317 :
1318 : /*
1319 : * Mark this subplan's output parameters as needing recalculation.
1320 : *
1321 : * CTE subplans are never executed via parameter recalculation; instead
1322 : * they get run when called by nodeCtescan.c. So don't mark the output
1323 : * parameter of a CTE subplan as dirty, but do set the chgParam bit for it
1324 : * so that dependent plan nodes will get told to rescan.
1325 : */
1326 2200 : foreach(l, subplan->setParam)
1327 : {
1328 1100 : int paramid = lfirst_int(l);
1329 1100 : ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
1330 :
1331 1100 : if (subplan->subLinkType != CTE_SUBLINK)
1332 804 : prm->execPlan = node;
1333 :
1334 1100 : parent->chgParam = bms_add_member(parent->chgParam, paramid);
1335 : }
1336 1100 : }
|