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-2017, 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 <limits.h>
30 : #include <math.h>
31 :
32 : #include "access/htup_details.h"
33 : #include "executor/executor.h"
34 : #include "executor/nodeSubplan.h"
35 : #include "nodes/makefuncs.h"
36 : #include "miscadmin.h"
37 : #include "optimizer/clauses.h"
38 : #include "utils/array.h"
39 : #include "utils/lsyscache.h"
40 : #include "utils/memutils.h"
41 :
42 :
43 : static Datum ExecHashSubPlan(SubPlanState *node,
44 : ExprContext *econtext,
45 : bool *isNull);
46 : static Datum ExecScanSubPlan(SubPlanState *node,
47 : ExprContext *econtext,
48 : bool *isNull);
49 : static void buildSubPlanHash(SubPlanState *node, ExprContext *econtext);
50 : static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
51 : FmgrInfo *eqfunctions);
52 : static bool slotAllNulls(TupleTableSlot *slot);
53 : static bool slotNoNulls(TupleTableSlot *slot);
54 :
55 :
56 : /* ----------------------------------------------------------------
57 : * ExecSubPlan
58 : *
59 : * This is the main entry point for execution of a regular SubPlan.
60 : * ----------------------------------------------------------------
61 : */
62 : Datum
63 82843 : ExecSubPlan(SubPlanState *node,
64 : ExprContext *econtext,
65 : bool *isNull)
66 : {
67 82843 : SubPlan *subplan = node->subplan;
68 :
69 82843 : CHECK_FOR_INTERRUPTS();
70 :
71 : /* Set non-null as default */
72 82843 : *isNull = false;
73 :
74 : /* Sanity checks */
75 82843 : if (subplan->subLinkType == CTE_SUBLINK)
76 0 : elog(ERROR, "CTE subplans should not be executed via ExecSubPlan");
77 82843 : if (subplan->setParam != NIL && subplan->subLinkType != MULTIEXPR_SUBLINK)
78 0 : elog(ERROR, "cannot set parent params from subquery");
79 :
80 : /* Select appropriate evaluation strategy */
81 82843 : if (subplan->useHashTable)
82 60099 : return ExecHashSubPlan(node, econtext, isNull);
83 : else
84 22744 : return ExecScanSubPlan(node, econtext, isNull);
85 : }
86 :
87 : /*
88 : * ExecHashSubPlan: store subselect result in an in-memory hash table
89 : */
90 : static Datum
91 60099 : ExecHashSubPlan(SubPlanState *node,
92 : ExprContext *econtext,
93 : bool *isNull)
94 : {
95 60099 : SubPlan *subplan = node->subplan;
96 60099 : PlanState *planstate = node->planstate;
97 : TupleTableSlot *slot;
98 :
99 : /* Shouldn't have any direct correlation Vars */
100 60099 : if (subplan->parParam != NIL || node->args != NIL)
101 0 : elog(ERROR, "hashed subplan with direct correlation not supported");
102 :
103 : /*
104 : * If first time through or we need to rescan the subplan, build the hash
105 : * table.
106 : */
107 60099 : if (node->hashtable == NULL || planstate->chgParam != NULL)
108 25 : buildSubPlanHash(node, econtext);
109 :
110 : /*
111 : * The result for an empty subplan is always FALSE; no need to evaluate
112 : * lefthand side.
113 : */
114 60099 : *isNull = false;
115 60099 : if (!node->havehashrows && !node->havenullrows)
116 0 : return BoolGetDatum(false);
117 :
118 : /*
119 : * Evaluate lefthand expressions and form a projection tuple. First we
120 : * have to set the econtext to use (hack alert!).
121 : */
122 60099 : node->projLeft->pi_exprContext = econtext;
123 60099 : slot = ExecProject(node->projLeft);
124 :
125 : /*
126 : * Note: because we are typically called in a per-tuple context, we have
127 : * to explicitly clear the projected tuple before returning. Otherwise,
128 : * we'll have a double-free situation: the per-tuple context will probably
129 : * be reset before we're called again, and then the tuple slot will think
130 : * it still needs to free the tuple.
131 : */
132 :
133 : /*
134 : * If the LHS is all non-null, probe for an exact match in the main hash
135 : * table. If we find one, the result is TRUE. Otherwise, scan the
136 : * partly-null table to see if there are any rows that aren't provably
137 : * unequal to the LHS; if so, the result is UNKNOWN. (We skip that part
138 : * if we don't care about UNKNOWN.) Otherwise, the result is FALSE.
139 : *
140 : * Note: the reason we can avoid a full scan of the main hash table is
141 : * that the combining operators are assumed never to yield NULL when both
142 : * inputs are non-null. If they were to do so, we might need to produce
143 : * UNKNOWN instead of FALSE because of an UNKNOWN result in comparing the
144 : * LHS to some main-table entry --- which is a comparison we will not even
145 : * make, unless there's a chance match of hash keys.
146 : */
147 60099 : if (slotNoNulls(slot))
148 : {
149 120192 : if (node->havehashrows &&
150 60095 : FindTupleHashEntry(node->hashtable,
151 : slot,
152 : node->cur_eq_funcs,
153 : node->lhs_hash_funcs) != NULL)
154 : {
155 130 : ExecClearTuple(slot);
156 130 : return BoolGetDatum(true);
157 : }
158 59969 : if (node->havenullrows &&
159 2 : findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
160 : {
161 1 : ExecClearTuple(slot);
162 1 : *isNull = true;
163 1 : return BoolGetDatum(false);
164 : }
165 59966 : ExecClearTuple(slot);
166 59966 : return BoolGetDatum(false);
167 : }
168 :
169 : /*
170 : * When the LHS is partly or wholly NULL, we can never return TRUE. If we
171 : * don't care about UNKNOWN, just return FALSE. Otherwise, if the LHS is
172 : * wholly NULL, immediately return UNKNOWN. (Since the combining
173 : * operators are strict, the result could only be FALSE if the sub-select
174 : * were empty, but we already handled that case.) Otherwise, we must scan
175 : * both the main and partly-null tables to see if there are any rows that
176 : * aren't provably unequal to the LHS; if so, the result is UNKNOWN.
177 : * Otherwise, the result is FALSE.
178 : */
179 2 : if (node->hashnulls == NULL)
180 : {
181 0 : ExecClearTuple(slot);
182 0 : return BoolGetDatum(false);
183 : }
184 2 : if (slotAllNulls(slot))
185 : {
186 0 : ExecClearTuple(slot);
187 0 : *isNull = true;
188 0 : return BoolGetDatum(false);
189 : }
190 : /* Scan partly-null table first, since more likely to get a match */
191 4 : if (node->havenullrows &&
192 2 : findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
193 : {
194 1 : ExecClearTuple(slot);
195 1 : *isNull = true;
196 1 : return BoolGetDatum(false);
197 : }
198 1 : if (node->havehashrows &&
199 0 : findPartialMatch(node->hashtable, slot, node->cur_eq_funcs))
200 : {
201 0 : ExecClearTuple(slot);
202 0 : *isNull = true;
203 0 : return BoolGetDatum(false);
204 : }
205 1 : ExecClearTuple(slot);
206 1 : return BoolGetDatum(false);
207 : }
208 :
209 : /*
210 : * ExecScanSubPlan: default case where we have to rescan subplan each time
211 : */
212 : static Datum
213 22744 : ExecScanSubPlan(SubPlanState *node,
214 : ExprContext *econtext,
215 : bool *isNull)
216 : {
217 22744 : SubPlan *subplan = node->subplan;
218 22744 : PlanState *planstate = node->planstate;
219 22744 : SubLinkType subLinkType = subplan->subLinkType;
220 : MemoryContext oldcontext;
221 : TupleTableSlot *slot;
222 : Datum result;
223 22744 : bool found = false; /* TRUE if got at least one subplan tuple */
224 : ListCell *pvar;
225 : ListCell *l;
226 22744 : ArrayBuildStateAny *astate = NULL;
227 :
228 : /*
229 : * MULTIEXPR subplans, when "executed", just return NULL; but first we
230 : * mark the subplan's output parameters as needing recalculation. (This
231 : * is a bit of a hack: it relies on the subplan appearing later in its
232 : * targetlist than any of the referencing Params, so that all the Params
233 : * have been evaluated before we re-mark them for the next evaluation
234 : * cycle. But in general resjunk tlist items appear after non-resjunk
235 : * ones, so this should be safe.) Unlike ExecReScanSetParamPlan, we do
236 : * *not* set bits in the parent plan node's chgParam, because we don't
237 : * want to cause a rescan of the parent.
238 : */
239 22744 : if (subLinkType == MULTIEXPR_SUBLINK)
240 : {
241 8 : EState *estate = node->parent->state;
242 :
243 24 : foreach(l, subplan->setParam)
244 : {
245 16 : int paramid = lfirst_int(l);
246 16 : ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
247 :
248 16 : prm->execPlan = node;
249 : }
250 8 : *isNull = true;
251 8 : return (Datum) 0;
252 : }
253 :
254 : /* Initialize ArrayBuildStateAny in caller's context, if needed */
255 22736 : if (subLinkType == ARRAY_SUBLINK)
256 499 : astate = initArrayResultAny(subplan->firstColType,
257 : CurrentMemoryContext, true);
258 :
259 : /*
260 : * We are probably in a short-lived expression-evaluation context. Switch
261 : * to the per-query context for manipulating the child plan's chgParam,
262 : * calling ExecProcNode on it, etc.
263 : */
264 22736 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
265 :
266 : /*
267 : * Set Params of this plan from parent plan correlation values. (Any
268 : * calculation we have to do is done in the parent econtext, since the
269 : * Param values don't need to have per-query lifetime.)
270 : */
271 22736 : Assert(list_length(subplan->parParam) == list_length(node->args));
272 :
273 47569 : forboth(l, subplan->parParam, pvar, node->args)
274 : {
275 24833 : int paramid = lfirst_int(l);
276 24833 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
277 :
278 24833 : prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
279 : econtext,
280 : &(prm->isnull));
281 24833 : planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
282 : }
283 :
284 : /*
285 : * Now that we've set up its parameters, we can reset the subplan.
286 : */
287 22736 : ExecReScan(planstate);
288 :
289 : /*
290 : * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result
291 : * is boolean as are the results of the combining operators. We combine
292 : * results across tuples (if the subplan produces more than one) using OR
293 : * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
294 : * (ROWCOMPARE_SUBLINK doesn't allow multiple tuples from the subplan.)
295 : * NULL results from the combining operators are handled according to the
296 : * usual SQL semantics for OR and AND. The result for no input tuples is
297 : * FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
298 : * ROWCOMPARE_SUBLINK.
299 : *
300 : * For EXPR_SUBLINK we require the subplan to produce no more than one
301 : * tuple, else an error is raised. If zero tuples are produced, we return
302 : * NULL. Assuming we get a tuple, we just use its first column (there can
303 : * be only one non-junk column in this case).
304 : *
305 : * For ARRAY_SUBLINK we allow the subplan to produce any number of tuples,
306 : * and form an array of the first column's values. Note in particular
307 : * that we produce a zero-element array if no tuples are produced (this is
308 : * a change from pre-8.3 behavior of returning NULL).
309 : */
310 22736 : result = BoolGetDatum(subLinkType == ALL_SUBLINK);
311 22736 : *isNull = false;
312 :
313 66842 : for (slot = ExecProcNode(planstate);
314 41996 : !TupIsNull(slot);
315 21370 : slot = ExecProcNode(planstate))
316 : {
317 21489 : TupleDesc tdesc = slot->tts_tupleDescriptor;
318 : Datum rowresult;
319 : bool rownull;
320 : int col;
321 : ListCell *plst;
322 :
323 21489 : if (subLinkType == EXISTS_SUBLINK)
324 : {
325 74 : found = true;
326 74 : result = BoolGetDatum(true);
327 193 : break;
328 : }
329 :
330 21415 : if (subLinkType == EXPR_SUBLINK)
331 : {
332 : /* cannot allow multiple input tuples for EXPR sublink */
333 20744 : if (found)
334 0 : ereport(ERROR,
335 : (errcode(ERRCODE_CARDINALITY_VIOLATION),
336 : errmsg("more than one row returned by a subquery used as an expression")));
337 20744 : found = true;
338 :
339 : /*
340 : * We need to copy the subplan's tuple in case the result is of
341 : * pass-by-ref type --- our return value will point into this
342 : * copied tuple! Can't use the subplan's instance of the tuple
343 : * since it won't still be valid after next ExecProcNode() call.
344 : * node->curTuple keeps track of the copied tuple for eventual
345 : * freeing.
346 : */
347 20744 : if (node->curTuple)
348 20666 : heap_freetuple(node->curTuple);
349 20744 : node->curTuple = ExecCopySlotTuple(slot);
350 :
351 20744 : result = heap_getattr(node->curTuple, 1, tdesc, isNull);
352 : /* keep scanning subplan to make sure there's only one tuple */
353 42037 : continue;
354 : }
355 :
356 671 : if (subLinkType == ARRAY_SUBLINK)
357 : {
358 : Datum dvalue;
359 : bool disnull;
360 :
361 549 : found = true;
362 : /* stash away current value */
363 549 : Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
364 549 : dvalue = slot_getattr(slot, 1, &disnull);
365 549 : astate = accumArrayResultAny(astate, dvalue, disnull,
366 : subplan->firstColType, oldcontext);
367 : /* keep scanning subplan to collect all values */
368 549 : continue;
369 : }
370 :
371 : /* cannot allow multiple input tuples for ROWCOMPARE sublink either */
372 122 : if (subLinkType == ROWCOMPARE_SUBLINK && found)
373 0 : ereport(ERROR,
374 : (errcode(ERRCODE_CARDINALITY_VIOLATION),
375 : errmsg("more than one row returned by a subquery used as an expression")));
376 :
377 122 : found = true;
378 :
379 : /*
380 : * For ALL, ANY, and ROWCOMPARE sublinks, load up the Params
381 : * representing the columns of the sub-select, and then evaluate the
382 : * combining expression.
383 : */
384 122 : col = 1;
385 244 : foreach(plst, subplan->paramIds)
386 : {
387 122 : int paramid = lfirst_int(plst);
388 : ParamExecData *prmdata;
389 :
390 122 : prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
391 122 : Assert(prmdata->execPlan == NULL);
392 122 : prmdata->value = slot_getattr(slot, col, &(prmdata->isnull));
393 122 : col++;
394 : }
395 :
396 122 : rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext,
397 : &rownull);
398 :
399 122 : if (subLinkType == ANY_SUBLINK)
400 : {
401 : /* combine across rows per OR semantics */
402 121 : if (rownull)
403 3 : *isNull = true;
404 118 : else if (DatumGetBool(rowresult))
405 : {
406 45 : result = BoolGetDatum(true);
407 45 : *isNull = false;
408 45 : break; /* needn't look at any more rows */
409 : }
410 : }
411 1 : else if (subLinkType == ALL_SUBLINK)
412 : {
413 : /* combine across rows per AND semantics */
414 1 : if (rownull)
415 0 : *isNull = true;
416 1 : else if (!DatumGetBool(rowresult))
417 : {
418 0 : result = BoolGetDatum(false);
419 0 : *isNull = false;
420 0 : break; /* needn't look at any more rows */
421 : }
422 : }
423 : else
424 : {
425 : /* must be ROWCOMPARE_SUBLINK */
426 0 : result = rowresult;
427 0 : *isNull = rownull;
428 : }
429 : }
430 :
431 22736 : MemoryContextSwitchTo(oldcontext);
432 :
433 22736 : if (subLinkType == ARRAY_SUBLINK)
434 : {
435 : /* We return the result in the caller's context */
436 499 : result = makeArrayResultAny(astate, oldcontext, true);
437 : }
438 22237 : else if (!found)
439 : {
440 : /*
441 : * deal with empty subplan result. result/isNull were previously
442 : * initialized correctly for all sublink types except EXPR and
443 : * ROWCOMPARE; for those, return NULL.
444 : */
445 1345 : if (subLinkType == EXPR_SUBLINK ||
446 : subLinkType == ROWCOMPARE_SUBLINK)
447 : {
448 1250 : result = (Datum) 0;
449 1250 : *isNull = true;
450 : }
451 : }
452 :
453 22736 : return result;
454 : }
455 :
456 : /*
457 : * buildSubPlanHash: load hash table by scanning subplan output.
458 : */
459 : static void
460 25 : buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
461 : {
462 25 : SubPlan *subplan = node->subplan;
463 25 : PlanState *planstate = node->planstate;
464 25 : int ncols = list_length(subplan->paramIds);
465 25 : ExprContext *innerecontext = node->innerecontext;
466 : MemoryContext oldcontext;
467 : long nbuckets;
468 : TupleTableSlot *slot;
469 :
470 25 : Assert(subplan->subLinkType == ANY_SUBLINK);
471 :
472 : /*
473 : * If we already had any hash tables, destroy 'em; then create empty hash
474 : * table(s).
475 : *
476 : * If we need to distinguish accurately between FALSE and UNKNOWN (i.e.,
477 : * NULL) results of the IN operation, then we have to store subplan output
478 : * rows that are partly or wholly NULL. We store such rows in a separate
479 : * hash table that we expect will be much smaller than the main table. (We
480 : * can use hashing to eliminate partly-null rows that are not distinct. We
481 : * keep them separate to minimize the cost of the inevitable full-table
482 : * searches; see findPartialMatch.)
483 : *
484 : * If it's not necessary to distinguish FALSE and UNKNOWN, then we don't
485 : * need to store subplan output rows that contain NULL.
486 : */
487 25 : MemoryContextReset(node->hashtablecxt);
488 25 : node->hashtable = NULL;
489 25 : node->hashnulls = NULL;
490 25 : node->havehashrows = false;
491 25 : node->havenullrows = false;
492 :
493 25 : nbuckets = (long) Min(planstate->plan->plan_rows, (double) LONG_MAX);
494 25 : if (nbuckets < 1)
495 0 : nbuckets = 1;
496 :
497 25 : node->hashtable = BuildTupleHashTable(ncols,
498 : node->keyColIdx,
499 : node->tab_eq_funcs,
500 : node->tab_hash_funcs,
501 : nbuckets,
502 : 0,
503 : node->hashtablecxt,
504 : node->hashtempcxt,
505 : false);
506 :
507 25 : if (!subplan->unknownEqFalse)
508 : {
509 12 : if (ncols == 1)
510 9 : nbuckets = 1; /* there can only be one entry */
511 : else
512 : {
513 3 : nbuckets /= 16;
514 3 : if (nbuckets < 1)
515 0 : nbuckets = 1;
516 : }
517 12 : node->hashnulls = BuildTupleHashTable(ncols,
518 : node->keyColIdx,
519 : node->tab_eq_funcs,
520 : node->tab_hash_funcs,
521 : nbuckets,
522 : 0,
523 : node->hashtablecxt,
524 : node->hashtempcxt,
525 : false);
526 : }
527 :
528 : /*
529 : * We are probably in a short-lived expression-evaluation context. Switch
530 : * to the per-query context for manipulating the child plan.
531 : */
532 25 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
533 :
534 : /*
535 : * Reset subplan to start.
536 : */
537 25 : ExecReScan(planstate);
538 :
539 : /*
540 : * Scan the subplan and load the hash table(s). Note that when there are
541 : * duplicate rows coming out of the sub-select, only one copy is stored.
542 : */
543 19354 : for (slot = ExecProcNode(planstate);
544 19324 : !TupIsNull(slot);
545 19304 : slot = ExecProcNode(planstate))
546 : {
547 19304 : int col = 1;
548 : ListCell *plst;
549 : bool isnew;
550 :
551 : /*
552 : * Load up the Params representing the raw sub-select outputs, then
553 : * form the projection tuple to store in the hashtable.
554 : */
555 47606 : foreach(plst, subplan->paramIds)
556 : {
557 28302 : int paramid = lfirst_int(plst);
558 : ParamExecData *prmdata;
559 :
560 28302 : prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
561 28302 : Assert(prmdata->execPlan == NULL);
562 28302 : prmdata->value = slot_getattr(slot, col,
563 : &(prmdata->isnull));
564 28302 : col++;
565 : }
566 19304 : slot = ExecProject(node->projRight);
567 :
568 : /*
569 : * If result contains any nulls, store separately or not at all.
570 : */
571 19304 : if (slotNoNulls(slot))
572 : {
573 19302 : (void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
574 19302 : node->havehashrows = true;
575 : }
576 2 : else if (node->hashnulls)
577 : {
578 2 : (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
579 2 : node->havenullrows = true;
580 : }
581 :
582 : /*
583 : * Reset innerecontext after each inner tuple to free any memory used
584 : * during ExecProject.
585 : */
586 19304 : ResetExprContext(innerecontext);
587 : }
588 :
589 : /*
590 : * Since the projected tuples are in the sub-query's context and not the
591 : * main context, we'd better clear the tuple slot before there's any
592 : * chance of a reset of the sub-query's context. Else we will have the
593 : * potential for a double free attempt. (XXX possibly no longer needed,
594 : * but can't hurt.)
595 : */
596 25 : ExecClearTuple(node->projRight->pi_state.resultslot);
597 :
598 25 : MemoryContextSwitchTo(oldcontext);
599 25 : }
600 :
601 : /*
602 : * findPartialMatch: does the hashtable contain an entry that is not
603 : * provably distinct from the tuple?
604 : *
605 : * We have to scan the whole hashtable; we can't usefully use hashkeys
606 : * to guide probing, since we might get partial matches on tuples with
607 : * hashkeys quite unrelated to what we'd get from the given tuple.
608 : *
609 : * Caller must provide the equality functions to use, since in cross-type
610 : * cases these are different from the hashtable's internal functions.
611 : */
612 : static bool
613 4 : findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
614 : FmgrInfo *eqfunctions)
615 : {
616 4 : int numCols = hashtable->numCols;
617 4 : AttrNumber *keyColIdx = hashtable->keyColIdx;
618 : TupleHashIterator hashiter;
619 : TupleHashEntry entry;
620 :
621 4 : InitTupleHashIterator(hashtable, &hashiter);
622 4 : while ((entry = ScanTupleHashTable(hashtable, &hashiter)) != NULL)
623 : {
624 4 : CHECK_FOR_INTERRUPTS();
625 :
626 4 : ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
627 4 : if (!execTuplesUnequal(slot, hashtable->tableslot,
628 : numCols, keyColIdx,
629 : eqfunctions,
630 : hashtable->tempcxt))
631 : {
632 : TermTupleHashIterator(&hashiter);
633 2 : return true;
634 : }
635 : }
636 : /* No TermTupleHashIterator call needed here */
637 2 : return false;
638 : }
639 :
640 : /*
641 : * slotAllNulls: is the slot completely NULL?
642 : *
643 : * This does not test for dropped columns, which is OK because we only
644 : * use it on projected tuples.
645 : */
646 : static bool
647 2 : slotAllNulls(TupleTableSlot *slot)
648 : {
649 2 : int ncols = slot->tts_tupleDescriptor->natts;
650 : int i;
651 :
652 2 : for (i = 1; i <= ncols; i++)
653 : {
654 2 : if (!slot_attisnull(slot, i))
655 2 : return false;
656 : }
657 0 : return true;
658 : }
659 :
660 : /*
661 : * slotNoNulls: is the slot entirely not NULL?
662 : *
663 : * This does not test for dropped columns, which is OK because we only
664 : * use it on projected tuples.
665 : */
666 : static bool
667 79403 : slotNoNulls(TupleTableSlot *slot)
668 : {
669 79403 : int ncols = slot->tts_tupleDescriptor->natts;
670 : int i;
671 :
672 177812 : for (i = 1; i <= ncols; i++)
673 : {
674 98413 : if (slot_attisnull(slot, i))
675 4 : return false;
676 : }
677 79399 : return true;
678 : }
679 :
680 : /* ----------------------------------------------------------------
681 : * ExecInitSubPlan
682 : *
683 : * Create a SubPlanState for a SubPlan; this is the SubPlan-specific part
684 : * of ExecInitExpr(). We split it out so that it can be used for InitPlans
685 : * as well as regular SubPlans. Note that we don't link the SubPlan into
686 : * the parent's subPlan list, because that shouldn't happen for InitPlans.
687 : * Instead, ExecInitExpr() does that one part.
688 : * ----------------------------------------------------------------
689 : */
690 : SubPlanState *
691 3274 : ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
692 : {
693 3274 : SubPlanState *sstate = makeNode(SubPlanState);
694 3274 : EState *estate = parent->state;
695 :
696 3274 : sstate->subplan = subplan;
697 :
698 : /* Link the SubPlanState to already-initialized subplan */
699 3274 : sstate->planstate = (PlanState *) list_nth(estate->es_subplanstates,
700 3274 : subplan->plan_id - 1);
701 :
702 : /* ... and to its parent's state */
703 3274 : sstate->parent = parent;
704 :
705 : /* Initialize subexpressions */
706 3274 : sstate->testexpr = ExecInitExpr((Expr *) subplan->testexpr, parent);
707 3274 : sstate->args = ExecInitExprList(subplan->args, parent);
708 :
709 : /*
710 : * initialize my state
711 : */
712 3274 : sstate->curTuple = NULL;
713 3274 : sstate->curArray = PointerGetDatum(NULL);
714 3274 : sstate->projLeft = NULL;
715 3274 : sstate->projRight = NULL;
716 3274 : sstate->hashtable = NULL;
717 3274 : sstate->hashnulls = NULL;
718 3274 : sstate->hashtablecxt = NULL;
719 3274 : sstate->hashtempcxt = NULL;
720 3274 : sstate->innerecontext = NULL;
721 3274 : sstate->keyColIdx = NULL;
722 3274 : sstate->tab_hash_funcs = NULL;
723 3274 : sstate->tab_eq_funcs = NULL;
724 3274 : sstate->lhs_hash_funcs = NULL;
725 3274 : sstate->cur_eq_funcs = NULL;
726 :
727 : /*
728 : * If this is an initplan or MULTIEXPR subplan, it has output parameters
729 : * that the parent plan will use, so mark those parameters as needing
730 : * evaluation. We don't actually run the subplan until we first need one
731 : * of its outputs.
732 : *
733 : * A CTE subplan's output parameter is never to be evaluated in the normal
734 : * way, so skip this in that case.
735 : *
736 : * Note that we don't set parent->chgParam here: the parent plan hasn't
737 : * been run yet, so no need to force it to re-run.
738 : */
739 3274 : if (subplan->setParam != NIL && subplan->subLinkType != CTE_SUBLINK)
740 : {
741 : ListCell *lst;
742 :
743 3477 : foreach(lst, subplan->setParam)
744 : {
745 1743 : int paramid = lfirst_int(lst);
746 1743 : ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
747 :
748 1743 : prm->execPlan = sstate;
749 : }
750 : }
751 :
752 : /*
753 : * If we are going to hash the subquery output, initialize relevant stuff.
754 : * (We don't create the hashtable until needed, though.)
755 : */
756 3274 : if (subplan->useHashTable)
757 : {
758 : int ncols,
759 : i;
760 : TupleDesc tupDesc;
761 : TupleTableSlot *slot;
762 : List *oplist,
763 : *lefttlist,
764 : *righttlist;
765 : ListCell *l;
766 :
767 : /* We need a memory context to hold the hash table(s) */
768 146 : sstate->hashtablecxt =
769 146 : AllocSetContextCreate(CurrentMemoryContext,
770 : "Subplan HashTable Context",
771 : ALLOCSET_DEFAULT_SIZES);
772 : /* and a small one for the hash tables to use as temp storage */
773 146 : sstate->hashtempcxt =
774 146 : AllocSetContextCreate(CurrentMemoryContext,
775 : "Subplan HashTable Temp Context",
776 : ALLOCSET_SMALL_SIZES);
777 : /* and a short-lived exprcontext for function evaluation */
778 146 : sstate->innerecontext = CreateExprContext(estate);
779 : /* Silly little array of column numbers 1..n */
780 146 : ncols = list_length(subplan->paramIds);
781 146 : sstate->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber));
782 330 : for (i = 0; i < ncols; i++)
783 184 : sstate->keyColIdx[i] = i + 1;
784 :
785 : /*
786 : * We use ExecProject to evaluate the lefthand and righthand
787 : * expression lists and form tuples. (You might think that we could
788 : * use the sub-select's output tuples directly, but that is not the
789 : * case if we had to insert any run-time coercions of the sub-select's
790 : * output datatypes; anyway this avoids storing any resjunk columns
791 : * that might be in the sub-select's output.) Run through the
792 : * combining expressions to build tlists for the lefthand and
793 : * righthand sides.
794 : *
795 : * We also extract the combining operators themselves to initialize
796 : * the equality and hashing functions for the hash tables.
797 : */
798 146 : if (IsA(subplan->testexpr, OpExpr))
799 : {
800 : /* single combining operator */
801 108 : oplist = list_make1(subplan->testexpr);
802 : }
803 38 : else if (and_clause((Node *) subplan->testexpr))
804 : {
805 : /* multiple combining operators */
806 38 : oplist = castNode(BoolExpr, subplan->testexpr)->args;
807 : }
808 : else
809 : {
810 : /* shouldn't see anything else in a hashable subplan */
811 0 : elog(ERROR, "unrecognized testexpr type: %d",
812 : (int) nodeTag(subplan->testexpr));
813 : oplist = NIL; /* keep compiler quiet */
814 : }
815 146 : Assert(list_length(oplist) == ncols);
816 :
817 146 : lefttlist = righttlist = NIL;
818 146 : sstate->tab_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
819 146 : sstate->tab_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
820 146 : sstate->lhs_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
821 146 : sstate->cur_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
822 146 : i = 1;
823 330 : foreach(l, oplist)
824 : {
825 184 : OpExpr *opexpr = lfirst_node(OpExpr, l);
826 : Expr *expr;
827 : TargetEntry *tle;
828 : Oid rhs_eq_oper;
829 : Oid left_hashfn;
830 : Oid right_hashfn;
831 :
832 184 : Assert(list_length(opexpr->args) == 2);
833 :
834 : /* Process lefthand argument */
835 184 : expr = (Expr *) linitial(opexpr->args);
836 184 : tle = makeTargetEntry(expr,
837 : i,
838 : NULL,
839 : false);
840 184 : lefttlist = lappend(lefttlist, tle);
841 :
842 : /* Process righthand argument */
843 184 : expr = (Expr *) lsecond(opexpr->args);
844 184 : tle = makeTargetEntry(expr,
845 : i,
846 : NULL,
847 : false);
848 184 : righttlist = lappend(righttlist, tle);
849 :
850 : /* Lookup the equality function (potentially cross-type) */
851 184 : fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
852 184 : fmgr_info_set_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
853 :
854 : /* Look up the equality function for the RHS type */
855 184 : if (!get_compatible_hash_operators(opexpr->opno,
856 : NULL, &rhs_eq_oper))
857 0 : elog(ERROR, "could not find compatible hash operator for operator %u",
858 : opexpr->opno);
859 184 : fmgr_info(get_opcode(rhs_eq_oper), &sstate->tab_eq_funcs[i - 1]);
860 :
861 : /* Lookup the associated hash functions */
862 184 : if (!get_op_hash_functions(opexpr->opno,
863 : &left_hashfn, &right_hashfn))
864 0 : elog(ERROR, "could not find hash function for hash operator %u",
865 : opexpr->opno);
866 184 : fmgr_info(left_hashfn, &sstate->lhs_hash_funcs[i - 1]);
867 184 : fmgr_info(right_hashfn, &sstate->tab_hash_funcs[i - 1]);
868 :
869 184 : i++;
870 : }
871 :
872 : /*
873 : * Construct tupdescs, slots and projection nodes for left and right
874 : * sides. The lefthand expressions will be evaluated in the parent
875 : * plan node's exprcontext, which we don't have access to here.
876 : * Fortunately we can just pass NULL for now and fill it in later
877 : * (hack alert!). The righthand expressions will be evaluated in our
878 : * own innerecontext.
879 : */
880 146 : tupDesc = ExecTypeFromTL(lefttlist, false);
881 146 : slot = ExecInitExtraTupleSlot(estate);
882 146 : ExecSetSlotDescriptor(slot, tupDesc);
883 146 : sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
884 : NULL,
885 : slot,
886 : parent,
887 : NULL);
888 :
889 146 : tupDesc = ExecTypeFromTL(righttlist, false);
890 146 : slot = ExecInitExtraTupleSlot(estate);
891 146 : ExecSetSlotDescriptor(slot, tupDesc);
892 146 : sstate->projRight = ExecBuildProjectionInfo(righttlist,
893 : sstate->innerecontext,
894 : slot,
895 146 : sstate->planstate,
896 : NULL);
897 : }
898 :
899 3274 : return sstate;
900 : }
901 :
902 : /* ----------------------------------------------------------------
903 : * ExecSetParamPlan
904 : *
905 : * Executes a subplan and sets its output parameters.
906 : *
907 : * This is called from ExecEvalParamExec() when the value of a PARAM_EXEC
908 : * parameter is requested and the param's execPlan field is set (indicating
909 : * that the param has not yet been evaluated). This allows lazy evaluation
910 : * of initplans: we don't run the subplan until/unless we need its output.
911 : * Note that this routine MUST clear the execPlan fields of the plan's
912 : * output parameters after evaluating them!
913 : * ----------------------------------------------------------------
914 : */
915 : void
916 1727 : ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
917 : {
918 1727 : SubPlan *subplan = node->subplan;
919 1727 : PlanState *planstate = node->planstate;
920 1727 : SubLinkType subLinkType = subplan->subLinkType;
921 : MemoryContext oldcontext;
922 : TupleTableSlot *slot;
923 : ListCell *pvar;
924 : ListCell *l;
925 1727 : bool found = false;
926 1727 : ArrayBuildStateAny *astate = NULL;
927 :
928 1727 : if (subLinkType == ANY_SUBLINK ||
929 : subLinkType == ALL_SUBLINK)
930 0 : elog(ERROR, "ANY/ALL subselect unsupported as initplan");
931 1727 : if (subLinkType == CTE_SUBLINK)
932 0 : elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
933 :
934 : /* Initialize ArrayBuildStateAny in caller's context, if needed */
935 1727 : if (subLinkType == ARRAY_SUBLINK)
936 8 : astate = initArrayResultAny(subplan->firstColType,
937 : CurrentMemoryContext, true);
938 :
939 : /*
940 : * Must switch to per-query memory context.
941 : */
942 1727 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
943 :
944 : /*
945 : * Set Params of this plan from parent plan correlation values. (Any
946 : * calculation we have to do is done in the parent econtext, since the
947 : * Param values don't need to have per-query lifetime.) Currently, we
948 : * expect only MULTIEXPR_SUBLINK plans to have any correlation values.
949 : */
950 1727 : Assert(subplan->parParam == NIL || subLinkType == MULTIEXPR_SUBLINK);
951 1727 : Assert(list_length(subplan->parParam) == list_length(node->args));
952 :
953 1743 : forboth(l, subplan->parParam, pvar, node->args)
954 : {
955 16 : int paramid = lfirst_int(l);
956 16 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
957 :
958 16 : prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
959 : econtext,
960 : &(prm->isnull));
961 16 : planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
962 : }
963 :
964 : /*
965 : * Run the plan. (If it needs to be rescanned, the first ExecProcNode
966 : * call will take care of that.)
967 : */
968 5947 : for (slot = ExecProcNode(planstate);
969 3994 : !TupIsNull(slot);
970 2493 : slot = ExecProcNode(planstate))
971 : {
972 2572 : TupleDesc tdesc = slot->tts_tupleDescriptor;
973 2572 : int i = 1;
974 :
975 2572 : if (subLinkType == EXISTS_SUBLINK)
976 : {
977 : /* There can be only one setParam... */
978 77 : int paramid = linitial_int(subplan->setParam);
979 77 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
980 :
981 77 : prm->execPlan = NULL;
982 77 : prm->value = BoolGetDatum(true);
983 77 : prm->isnull = false;
984 77 : found = true;
985 77 : break;
986 : }
987 :
988 2495 : if (subLinkType == ARRAY_SUBLINK)
989 : {
990 : Datum dvalue;
991 : bool disnull;
992 :
993 1318 : found = true;
994 : /* stash away current value */
995 1318 : Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
996 1318 : dvalue = slot_getattr(slot, 1, &disnull);
997 1318 : astate = accumArrayResultAny(astate, dvalue, disnull,
998 : subplan->firstColType, oldcontext);
999 : /* keep scanning subplan to collect all values */
1000 1318 : continue;
1001 : }
1002 :
1003 1177 : if (found &&
1004 1 : (subLinkType == EXPR_SUBLINK ||
1005 0 : subLinkType == MULTIEXPR_SUBLINK ||
1006 : subLinkType == ROWCOMPARE_SUBLINK))
1007 2 : ereport(ERROR,
1008 : (errcode(ERRCODE_CARDINALITY_VIOLATION),
1009 : errmsg("more than one row returned by a subquery used as an expression")));
1010 :
1011 1175 : found = true;
1012 :
1013 : /*
1014 : * We need to copy the subplan's tuple into our own context, in case
1015 : * any of the params are pass-by-ref type --- the pointers stored in
1016 : * the param structs will point at this copied tuple! node->curTuple
1017 : * keeps track of the copied tuple for eventual freeing.
1018 : */
1019 1175 : if (node->curTuple)
1020 64 : heap_freetuple(node->curTuple);
1021 1175 : node->curTuple = ExecCopySlotTuple(slot);
1022 :
1023 : /*
1024 : * Now set all the setParam params from the columns of the tuple
1025 : */
1026 2361 : foreach(l, subplan->setParam)
1027 : {
1028 1186 : int paramid = lfirst_int(l);
1029 1186 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1030 :
1031 1186 : prm->execPlan = NULL;
1032 1186 : prm->value = heap_getattr(node->curTuple, i, tdesc,
1033 : &(prm->isnull));
1034 1186 : i++;
1035 : }
1036 : }
1037 :
1038 1725 : if (subLinkType == ARRAY_SUBLINK)
1039 : {
1040 : /* There can be only one setParam... */
1041 8 : int paramid = linitial_int(subplan->setParam);
1042 8 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1043 :
1044 : /*
1045 : * We build the result array in query context so it won't disappear;
1046 : * to avoid leaking memory across repeated calls, we have to remember
1047 : * the latest value, much as for curTuple above.
1048 : */
1049 8 : if (node->curArray != PointerGetDatum(NULL))
1050 0 : pfree(DatumGetPointer(node->curArray));
1051 8 : node->curArray = makeArrayResultAny(astate,
1052 : econtext->ecxt_per_query_memory,
1053 : true);
1054 8 : prm->execPlan = NULL;
1055 8 : prm->value = node->curArray;
1056 8 : prm->isnull = false;
1057 : }
1058 1717 : else if (!found)
1059 : {
1060 467 : if (subLinkType == EXISTS_SUBLINK)
1061 : {
1062 : /* There can be only one setParam... */
1063 446 : int paramid = linitial_int(subplan->setParam);
1064 446 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1065 :
1066 446 : prm->execPlan = NULL;
1067 446 : prm->value = BoolGetDatum(false);
1068 446 : prm->isnull = false;
1069 : }
1070 : else
1071 : {
1072 : /* For other sublink types, set all the output params to NULL */
1073 43 : foreach(l, subplan->setParam)
1074 : {
1075 22 : int paramid = lfirst_int(l);
1076 22 : ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1077 :
1078 22 : prm->execPlan = NULL;
1079 22 : prm->value = (Datum) 0;
1080 22 : prm->isnull = true;
1081 : }
1082 : }
1083 : }
1084 :
1085 1725 : MemoryContextSwitchTo(oldcontext);
1086 1725 : }
1087 :
1088 : /*
1089 : * Mark an initplan as needing recalculation
1090 : */
1091 : void
1092 156 : ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
1093 : {
1094 156 : PlanState *planstate = node->planstate;
1095 156 : SubPlan *subplan = node->subplan;
1096 156 : EState *estate = parent->state;
1097 : ListCell *l;
1098 :
1099 : /* sanity checks */
1100 156 : if (subplan->parParam != NIL)
1101 0 : elog(ERROR, "direct correlated subquery unsupported as initplan");
1102 156 : if (subplan->setParam == NIL)
1103 0 : elog(ERROR, "setParam list of initplan is empty");
1104 156 : if (bms_is_empty(planstate->plan->extParam))
1105 0 : elog(ERROR, "extParam set of initplan is empty");
1106 :
1107 : /*
1108 : * Don't actually re-scan: it'll happen inside ExecSetParamPlan if needed.
1109 : */
1110 :
1111 : /*
1112 : * Mark this subplan's output parameters as needing recalculation.
1113 : *
1114 : * CTE subplans are never executed via parameter recalculation; instead
1115 : * they get run when called by nodeCtescan.c. So don't mark the output
1116 : * parameter of a CTE subplan as dirty, but do set the chgParam bit for it
1117 : * so that dependent plan nodes will get told to rescan.
1118 : */
1119 312 : foreach(l, subplan->setParam)
1120 : {
1121 156 : int paramid = lfirst_int(l);
1122 156 : ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
1123 :
1124 156 : if (subplan->subLinkType != CTE_SUBLINK)
1125 109 : prm->execPlan = node;
1126 :
1127 156 : parent->chgParam = bms_add_member(parent->chgParam, paramid);
1128 : }
1129 156 : }
1130 :
1131 :
1132 : /*
1133 : * ExecInitAlternativeSubPlan
1134 : *
1135 : * Initialize for execution of one of a set of alternative subplans.
1136 : */
1137 : AlternativeSubPlanState *
1138 99 : ExecInitAlternativeSubPlan(AlternativeSubPlan *asplan, PlanState *parent)
1139 : {
1140 99 : AlternativeSubPlanState *asstate = makeNode(AlternativeSubPlanState);
1141 : double num_calls;
1142 : SubPlan *subplan1;
1143 : SubPlan *subplan2;
1144 : Cost cost1;
1145 : Cost cost2;
1146 : ListCell *lc;
1147 :
1148 99 : asstate->subplan = asplan;
1149 :
1150 : /*
1151 : * Initialize subplans. (Can we get away with only initializing the one
1152 : * we're going to use?)
1153 : */
1154 297 : foreach(lc, asplan->subplans)
1155 : {
1156 198 : SubPlan *sp = lfirst_node(SubPlan, lc);
1157 198 : SubPlanState *sps = ExecInitSubPlan(sp, parent);
1158 :
1159 198 : asstate->subplans = lappend(asstate->subplans, sps);
1160 198 : parent->subPlan = lappend(parent->subPlan, sps);
1161 : }
1162 :
1163 : /*
1164 : * Select the one to be used. For this, we need an estimate of the number
1165 : * of executions of the subplan. We use the number of output rows
1166 : * expected from the parent plan node. This is a good estimate if we are
1167 : * in the parent's targetlist, and an underestimate (but probably not by
1168 : * more than a factor of 2) if we are in the qual.
1169 : */
1170 99 : num_calls = parent->plan->plan_rows;
1171 :
1172 : /*
1173 : * The planner saved enough info so that we don't have to work very hard
1174 : * to estimate the total cost, given the number-of-calls estimate.
1175 : */
1176 99 : Assert(list_length(asplan->subplans) == 2);
1177 99 : subplan1 = (SubPlan *) linitial(asplan->subplans);
1178 99 : subplan2 = (SubPlan *) lsecond(asplan->subplans);
1179 :
1180 99 : cost1 = subplan1->startup_cost + num_calls * subplan1->per_call_cost;
1181 99 : cost2 = subplan2->startup_cost + num_calls * subplan2->per_call_cost;
1182 :
1183 99 : if (cost1 < cost2)
1184 65 : asstate->active = 0;
1185 : else
1186 34 : asstate->active = 1;
1187 :
1188 99 : return asstate;
1189 : }
1190 :
1191 : /*
1192 : * ExecAlternativeSubPlan
1193 : *
1194 : * Execute one of a set of alternative subplans.
1195 : *
1196 : * Note: in future we might consider changing to different subplans on the
1197 : * fly, in case the original rowcount estimate turns out to be way off.
1198 : */
1199 : Datum
1200 143 : ExecAlternativeSubPlan(AlternativeSubPlanState *node,
1201 : ExprContext *econtext,
1202 : bool *isNull)
1203 : {
1204 : /* Just pass control to the active subplan */
1205 143 : SubPlanState *activesp = list_nth_node(SubPlanState,
1206 : node->subplans, node->active);
1207 :
1208 143 : return ExecSubPlan(activesp, econtext, isNull);
1209 : }
|