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 2838836 : ExecSubPlan(SubPlanState *node,
63 : ExprContext *econtext,
64 : bool *isNull)
65 : {
66 2838836 : SubPlan *subplan = node->subplan;
67 2838836 : EState *estate = node->planstate->state;
68 2838836 : ScanDirection dir = estate->es_direction;
69 : Datum retval;
70 :
71 2838836 : CHECK_FOR_INTERRUPTS();
72 :
73 : /* Set non-null as default */
74 2838836 : *isNull = false;
75 :
76 : /* Sanity checks */
77 2838836 : if (subplan->subLinkType == CTE_SUBLINK)
78 0 : elog(ERROR, "CTE subplans should not be executed via ExecSubPlan");
79 2838836 : 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 2838836 : estate->es_direction = ForwardScanDirection;
84 :
85 : /* Select appropriate evaluation strategy */
86 2838836 : if (subplan->useHashTable)
87 1496972 : retval = ExecHashSubPlan(node, econtext, isNull);
88 : else
89 1341864 : retval = ExecScanSubPlan(node, econtext, isNull);
90 :
91 : /* restore scan direction */
92 2838830 : estate->es_direction = dir;
93 :
94 2838830 : return retval;
95 : }
96 :
97 : /*
98 : * ExecHashSubPlan: store subselect result in an in-memory hash table
99 : */
100 : static Datum
101 1496972 : ExecHashSubPlan(SubPlanState *node,
102 : ExprContext *econtext,
103 : bool *isNull)
104 : {
105 1496972 : SubPlan *subplan = node->subplan;
106 1496972 : PlanState *planstate = node->planstate;
107 : TupleTableSlot *slot;
108 :
109 : /* Shouldn't have any direct correlation Vars */
110 1496972 : 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 1496972 : 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 1496966 : *isNull = false;
125 1496966 : if (!node->havehashrows && !node->havenullrows)
126 656708 : 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 840258 : node->projLeft->pi_exprContext = econtext;
133 840258 : 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 840258 : if (slotNoNulls(slot))
158 : {
159 1680420 : if (node->havehashrows &&
160 840198 : FindTupleHashEntry(node->hashtable,
161 : slot,
162 : node->cur_eq_comp,
163 : node->lhs_hash_funcs) != NULL)
164 : {
165 63100 : ExecClearTuple(slot);
166 63100 : return BoolGetDatum(true);
167 : }
168 777158 : 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 777104 : ExecClearTuple(slot);
176 777104 : 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 1341864 : ExecScanSubPlan(SubPlanState *node,
224 : ExprContext *econtext,
225 : bool *isNull)
226 : {
227 1341864 : SubPlan *subplan = node->subplan;
228 1341864 : PlanState *planstate = node->planstate;
229 1341864 : SubLinkType subLinkType = subplan->subLinkType;
230 : MemoryContext oldcontext;
231 : TupleTableSlot *slot;
232 : Datum result;
233 1341864 : bool found = false; /* true if got at least one subplan tuple */
234 : ListCell *l;
235 1341864 : ArrayBuildStateAny *astate = NULL;
236 :
237 : /* Initialize ArrayBuildStateAny in caller's context, if needed */
238 1341864 : if (subLinkType == ARRAY_SUBLINK)
239 49274 : 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 1341864 : 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 2707200 : foreach(l, subplan->parParam)
256 : {
257 1365336 : int paramid = lfirst_int(l);
258 :
259 1365336 : planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
260 : }
261 :
262 : /* with that done, we can reset the subplan */
263 1341864 : 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 1341864 : result = BoolGetDatum(subLinkType == ALL_SUBLINK);
292 1341864 : *isNull = false;
293 :
294 1650000 : for (slot = ExecProcNode(planstate);
295 1597234 : !TupIsNull(slot);
296 308136 : slot = ExecProcNode(planstate))
297 : {
298 308958 : TupleDesc tdesc = slot->tts_tupleDescriptor;
299 : Datum rowresult;
300 : bool rownull;
301 : int col;
302 : ListCell *plst;
303 :
304 308958 : if (subLinkType == EXISTS_SUBLINK)
305 : {
306 690 : found = true;
307 690 : result = BoolGetDatum(true);
308 822 : break;
309 : }
310 :
311 308268 : if (subLinkType == EXPR_SUBLINK)
312 : {
313 : /* cannot allow multiple input tuples for EXPR sublink */
314 292262 : 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 292262 : 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 292262 : if (node->curTuple)
329 286940 : heap_freetuple(node->curTuple);
330 292262 : node->curTuple = ExecCopySlotHeapTuple(slot);
331 :
332 292262 : result = heap_getattr(node->curTuple, 1, tdesc, isNull);
333 : /* keep scanning subplan to make sure there's only one tuple */
334 297192 : continue;
335 : }
336 :
337 16006 : 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 15766 : if (subLinkType == ARRAY_SUBLINK)
379 : {
380 : Datum dvalue;
381 : bool disnull;
382 :
383 4690 : found = true;
384 : /* stash away current value */
385 : Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
386 4690 : dvalue = slot_getattr(slot, 1, &disnull);
387 4690 : astate = accumArrayResultAny(astate, dvalue, disnull,
388 : subplan->firstColType, oldcontext);
389 : /* keep scanning subplan to collect all values */
390 4690 : 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 1341864 : MemoryContextSwitchTo(oldcontext);
454 :
455 1341864 : if (subLinkType == ARRAY_SUBLINK)
456 : {
457 : /* We return the result in the caller's context */
458 49274 : result = makeArrayResultAny(astate, oldcontext, true);
459 : }
460 1292590 : 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 993794 : if (subLinkType == EXPR_SUBLINK ||
468 : subLinkType == ROWCOMPARE_SUBLINK)
469 : {
470 17772 : result = (Datum) 0;
471 17772 : *isNull = true;
472 : }
473 976022 : 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 1341864 : 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 1376 : MemoryContextReset(node->hashtablecxt);
524 1376 : node->havehashrows = false;
525 1376 : node->havenullrows = false;
526 :
527 1376 : nbuckets = clamp_cardinality_to_long(planstate->plan->plan_rows);
528 1376 : if (nbuckets < 1)
529 0 : nbuckets = 1;
530 :
531 1376 : if (node->hashtable)
532 594 : ResetTupleHashTable(node->hashtable);
533 : else
534 782 : node->hashtable = BuildTupleHashTableExt(node->parent,
535 : node->descRight,
536 : ncols,
537 : node->keyColIdx,
538 782 : node->tab_eq_funcoids,
539 : node->tab_hash_funcs,
540 : node->tab_collations,
541 : nbuckets,
542 : 0,
543 782 : node->planstate->state->es_query_cxt,
544 : node->hashtablecxt,
545 : node->hashtempcxt,
546 : false);
547 :
548 1376 : 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 614 : 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 1376 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
584 :
585 : /*
586 : * Reset subplan to start.
587 : */
588 1376 : 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 182772 : for (slot = ExecProcNode(planstate);
595 182094 : !TupIsNull(slot);
596 181396 : slot = ExecProcNode(planstate))
597 : {
598 181402 : 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 416840 : foreach(plst, subplan->paramIds)
607 : {
608 235438 : int paramid = lfirst_int(plst);
609 : ParamExecData *prmdata;
610 :
611 235438 : prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
612 : Assert(prmdata->execPlan == NULL);
613 235438 : prmdata->value = slot_getattr(slot, col,
614 : &(prmdata->isnull));
615 235438 : col++;
616 : }
617 181402 : slot = ExecProject(node->projRight);
618 :
619 : /*
620 : * If result contains any nulls, store separately or not at all.
621 : */
622 181402 : if (slotNoNulls(slot))
623 : {
624 181378 : (void) LookupTupleHashEntry(node->hashtable, slot, &isnew, NULL);
625 181372 : 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 181396 : 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 1370 : ExecClearTuple(node->projRight->pi_state.resultslot);
648 :
649 1370 : MemoryContextSwitchTo(oldcontext);
650 1370 : }
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 1021660 : slotNoNulls(TupleTableSlot *slot)
792 : {
793 1021660 : int ncols = slot->tts_tupleDescriptor->natts;
794 : int i;
795 :
796 2157482 : for (i = 1; i <= ncols; i++)
797 : {
798 1135882 : if (slot_attisnull(slot, i))
799 60 : return false;
800 : }
801 1021600 : 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 35990 : ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
820 : {
821 35990 : SubPlanState *sstate = makeNode(SubPlanState);
822 35990 : EState *estate = parent->state;
823 :
824 35990 : sstate->subplan = subplan;
825 :
826 : /* Link the SubPlanState to already-initialized subplan */
827 71980 : sstate->planstate = (PlanState *) list_nth(estate->es_subplanstates,
828 35990 : 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 35990 : 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 35990 : sstate->parent = parent;
840 :
841 : /* Initialize subexpressions */
842 35990 : sstate->testexpr = ExecInitExpr((Expr *) subplan->testexpr, parent);
843 :
844 : /*
845 : * initialize my state
846 : */
847 35990 : sstate->curTuple = NULL;
848 35990 : sstate->curArray = PointerGetDatum(NULL);
849 35990 : sstate->projLeft = NULL;
850 35990 : sstate->projRight = NULL;
851 35990 : sstate->hashtable = NULL;
852 35990 : sstate->hashnulls = NULL;
853 35990 : sstate->hashtablecxt = NULL;
854 35990 : sstate->hashtempcxt = NULL;
855 35990 : sstate->innerecontext = NULL;
856 35990 : sstate->keyColIdx = NULL;
857 35990 : sstate->tab_eq_funcoids = NULL;
858 35990 : sstate->tab_hash_funcs = NULL;
859 35990 : sstate->tab_eq_funcs = NULL;
860 35990 : sstate->tab_collations = NULL;
861 35990 : sstate->lhs_hash_funcs = NULL;
862 35990 : sstate->cur_eq_funcs = NULL;
863 :
864 : /*
865 : * If this is an initplan, it has output parameters that the parent plan
866 : * will use, so mark those parameters as needing evaluation. We don't
867 : * actually run the subplan until we first need one of its outputs.
868 : *
869 : * A CTE subplan's output parameter is never to be evaluated in the normal
870 : * way, so skip this in that case.
871 : *
872 : * Note that we don't set parent->chgParam here: the parent plan hasn't
873 : * been run yet, so no need to force it to re-run.
874 : */
875 35990 : if (subplan->setParam != NIL && subplan->parParam == NIL &&
876 12402 : subplan->subLinkType != CTE_SUBLINK)
877 : {
878 : ListCell *lst;
879 :
880 20748 : foreach(lst, subplan->setParam)
881 : {
882 10398 : int paramid = lfirst_int(lst);
883 10398 : ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
884 :
885 10398 : prm->execPlan = sstate;
886 : }
887 : }
888 :
889 : /*
890 : * If we are going to hash the subquery output, initialize relevant stuff.
891 : * (We don't create the hashtable until needed, though.)
892 : */
893 35990 : if (subplan->useHashTable)
894 : {
895 : int ncols,
896 : i;
897 : TupleDesc tupDescLeft;
898 : TupleDesc tupDescRight;
899 : Oid *cross_eq_funcoids;
900 : TupleTableSlot *slot;
901 : List *oplist,
902 : *lefttlist,
903 : *righttlist;
904 : ListCell *l;
905 :
906 : /* We need a memory context to hold the hash table(s) */
907 1038 : sstate->hashtablecxt =
908 1038 : AllocSetContextCreate(CurrentMemoryContext,
909 : "Subplan HashTable Context",
910 : ALLOCSET_DEFAULT_SIZES);
911 : /* and a small one for the hash tables to use as temp storage */
912 1038 : sstate->hashtempcxt =
913 1038 : AllocSetContextCreate(CurrentMemoryContext,
914 : "Subplan HashTable Temp Context",
915 : ALLOCSET_SMALL_SIZES);
916 : /* and a short-lived exprcontext for function evaluation */
917 1038 : sstate->innerecontext = CreateExprContext(estate);
918 :
919 : /*
920 : * We use ExecProject to evaluate the lefthand and righthand
921 : * expression lists and form tuples. (You might think that we could
922 : * use the sub-select's output tuples directly, but that is not the
923 : * case if we had to insert any run-time coercions of the sub-select's
924 : * output datatypes; anyway this avoids storing any resjunk columns
925 : * that might be in the sub-select's output.) Run through the
926 : * combining expressions to build tlists for the lefthand and
927 : * righthand sides.
928 : *
929 : * We also extract the combining operators themselves to initialize
930 : * the equality and hashing functions for the hash tables.
931 : */
932 1038 : if (IsA(subplan->testexpr, OpExpr))
933 : {
934 : /* single combining operator */
935 844 : oplist = list_make1(subplan->testexpr);
936 : }
937 194 : else if (is_andclause(subplan->testexpr))
938 : {
939 : /* multiple combining operators */
940 194 : oplist = castNode(BoolExpr, subplan->testexpr)->args;
941 : }
942 : else
943 : {
944 : /* shouldn't see anything else in a hashable subplan */
945 0 : elog(ERROR, "unrecognized testexpr type: %d",
946 : (int) nodeTag(subplan->testexpr));
947 : oplist = NIL; /* keep compiler quiet */
948 : }
949 1038 : ncols = list_length(oplist);
950 :
951 1038 : lefttlist = righttlist = NIL;
952 1038 : sstate->numCols = ncols;
953 1038 : sstate->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber));
954 1038 : sstate->tab_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
955 1038 : sstate->tab_collations = (Oid *) palloc(ncols * sizeof(Oid));
956 1038 : sstate->tab_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
957 1038 : sstate->tab_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
958 1038 : sstate->lhs_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
959 1038 : sstate->cur_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
960 : /* we'll need the cross-type equality fns below, but not in sstate */
961 1038 : cross_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
962 :
963 1038 : i = 1;
964 2270 : foreach(l, oplist)
965 : {
966 1232 : OpExpr *opexpr = lfirst_node(OpExpr, l);
967 : Expr *expr;
968 : TargetEntry *tle;
969 : Oid rhs_eq_oper;
970 : Oid left_hashfn;
971 : Oid right_hashfn;
972 :
973 : Assert(list_length(opexpr->args) == 2);
974 :
975 : /* Process lefthand argument */
976 1232 : expr = (Expr *) linitial(opexpr->args);
977 1232 : tle = makeTargetEntry(expr,
978 : i,
979 : NULL,
980 : false);
981 1232 : lefttlist = lappend(lefttlist, tle);
982 :
983 : /* Process righthand argument */
984 1232 : expr = (Expr *) lsecond(opexpr->args);
985 1232 : tle = makeTargetEntry(expr,
986 : i,
987 : NULL,
988 : false);
989 1232 : righttlist = lappend(righttlist, tle);
990 :
991 : /* Lookup the equality function (potentially cross-type) */
992 1232 : cross_eq_funcoids[i - 1] = opexpr->opfuncid;
993 1232 : fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
994 1232 : fmgr_info_set_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
995 :
996 : /* Look up the equality function for the RHS type */
997 1232 : if (!get_compatible_hash_operators(opexpr->opno,
998 : NULL, &rhs_eq_oper))
999 0 : elog(ERROR, "could not find compatible hash operator for operator %u",
1000 : opexpr->opno);
1001 1232 : sstate->tab_eq_funcoids[i - 1] = get_opcode(rhs_eq_oper);
1002 1232 : fmgr_info(sstate->tab_eq_funcoids[i - 1],
1003 1232 : &sstate->tab_eq_funcs[i - 1]);
1004 :
1005 : /* Lookup the associated hash functions */
1006 1232 : if (!get_op_hash_functions(opexpr->opno,
1007 : &left_hashfn, &right_hashfn))
1008 0 : elog(ERROR, "could not find hash function for hash operator %u",
1009 : opexpr->opno);
1010 1232 : fmgr_info(left_hashfn, &sstate->lhs_hash_funcs[i - 1]);
1011 1232 : fmgr_info(right_hashfn, &sstate->tab_hash_funcs[i - 1]);
1012 :
1013 : /* Set collation */
1014 1232 : sstate->tab_collations[i - 1] = opexpr->inputcollid;
1015 :
1016 : /* keyColIdx is just column numbers 1..n */
1017 1232 : sstate->keyColIdx[i - 1] = i;
1018 :
1019 1232 : i++;
1020 : }
1021 :
1022 : /*
1023 : * Construct tupdescs, slots and projection nodes for left and right
1024 : * sides. The lefthand expressions will be evaluated in the parent
1025 : * plan node's exprcontext, which we don't have access to here.
1026 : * Fortunately we can just pass NULL for now and fill it in later
1027 : * (hack alert!). The righthand expressions will be evaluated in our
1028 : * own innerecontext.
1029 : */
1030 1038 : tupDescLeft = ExecTypeFromTL(lefttlist);
1031 1038 : slot = ExecInitExtraTupleSlot(estate, tupDescLeft, &TTSOpsVirtual);
1032 1038 : sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
1033 : NULL,
1034 : slot,
1035 : parent,
1036 : NULL);
1037 :
1038 1038 : sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist);
1039 1038 : slot = ExecInitExtraTupleSlot(estate, tupDescRight, &TTSOpsVirtual);
1040 2076 : sstate->projRight = ExecBuildProjectionInfo(righttlist,
1041 : sstate->innerecontext,
1042 : slot,
1043 1038 : sstate->planstate,
1044 : NULL);
1045 :
1046 : /*
1047 : * Create comparator for lookups of rows in the table (potentially
1048 : * cross-type comparisons).
1049 : */
1050 1038 : sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
1051 : &TTSOpsVirtual, &TTSOpsMinimalTuple,
1052 : ncols,
1053 1038 : sstate->keyColIdx,
1054 : cross_eq_funcoids,
1055 1038 : sstate->tab_collations,
1056 : parent);
1057 : }
1058 :
1059 35990 : return sstate;
1060 : }
1061 :
1062 : /* ----------------------------------------------------------------
1063 : * ExecSetParamPlan
1064 : *
1065 : * Executes a subplan and sets its output parameters.
1066 : *
1067 : * This is called from ExecEvalParamExec() when the value of a PARAM_EXEC
1068 : * parameter is requested and the param's execPlan field is set (indicating
1069 : * that the param has not yet been evaluated). This allows lazy evaluation
1070 : * of initplans: we don't run the subplan until/unless we need its output.
1071 : * Note that this routine MUST clear the execPlan fields of the plan's
1072 : * output parameters after evaluating them!
1073 : *
1074 : * The results of this function are stored in the EState associated with the
1075 : * ExprContext (particularly, its ecxt_param_exec_vals); any pass-by-ref
1076 : * result Datums are allocated in the EState's per-query memory. The passed
1077 : * econtext can be any ExprContext belonging to that EState; which one is
1078 : * important only to the extent that the ExprContext's per-tuple memory
1079 : * context is used to evaluate any parameters passed down to the subplan.
1080 : * (Thus in principle, the shorter-lived the ExprContext the better, since
1081 : * that data isn't needed after we return. In practice, because initplan
1082 : * parameters are never more complex than Vars, Aggrefs, etc, evaluating them
1083 : * currently never leaks any memory anyway.)
1084 : * ----------------------------------------------------------------
1085 : */
1086 : void
1087 8434 : ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
1088 : {
1089 8434 : SubPlan *subplan = node->subplan;
1090 8434 : PlanState *planstate = node->planstate;
1091 8434 : SubLinkType subLinkType = subplan->subLinkType;
1092 8434 : EState *estate = planstate->state;
1093 8434 : ScanDirection dir = estate->es_direction;
1094 : MemoryContext oldcontext;
1095 : TupleTableSlot *slot;
1096 : ListCell *l;
1097 8434 : bool found = false;
1098 8434 : ArrayBuildStateAny *astate = NULL;
1099 :
1100 8434 : if (subLinkType == ANY_SUBLINK ||
1101 : subLinkType == ALL_SUBLINK)
1102 0 : elog(ERROR, "ANY/ALL subselect unsupported as initplan");
1103 8434 : if (subLinkType == CTE_SUBLINK)
1104 0 : elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
1105 8434 : if (subplan->parParam || subplan->args)
1106 0 : elog(ERROR, "correlated subplans should not be executed via ExecSetParamPlan");
1107 :
1108 : /*
1109 : * Enforce forward scan direction regardless of caller. It's hard but not
1110 : * impossible to get here in backward scan, so make it work anyway.
1111 : */
1112 8434 : estate->es_direction = ForwardScanDirection;
1113 :
1114 : /* Initialize ArrayBuildStateAny in caller's context, if needed */
1115 8434 : if (subLinkType == ARRAY_SUBLINK)
1116 80 : astate = initArrayResultAny(subplan->firstColType,
1117 : CurrentMemoryContext, true);
1118 :
1119 : /*
1120 : * Must switch to per-query memory context.
1121 : */
1122 8434 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
1123 :
1124 : /*
1125 : * Run the plan. (If it needs to be rescanned, the first ExecProcNode
1126 : * call will take care of that.)
1127 : */
1128 28138 : for (slot = ExecProcNode(planstate);
1129 25740 : !TupIsNull(slot);
1130 19704 : slot = ExecProcNode(planstate))
1131 : {
1132 19812 : TupleDesc tdesc = slot->tts_tupleDescriptor;
1133 19812 : int i = 1;
1134 :
1135 19812 : if (subLinkType == EXISTS_SUBLINK)
1136 : {
1137 : /* There can be only one setParam... */
1138 90 : int paramid = linitial_int(subplan->setParam);
1139 90 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1140 :
1141 90 : prm->execPlan = NULL;
1142 90 : prm->value = BoolGetDatum(true);
1143 90 : prm->isnull = false;
1144 90 : found = true;
1145 90 : break;
1146 : }
1147 :
1148 19722 : if (subLinkType == ARRAY_SUBLINK)
1149 : {
1150 : Datum dvalue;
1151 : bool disnull;
1152 :
1153 12142 : found = true;
1154 : /* stash away current value */
1155 : Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
1156 12142 : dvalue = slot_getattr(slot, 1, &disnull);
1157 12142 : astate = accumArrayResultAny(astate, dvalue, disnull,
1158 : subplan->firstColType, oldcontext);
1159 : /* keep scanning subplan to collect all values */
1160 12142 : continue;
1161 : }
1162 :
1163 7580 : if (found &&
1164 12 : (subLinkType == EXPR_SUBLINK ||
1165 6 : subLinkType == MULTIEXPR_SUBLINK ||
1166 : subLinkType == ROWCOMPARE_SUBLINK))
1167 18 : ereport(ERROR,
1168 : (errcode(ERRCODE_CARDINALITY_VIOLATION),
1169 : errmsg("more than one row returned by a subquery used as an expression")));
1170 :
1171 7562 : found = true;
1172 :
1173 : /*
1174 : * We need to copy the subplan's tuple into our own context, in case
1175 : * any of the params are pass-by-ref type --- the pointers stored in
1176 : * the param structs will point at this copied tuple! node->curTuple
1177 : * keeps track of the copied tuple for eventual freeing.
1178 : */
1179 7562 : if (node->curTuple)
1180 394 : heap_freetuple(node->curTuple);
1181 7562 : node->curTuple = ExecCopySlotHeapTuple(slot);
1182 :
1183 : /*
1184 : * Now set all the setParam params from the columns of the tuple
1185 : */
1186 15160 : foreach(l, subplan->setParam)
1187 : {
1188 7598 : int paramid = lfirst_int(l);
1189 7598 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1190 :
1191 7598 : prm->execPlan = NULL;
1192 7598 : prm->value = heap_getattr(node->curTuple, i, tdesc,
1193 : &(prm->isnull));
1194 7598 : i++;
1195 : }
1196 : }
1197 :
1198 8416 : if (subLinkType == ARRAY_SUBLINK)
1199 : {
1200 : /* There can be only one setParam... */
1201 80 : int paramid = linitial_int(subplan->setParam);
1202 80 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1203 :
1204 : /*
1205 : * We build the result array in query context so it won't disappear;
1206 : * to avoid leaking memory across repeated calls, we have to remember
1207 : * the latest value, much as for curTuple above.
1208 : */
1209 80 : if (node->curArray != PointerGetDatum(NULL))
1210 0 : pfree(DatumGetPointer(node->curArray));
1211 80 : node->curArray = makeArrayResultAny(astate,
1212 : econtext->ecxt_per_query_memory,
1213 : true);
1214 80 : prm->execPlan = NULL;
1215 80 : prm->value = node->curArray;
1216 80 : prm->isnull = false;
1217 : }
1218 8336 : else if (!found)
1219 : {
1220 702 : if (subLinkType == EXISTS_SUBLINK)
1221 : {
1222 : /* There can be only one setParam... */
1223 652 : int paramid = linitial_int(subplan->setParam);
1224 652 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1225 :
1226 652 : prm->execPlan = NULL;
1227 652 : prm->value = BoolGetDatum(false);
1228 652 : prm->isnull = false;
1229 : }
1230 : else
1231 : {
1232 : /* For other sublink types, set all the output params to NULL */
1233 106 : foreach(l, subplan->setParam)
1234 : {
1235 56 : int paramid = lfirst_int(l);
1236 56 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1237 :
1238 56 : prm->execPlan = NULL;
1239 56 : prm->value = (Datum) 0;
1240 56 : prm->isnull = true;
1241 : }
1242 : }
1243 : }
1244 :
1245 8416 : MemoryContextSwitchTo(oldcontext);
1246 :
1247 : /* restore scan direction */
1248 8416 : estate->es_direction = dir;
1249 8416 : }
1250 :
1251 : /*
1252 : * ExecSetParamPlanMulti
1253 : *
1254 : * Apply ExecSetParamPlan to evaluate any not-yet-evaluated initplan output
1255 : * parameters whose ParamIDs are listed in "params". Any listed params that
1256 : * are not initplan outputs are ignored.
1257 : *
1258 : * As with ExecSetParamPlan, any ExprContext belonging to the current EState
1259 : * can be used, but in principle a shorter-lived ExprContext is better than a
1260 : * longer-lived one.
1261 : */
1262 : void
1263 1306 : ExecSetParamPlanMulti(const Bitmapset *params, ExprContext *econtext)
1264 : {
1265 : int paramid;
1266 :
1267 1306 : paramid = -1;
1268 1722 : while ((paramid = bms_next_member(params, paramid)) >= 0)
1269 : {
1270 416 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1271 :
1272 416 : if (prm->execPlan != NULL)
1273 : {
1274 : /* Parameter not evaluated yet, so go do it */
1275 34 : ExecSetParamPlan(prm->execPlan, econtext);
1276 : /* ExecSetParamPlan should have processed this param... */
1277 : Assert(prm->execPlan == NULL);
1278 : }
1279 : }
1280 1306 : }
1281 :
1282 : /*
1283 : * Mark an initplan as needing recalculation
1284 : */
1285 : void
1286 962 : ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
1287 : {
1288 962 : PlanState *planstate = node->planstate;
1289 962 : SubPlan *subplan = node->subplan;
1290 962 : EState *estate = parent->state;
1291 : ListCell *l;
1292 :
1293 : /* sanity checks */
1294 962 : if (subplan->parParam != NIL)
1295 0 : elog(ERROR, "direct correlated subquery unsupported as initplan");
1296 962 : if (subplan->setParam == NIL)
1297 0 : elog(ERROR, "setParam list of initplan is empty");
1298 962 : if (bms_is_empty(planstate->plan->extParam))
1299 0 : elog(ERROR, "extParam set of initplan is empty");
1300 :
1301 : /*
1302 : * Don't actually re-scan: it'll happen inside ExecSetParamPlan if needed.
1303 : */
1304 :
1305 : /*
1306 : * Mark this subplan's output parameters as needing recalculation.
1307 : *
1308 : * CTE subplans are never executed via parameter recalculation; instead
1309 : * they get run when called by nodeCtescan.c. So don't mark the output
1310 : * parameter of a CTE subplan as dirty, but do set the chgParam bit for it
1311 : * so that dependent plan nodes will get told to rescan.
1312 : */
1313 1924 : foreach(l, subplan->setParam)
1314 : {
1315 962 : int paramid = lfirst_int(l);
1316 962 : ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
1317 :
1318 962 : if (subplan->subLinkType != CTE_SUBLINK)
1319 666 : prm->execPlan = node;
1320 :
1321 962 : parent->chgParam = bms_add_member(parent->chgParam, paramid);
1322 : }
1323 962 : }
|