Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * execProcnode.c
4 : : * contains dispatch functions which call the appropriate "initialize",
5 : : * "get a tuple", and "cleanup" routines for the given node type.
6 : : * If the node has children, then it will presumably call ExecInitNode,
7 : : * ExecProcNode, or ExecEndNode on its subnodes and do the appropriate
8 : : * processing.
9 : : *
10 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
11 : : * Portions Copyright (c) 1994, Regents of the University of California
12 : : *
13 : : *
14 : : * IDENTIFICATION
15 : : * src/backend/executor/execProcnode.c
16 : : *
17 : : *-------------------------------------------------------------------------
18 : : */
19 : : /*
20 : : * NOTES
21 : : * This used to be three files. It is now all combined into
22 : : * one file so that it is easier to keep the dispatch routines
23 : : * in sync when new nodes are added.
24 : : *
25 : : * EXAMPLE
26 : : * Suppose we want the age of the manager of the shoe department and
27 : : * the number of employees in that department. So we have the query:
28 : : *
29 : : * select DEPT.no_emps, EMP.age
30 : : * from DEPT, EMP
31 : : * where EMP.name = DEPT.mgr and
32 : : * DEPT.name = "shoe"
33 : : *
34 : : * Suppose the planner gives us the following plan:
35 : : *
36 : : * Nest Loop (DEPT.mgr = EMP.name)
37 : : * / \
38 : : * / \
39 : : * Seq Scan Seq Scan
40 : : * DEPT EMP
41 : : * (name = "shoe")
42 : : *
43 : : * ExecutorStart() is called first.
44 : : * It calls InitPlan() which calls ExecInitNode() on
45 : : * the root of the plan -- the nest loop node.
46 : : *
47 : : * * ExecInitNode() notices that it is looking at a nest loop and
48 : : * as the code below demonstrates, it calls ExecInitNestLoop().
49 : : * Eventually this calls ExecInitNode() on the right and left subplans
50 : : * and so forth until the entire plan is initialized. The result
51 : : * of ExecInitNode() is a plan state tree built with the same structure
52 : : * as the underlying plan tree.
53 : : *
54 : : * * Then when ExecutorRun() is called, it calls ExecutePlan() which calls
55 : : * ExecProcNode() repeatedly on the top node of the plan state tree.
56 : : * Each time this happens, ExecProcNode() will end up calling
57 : : * ExecNestLoop(), which calls ExecProcNode() on its subplans.
58 : : * Each of these subplans is a sequential scan so ExecSeqScan() is
59 : : * called. The slots returned by ExecSeqScan() may contain
60 : : * tuples which contain the attributes ExecNestLoop() uses to
61 : : * form the tuples it returns.
62 : : *
63 : : * * Eventually ExecSeqScan() stops returning tuples and the nest
64 : : * loop join ends. Lastly, ExecutorEnd() calls ExecEndNode() which
65 : : * calls ExecEndNestLoop() which in turn calls ExecEndNode() on
66 : : * its subplans which result in ExecEndSeqScan().
67 : : *
68 : : * This should show how the executor works by having
69 : : * ExecInitNode(), ExecProcNode() and ExecEndNode() dispatch
70 : : * their work to the appropriate node support routines which may
71 : : * in turn call these routines themselves on their subplans.
72 : : */
73 : : #include "postgres.h"
74 : :
75 : : #include "executor/executor.h"
76 : : #include "executor/nodeAgg.h"
77 : : #include "executor/nodeAppend.h"
78 : : #include "executor/nodeBitmapAnd.h"
79 : : #include "executor/nodeBitmapHeapscan.h"
80 : : #include "executor/nodeBitmapIndexscan.h"
81 : : #include "executor/nodeBitmapOr.h"
82 : : #include "executor/nodeCtescan.h"
83 : : #include "executor/nodeCustom.h"
84 : : #include "executor/nodeForeignscan.h"
85 : : #include "executor/nodeFunctionscan.h"
86 : : #include "executor/nodeGather.h"
87 : : #include "executor/nodeGatherMerge.h"
88 : : #include "executor/nodeGroup.h"
89 : : #include "executor/nodeHash.h"
90 : : #include "executor/nodeHashjoin.h"
91 : : #include "executor/nodeIncrementalSort.h"
92 : : #include "executor/nodeIndexonlyscan.h"
93 : : #include "executor/nodeIndexscan.h"
94 : : #include "executor/nodeLimit.h"
95 : : #include "executor/nodeLockRows.h"
96 : : #include "executor/nodeMaterial.h"
97 : : #include "executor/nodeMemoize.h"
98 : : #include "executor/nodeMergeAppend.h"
99 : : #include "executor/nodeMergejoin.h"
100 : : #include "executor/nodeModifyTable.h"
101 : : #include "executor/nodeNamedtuplestorescan.h"
102 : : #include "executor/nodeNestloop.h"
103 : : #include "executor/nodeProjectSet.h"
104 : : #include "executor/nodeRecursiveunion.h"
105 : : #include "executor/nodeResult.h"
106 : : #include "executor/nodeSamplescan.h"
107 : : #include "executor/nodeSeqscan.h"
108 : : #include "executor/nodeSetOp.h"
109 : : #include "executor/nodeSort.h"
110 : : #include "executor/nodeSubplan.h"
111 : : #include "executor/nodeSubqueryscan.h"
112 : : #include "executor/nodeTableFuncscan.h"
113 : : #include "executor/nodeTidrangescan.h"
114 : : #include "executor/nodeTidscan.h"
115 : : #include "executor/nodeUnique.h"
116 : : #include "executor/nodeValuesscan.h"
117 : : #include "executor/nodeWindowAgg.h"
118 : : #include "executor/nodeWorktablescan.h"
119 : : #include "miscadmin.h"
120 : : #include "nodes/nodeFuncs.h"
121 : :
122 : : static TupleTableSlot *ExecProcNodeFirst(PlanState *node);
123 : : static TupleTableSlot *ExecProcNodeInstr(PlanState *node);
124 : : static bool ExecShutdownNode_walker(PlanState *node, void *context);
125 : :
126 : :
127 : : /* ------------------------------------------------------------------------
128 : : * ExecInitNode
129 : : *
130 : : * Recursively initializes all the nodes in the plan tree rooted
131 : : * at 'node'.
132 : : *
133 : : * Inputs:
134 : : * 'node' is the current node of the plan produced by the query planner
135 : : * 'estate' is the shared execution state for the plan tree
136 : : * 'eflags' is a bitwise OR of flag bits described in executor.h
137 : : *
138 : : * Returns a PlanState node corresponding to the given Plan node.
139 : : * ------------------------------------------------------------------------
140 : : */
141 : : PlanState *
142 : 956305 : ExecInitNode(Plan *node, EState *estate, int eflags)
143 : : {
144 : 956305 : PlanState *result;
145 : 956305 : List *subps;
146 : 956305 : ListCell *l;
147 : :
148 : : /*
149 : : * do nothing when we get to the end of a leaf on tree.
150 : : */
151 [ + + ]: 956305 : if (node == NULL)
152 : 23000 : return NULL;
153 : :
154 : : /*
155 : : * Make sure there's enough stack available. Need to check here, in
156 : : * addition to ExecProcNode() (via ExecProcNodeFirst()), to ensure the
157 : : * stack isn't overrun while initializing the node tree.
158 : : */
159 : 933305 : check_stack_depth();
160 : :
161 [ + - + + : 933305 : switch (nodeTag(node))
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + - + +
+ + + + +
+ + + + +
+ + + - ]
162 : : {
163 : : /*
164 : : * control nodes
165 : : */
166 : : case T_Result:
167 : 49236 : result = (PlanState *) ExecInitResult((Result *) node,
168 : 24618 : estate, eflags);
169 : 24618 : break;
170 : :
171 : : case T_ProjectSet:
172 : 4002 : result = (PlanState *) ExecInitProjectSet((ProjectSet *) node,
173 : 2001 : estate, eflags);
174 : 2001 : break;
175 : :
176 : : case T_ModifyTable:
177 : 20314 : result = (PlanState *) ExecInitModifyTable((ModifyTable *) node,
178 : 10157 : estate, eflags);
179 : 10157 : break;
180 : :
181 : : case T_Append:
182 : 5154 : result = (PlanState *) ExecInitAppend((Append *) node,
183 : 2577 : estate, eflags);
184 : 2577 : break;
185 : :
186 : : case T_MergeAppend:
187 : 192 : result = (PlanState *) ExecInitMergeAppend((MergeAppend *) node,
188 : 96 : estate, eflags);
189 : 96 : break;
190 : :
191 : : case T_RecursiveUnion:
192 : 146 : result = (PlanState *) ExecInitRecursiveUnion((RecursiveUnion *) node,
193 : 73 : estate, eflags);
194 : 73 : break;
195 : :
196 : : case T_BitmapAnd:
197 : 34 : result = (PlanState *) ExecInitBitmapAnd((BitmapAnd *) node,
198 : 17 : estate, eflags);
199 : 17 : break;
200 : :
201 : : case T_BitmapOr:
202 : 66 : result = (PlanState *) ExecInitBitmapOr((BitmapOr *) node,
203 : 33 : estate, eflags);
204 : 33 : break;
205 : :
206 : : /*
207 : : * scan nodes
208 : : */
209 : : case T_SeqScan:
210 : 656114 : result = (PlanState *) ExecInitSeqScan((SeqScan *) node,
211 : 328057 : estate, eflags);
212 : 328057 : break;
213 : :
214 : : case T_SampleScan:
215 : 90 : result = (PlanState *) ExecInitSampleScan((SampleScan *) node,
216 : 45 : estate, eflags);
217 : 45 : break;
218 : :
219 : : case T_IndexScan:
220 : 226308 : result = (PlanState *) ExecInitIndexScan((IndexScan *) node,
221 : 113154 : estate, eflags);
222 : 113154 : break;
223 : :
224 : : case T_IndexOnlyScan:
225 : 3930 : result = (PlanState *) ExecInitIndexOnlyScan((IndexOnlyScan *) node,
226 : 1965 : estate, eflags);
227 : 1965 : break;
228 : :
229 : : case T_BitmapIndexScan:
230 : 5540 : result = (PlanState *) ExecInitBitmapIndexScan((BitmapIndexScan *) node,
231 : 2770 : estate, eflags);
232 : 2770 : break;
233 : :
234 : : case T_BitmapHeapScan:
235 : 5438 : result = (PlanState *) ExecInitBitmapHeapScan((BitmapHeapScan *) node,
236 : 2719 : estate, eflags);
237 : 2719 : break;
238 : :
239 : : case T_TidScan:
240 : 190 : result = (PlanState *) ExecInitTidScan((TidScan *) node,
241 : 95 : estate, eflags);
242 : 95 : break;
243 : :
244 : : case T_TidRangeScan:
245 : 700 : result = (PlanState *) ExecInitTidRangeScan((TidRangeScan *) node,
246 : 350 : estate, eflags);
247 : 350 : break;
248 : :
249 : : case T_SubqueryScan:
250 : 3028 : result = (PlanState *) ExecInitSubqueryScan((SubqueryScan *) node,
251 : 1514 : estate, eflags);
252 : 1514 : break;
253 : :
254 : : case T_FunctionScan:
255 : 11148 : result = (PlanState *) ExecInitFunctionScan((FunctionScan *) node,
256 : 5574 : estate, eflags);
257 : 5574 : break;
258 : :
259 : : case T_TableFuncScan:
260 : 206 : result = (PlanState *) ExecInitTableFuncScan((TableFuncScan *) node,
261 : 103 : estate, eflags);
262 : 103 : break;
263 : :
264 : : case T_ValuesScan:
265 : 2500 : result = (PlanState *) ExecInitValuesScan((ValuesScan *) node,
266 : 1250 : estate, eflags);
267 : 1250 : break;
268 : :
269 : : case T_CteScan:
270 : 424 : result = (PlanState *) ExecInitCteScan((CteScan *) node,
271 : 212 : estate, eflags);
272 : 212 : break;
273 : :
274 : : case T_NamedTuplestoreScan:
275 : 226 : result = (PlanState *) ExecInitNamedTuplestoreScan((NamedTuplestoreScan *) node,
276 : 113 : estate, eflags);
277 : 113 : break;
278 : :
279 : : case T_WorkTableScan:
280 : 146 : result = (PlanState *) ExecInitWorkTableScan((WorkTableScan *) node,
281 : 73 : estate, eflags);
282 : 73 : break;
283 : :
284 : : case T_ForeignScan:
285 : 0 : result = (PlanState *) ExecInitForeignScan((ForeignScan *) node,
286 : 0 : estate, eflags);
287 : 0 : break;
288 : :
289 : : case T_CustomScan:
290 : 0 : result = (PlanState *) ExecInitCustomScan((CustomScan *) node,
291 : 0 : estate, eflags);
292 : 0 : break;
293 : :
294 : : /*
295 : : * join nodes
296 : : */
297 : : case T_NestLoop:
298 : 18308 : result = (PlanState *) ExecInitNestLoop((NestLoop *) node,
299 : 9154 : estate, eflags);
300 : 9154 : break;
301 : :
302 : : case T_MergeJoin:
303 : 964 : result = (PlanState *) ExecInitMergeJoin((MergeJoin *) node,
304 : 482 : estate, eflags);
305 : 482 : break;
306 : :
307 : : case T_HashJoin:
308 : 6856 : result = (PlanState *) ExecInitHashJoin((HashJoin *) node,
309 : 3428 : estate, eflags);
310 : 3428 : break;
311 : :
312 : : /*
313 : : * materialization nodes
314 : : */
315 : : case T_Material:
316 : 1064 : result = (PlanState *) ExecInitMaterial((Material *) node,
317 : 532 : estate, eflags);
318 : 532 : break;
319 : :
320 : : case T_Sort:
321 : 18912 : result = (PlanState *) ExecInitSort((Sort *) node,
322 : 9456 : estate, eflags);
323 : 9456 : break;
324 : :
325 : : case T_IncrementalSort:
326 : 238 : result = (PlanState *) ExecInitIncrementalSort((IncrementalSort *) node,
327 : 119 : estate, eflags);
328 : 119 : break;
329 : :
330 : : case T_Memoize:
331 : 434 : result = (PlanState *) ExecInitMemoize((Memoize *) node, estate,
332 : 217 : eflags);
333 : 217 : break;
334 : :
335 : : case T_Group:
336 : 78 : result = (PlanState *) ExecInitGroup((Group *) node,
337 : 39 : estate, eflags);
338 : 39 : break;
339 : :
340 : : case T_Agg:
341 : 11996 : result = (PlanState *) ExecInitAgg((Agg *) node,
342 : 5998 : estate, eflags);
343 : 5998 : break;
344 : :
345 : : case T_WindowAgg:
346 : 914 : result = (PlanState *) ExecInitWindowAgg((WindowAgg *) node,
347 : 457 : estate, eflags);
348 : 457 : break;
349 : :
350 : : case T_Unique:
351 : 1424 : result = (PlanState *) ExecInitUnique((Unique *) node,
352 : 712 : estate, eflags);
353 : 712 : break;
354 : :
355 : : case T_Gather:
356 : 386 : result = (PlanState *) ExecInitGather((Gather *) node,
357 : 193 : estate, eflags);
358 : 193 : break;
359 : :
360 : : case T_GatherMerge:
361 : 134 : result = (PlanState *) ExecInitGatherMerge((GatherMerge *) node,
362 : 67 : estate, eflags);
363 : 67 : break;
364 : :
365 : : case T_Hash:
366 : 6856 : result = (PlanState *) ExecInitHash((Hash *) node,
367 : 3428 : estate, eflags);
368 : 3428 : break;
369 : :
370 : : case T_SetOp:
371 : 220 : result = (PlanState *) ExecInitSetOp((SetOp *) node,
372 : 110 : estate, eflags);
373 : 110 : break;
374 : :
375 : : case T_LockRows:
376 : 801664 : result = (PlanState *) ExecInitLockRows((LockRows *) node,
377 : 400832 : estate, eflags);
378 : 400832 : break;
379 : :
380 : : case T_Limit:
381 : 1030 : result = (PlanState *) ExecInitLimit((Limit *) node,
382 : 515 : estate, eflags);
383 : 515 : break;
384 : :
385 : : default:
386 [ # # # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
387 : 0 : result = NULL; /* keep compiler quiet */
388 : 0 : break;
389 : : }
390 : :
391 : 933305 : ExecSetExecProcNode(result, result->ExecProcNode);
392 : :
393 : : /*
394 : : * Initialize any initPlans present in this node. The planner put them in
395 : : * a separate list for us.
396 : : *
397 : : * The defining characteristic of initplans is that they don't have
398 : : * arguments, so we don't need to evaluate them (in contrast to
399 : : * ExecInitSubPlanExpr()).
400 : : */
401 : 933305 : subps = NIL;
402 [ + + + + : 934397 : foreach(l, node->initPlan)
+ + ]
403 : : {
404 : 1092 : SubPlan *subplan = (SubPlan *) lfirst(l);
405 : 1092 : SubPlanState *sstate;
406 : :
407 [ + - ]: 1092 : Assert(IsA(subplan, SubPlan));
408 [ + - ]: 1092 : Assert(subplan->args == NIL);
409 : 1092 : sstate = ExecInitSubPlan(subplan, result);
410 : 1092 : subps = lappend(subps, sstate);
411 : 1092 : }
412 : 933305 : result->initPlan = subps;
413 : :
414 : : /* Set up instrumentation for this node if requested */
415 [ + + ]: 933305 : if (estate->es_instrument)
416 : 3420 : result->instrument = InstrAlloc(1, estate->es_instrument,
417 : 1710 : result->async_capable);
418 : :
419 : 933305 : return result;
420 : 956305 : }
421 : :
422 : :
423 : : /*
424 : : * If a node wants to change its ExecProcNode function after ExecInitNode()
425 : : * has finished, it should do so with this function. That way any wrapper
426 : : * functions can be reinstalled, without the node having to know how that
427 : : * works.
428 : : */
429 : : void
430 : 933319 : ExecSetExecProcNode(PlanState *node, ExecProcNodeMtd function)
431 : : {
432 : : /*
433 : : * Add a wrapper around the ExecProcNode callback that checks stack depth
434 : : * during the first execution and maybe adds an instrumentation wrapper.
435 : : * When the callback is changed after execution has already begun that
436 : : * means we'll superfluously execute ExecProcNodeFirst, but that seems ok.
437 : : */
438 : 933319 : node->ExecProcNodeReal = function;
439 : 933319 : node->ExecProcNode = ExecProcNodeFirst;
440 : 933319 : }
441 : :
442 : :
443 : : /*
444 : : * ExecProcNode wrapper that performs some one-time checks, before calling
445 : : * the relevant node method (possibly via an instrumentation wrapper).
446 : : */
447 : : static TupleTableSlot *
448 : 907074 : ExecProcNodeFirst(PlanState *node)
449 : : {
450 : : /*
451 : : * Perform stack depth check during the first execution of the node. We
452 : : * only do so the first time round because it turns out to not be cheap on
453 : : * some common architectures (eg. x86). This relies on the assumption
454 : : * that ExecProcNode calls for a given plan node will always be made at
455 : : * roughly the same stack depth.
456 : : */
457 : 907074 : check_stack_depth();
458 : :
459 : : /*
460 : : * If instrumentation is required, change the wrapper to one that just
461 : : * does instrumentation. Otherwise we can dispense with all wrappers and
462 : : * have ExecProcNode() directly call the relevant function from now on.
463 : : */
464 [ + + ]: 907074 : if (node->instrument)
465 : 1322 : node->ExecProcNode = ExecProcNodeInstr;
466 : : else
467 : 905752 : node->ExecProcNode = node->ExecProcNodeReal;
468 : :
469 : 907074 : return node->ExecProcNode(node);
470 : : }
471 : :
472 : :
473 : : /*
474 : : * ExecProcNode wrapper that performs instrumentation calls. By keeping
475 : : * this a separate function, we avoid overhead in the normal case where
476 : : * no instrumentation is wanted.
477 : : */
478 : : static TupleTableSlot *
479 : 2251945 : ExecProcNodeInstr(PlanState *node)
480 : : {
481 : 2251945 : TupleTableSlot *result;
482 : :
483 : 2251945 : InstrStartNode(node->instrument);
484 : :
485 : 2251945 : result = node->ExecProcNodeReal(node);
486 : :
487 [ + + ]: 2251945 : InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
488 : :
489 : 4503890 : return result;
490 : 2251945 : }
491 : :
492 : :
493 : : /* ----------------------------------------------------------------
494 : : * MultiExecProcNode
495 : : *
496 : : * Execute a node that doesn't return individual tuples
497 : : * (it might return a hashtable, bitmap, etc). Caller should
498 : : * check it got back the expected kind of Node.
499 : : *
500 : : * This has essentially the same responsibilities as ExecProcNode,
501 : : * but it does not do InstrStartNode/InstrStopNode (mainly because
502 : : * it can't tell how many returned tuples to count). Each per-node
503 : : * function must provide its own instrumentation support.
504 : : * ----------------------------------------------------------------
505 : : */
506 : : Node *
507 : 3907 : MultiExecProcNode(PlanState *node)
508 : : {
509 : 3907 : Node *result;
510 : :
511 : 3907 : check_stack_depth();
512 : :
513 [ + - ]: 3907 : CHECK_FOR_INTERRUPTS();
514 : :
515 [ + + ]: 3907 : if (node->chgParam != NULL) /* something changed */
516 : 266 : ExecReScan(node); /* let ReScan handle this */
517 : :
518 [ + + + + : 3907 : switch (nodeTag(node))
- ]
519 : : {
520 : : /*
521 : : * Only node types that actually support multiexec will be listed
522 : : */
523 : :
524 : : case T_HashState:
525 : 1905 : result = MultiExecHash((HashState *) node);
526 : 1905 : break;
527 : :
528 : : case T_BitmapIndexScanState:
529 : 1984 : result = MultiExecBitmapIndexScan((BitmapIndexScanState *) node);
530 : 1984 : break;
531 : :
532 : : case T_BitmapAndState:
533 : 9 : result = MultiExecBitmapAnd((BitmapAndState *) node);
534 : 9 : break;
535 : :
536 : : case T_BitmapOrState:
537 : 9 : result = MultiExecBitmapOr((BitmapOrState *) node);
538 : 9 : break;
539 : :
540 : : default:
541 [ # # # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
542 : 0 : result = NULL;
543 : 0 : break;
544 : : }
545 : :
546 : 7814 : return result;
547 : 3907 : }
548 : :
549 : :
550 : : /* ----------------------------------------------------------------
551 : : * ExecEndNode
552 : : *
553 : : * Recursively cleans up all the nodes in the plan rooted
554 : : * at 'node'.
555 : : *
556 : : * After this operation, the query plan will not be able to be
557 : : * processed any further. This should be called only after
558 : : * the query plan has been fully executed.
559 : : * ----------------------------------------------------------------
560 : : */
561 : : void
562 : 943355 : ExecEndNode(PlanState *node)
563 : : {
564 : : /*
565 : : * do nothing when we get to the end of a leaf on tree.
566 : : */
567 [ + + ]: 943355 : if (node == NULL)
568 : 17911 : return;
569 : :
570 : : /*
571 : : * Make sure there's enough stack available. Need to check here, in
572 : : * addition to ExecProcNode() (via ExecProcNodeFirst()), because it's not
573 : : * guaranteed that ExecProcNode() is reached for all nodes.
574 : : */
575 : 925444 : check_stack_depth();
576 : :
577 [ + + ]: 925444 : if (node->chgParam != NULL)
578 : : {
579 : 1201 : bms_free(node->chgParam);
580 : 1201 : node->chgParam = NULL;
581 : 1201 : }
582 : :
583 [ + + + + : 925444 : switch (nodeTag(node))
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ - - + +
+ + + + +
+ + + + +
+ - ]
584 : : {
585 : : /*
586 : : * control nodes
587 : : */
588 : : case T_ResultState:
589 : 19535 : ExecEndResult((ResultState *) node);
590 : 19535 : break;
591 : :
592 : : case T_ProjectSetState:
593 : 1762 : ExecEndProjectSet((ProjectSetState *) node);
594 : 1762 : break;
595 : :
596 : : case T_ModifyTableState:
597 : 9478 : ExecEndModifyTable((ModifyTableState *) node);
598 : 9478 : break;
599 : :
600 : : case T_AppendState:
601 : 2534 : ExecEndAppend((AppendState *) node);
602 : 2534 : break;
603 : :
604 : : case T_MergeAppendState:
605 : 96 : ExecEndMergeAppend((MergeAppendState *) node);
606 : 96 : break;
607 : :
608 : : case T_RecursiveUnionState:
609 : 73 : ExecEndRecursiveUnion((RecursiveUnionState *) node);
610 : 73 : break;
611 : :
612 : : case T_BitmapAndState:
613 : 17 : ExecEndBitmapAnd((BitmapAndState *) node);
614 : 17 : break;
615 : :
616 : : case T_BitmapOrState:
617 : 33 : ExecEndBitmapOr((BitmapOrState *) node);
618 : 33 : break;
619 : :
620 : : /*
621 : : * scan nodes
622 : : */
623 : : case T_SeqScanState:
624 : 327668 : ExecEndSeqScan((SeqScanState *) node);
625 : 327668 : break;
626 : :
627 : : case T_SampleScanState:
628 : 39 : ExecEndSampleScan((SampleScanState *) node);
629 : 39 : break;
630 : :
631 : : case T_GatherState:
632 : 191 : ExecEndGather((GatherState *) node);
633 : 191 : break;
634 : :
635 : : case T_GatherMergeState:
636 : 67 : ExecEndGatherMerge((GatherMergeState *) node);
637 : 67 : break;
638 : :
639 : : case T_IndexScanState:
640 : 113071 : ExecEndIndexScan((IndexScanState *) node);
641 : 113071 : break;
642 : :
643 : : case T_IndexOnlyScanState:
644 : 1957 : ExecEndIndexOnlyScan((IndexOnlyScanState *) node);
645 : 1957 : break;
646 : :
647 : : case T_BitmapIndexScanState:
648 : 2754 : ExecEndBitmapIndexScan((BitmapIndexScanState *) node);
649 : 2754 : break;
650 : :
651 : : case T_BitmapHeapScanState:
652 : 2703 : ExecEndBitmapHeapScan((BitmapHeapScanState *) node);
653 : 2703 : break;
654 : :
655 : : case T_TidScanState:
656 : 75 : ExecEndTidScan((TidScanState *) node);
657 : 75 : break;
658 : :
659 : : case T_TidRangeScanState:
660 : 61 : ExecEndTidRangeScan((TidRangeScanState *) node);
661 : 61 : break;
662 : :
663 : : case T_SubqueryScanState:
664 : 1514 : ExecEndSubqueryScan((SubqueryScanState *) node);
665 : 1514 : break;
666 : :
667 : : case T_FunctionScanState:
668 : 4790 : ExecEndFunctionScan((FunctionScanState *) node);
669 : 4790 : break;
670 : :
671 : : case T_TableFuncScanState:
672 : 84 : ExecEndTableFuncScan((TableFuncScanState *) node);
673 : 84 : break;
674 : :
675 : : case T_CteScanState:
676 : 209 : ExecEndCteScan((CteScanState *) node);
677 : 209 : break;
678 : :
679 : : case T_ForeignScanState:
680 : 0 : ExecEndForeignScan((ForeignScanState *) node);
681 : 0 : break;
682 : :
683 : : case T_CustomScanState:
684 : 0 : ExecEndCustomScan((CustomScanState *) node);
685 : 0 : break;
686 : :
687 : : /*
688 : : * join nodes
689 : : */
690 : : case T_NestLoopState:
691 : 9136 : ExecEndNestLoop((NestLoopState *) node);
692 : 9136 : break;
693 : :
694 : : case T_MergeJoinState:
695 : 481 : ExecEndMergeJoin((MergeJoinState *) node);
696 : 481 : break;
697 : :
698 : : case T_HashJoinState:
699 : 3412 : ExecEndHashJoin((HashJoinState *) node);
700 : 3412 : break;
701 : :
702 : : /*
703 : : * materialization nodes
704 : : */
705 : : case T_MaterialState:
706 : 524 : ExecEndMaterial((MaterialState *) node);
707 : 524 : break;
708 : :
709 : : case T_SortState:
710 : 9429 : ExecEndSort((SortState *) node);
711 : 9429 : break;
712 : :
713 : : case T_IncrementalSortState:
714 : 119 : ExecEndIncrementalSort((IncrementalSortState *) node);
715 : 119 : break;
716 : :
717 : : case T_MemoizeState:
718 : 217 : ExecEndMemoize((MemoizeState *) node);
719 : 217 : break;
720 : :
721 : : case T_GroupState:
722 : 39 : ExecEndGroup((GroupState *) node);
723 : 39 : break;
724 : :
725 : : case T_AggState:
726 : 5978 : ExecEndAgg((AggState *) node);
727 : 5978 : break;
728 : :
729 : : case T_WindowAggState:
730 : 423 : ExecEndWindowAgg((WindowAggState *) node);
731 : 423 : break;
732 : :
733 : : case T_UniqueState:
734 : 712 : ExecEndUnique((UniqueState *) node);
735 : 712 : break;
736 : :
737 : : case T_HashState:
738 : 3412 : ExecEndHash((HashState *) node);
739 : 3412 : break;
740 : :
741 : : case T_SetOpState:
742 : 110 : ExecEndSetOp((SetOpState *) node);
743 : 110 : break;
744 : :
745 : : case T_LockRowsState:
746 : 400828 : ExecEndLockRows((LockRowsState *) node);
747 : 400828 : break;
748 : :
749 : : case T_LimitState:
750 : 506 : ExecEndLimit((LimitState *) node);
751 : 506 : break;
752 : :
753 : : /* No clean up actions for these nodes. */
754 : : case T_ValuesScanState:
755 : : case T_NamedTuplestoreScanState:
756 : : case T_WorkTableScanState:
757 : 1407 : break;
758 : :
759 : : default:
760 [ # # # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
761 : 0 : break;
762 : : }
763 : 943355 : }
764 : :
765 : : /*
766 : : * ExecShutdownNode
767 : : *
768 : : * Give execution nodes a chance to stop asynchronous resource consumption
769 : : * and release any resources still held.
770 : : */
771 : : void
772 : 445621 : ExecShutdownNode(PlanState *node)
773 : : {
774 : 445621 : (void) ExecShutdownNode_walker(node, NULL);
775 : 445621 : }
776 : :
777 : : static bool
778 : 915738 : ExecShutdownNode_walker(PlanState *node, void *context)
779 : : {
780 [ + - ]: 915738 : if (node == NULL)
781 : 0 : return false;
782 : :
783 : 915738 : check_stack_depth();
784 : :
785 : : /*
786 : : * Treat the node as running while we shut it down, but only if it's run
787 : : * at least once already. We don't expect much CPU consumption during
788 : : * node shutdown, but in the case of Gather or Gather Merge, we may shut
789 : : * down workers at this stage. If so, their buffer usage will get
790 : : * propagated into pgBufferUsage at this point, and we want to make sure
791 : : * that it gets associated with the Gather node. We skip this if the node
792 : : * has never been executed, so as to avoid incorrectly making it appear
793 : : * that it has.
794 : : */
795 [ + + + + ]: 915738 : if (node->instrument && node->instrument->running)
796 : 1449 : InstrStartNode(node->instrument);
797 : :
798 : 915738 : planstate_tree_walker(node, ExecShutdownNode_walker, context);
799 : :
800 [ + - - + : 915738 : switch (nodeTag(node))
+ + + ]
801 : : {
802 : : case T_GatherState:
803 : 105 : ExecShutdownGather((GatherState *) node);
804 : 105 : break;
805 : : case T_ForeignScanState:
806 : 0 : ExecShutdownForeignScan((ForeignScanState *) node);
807 : 0 : break;
808 : : case T_CustomScanState:
809 : 0 : ExecShutdownCustomScan((CustomScanState *) node);
810 : 0 : break;
811 : : case T_GatherMergeState:
812 : 23 : ExecShutdownGatherMerge((GatherMergeState *) node);
813 : 23 : break;
814 : : case T_HashState:
815 : 2809 : ExecShutdownHash((HashState *) node);
816 : 2809 : break;
817 : : case T_HashJoinState:
818 : 2809 : ExecShutdownHashJoin((HashJoinState *) node);
819 : 2809 : break;
820 : : default:
821 : 909992 : break;
822 : : }
823 : :
824 : : /* Stop the node if we started it above, reporting 0 tuples. */
825 [ + + + + ]: 915738 : if (node->instrument && node->instrument->running)
826 : 1449 : InstrStopNode(node->instrument, 0);
827 : :
828 : 915738 : return false;
829 : 915738 : }
830 : :
831 : : /*
832 : : * ExecSetTupleBound
833 : : *
834 : : * Set a tuple bound for a planstate node. This lets child plan nodes
835 : : * optimize based on the knowledge that the maximum number of tuples that
836 : : * their parent will demand is limited. The tuple bound for a node may
837 : : * only be changed between scans (i.e., after node initialization or just
838 : : * before an ExecReScan call).
839 : : *
840 : : * Any negative tuples_needed value means "no limit", which should be the
841 : : * default assumption when this is not called at all for a particular node.
842 : : *
843 : : * Note: if this is called repeatedly on a plan tree, the exact same set
844 : : * of nodes must be updated with the new limit each time; be careful that
845 : : * only unchanging conditions are tested here.
846 : : */
847 : : void
848 : 10982 : ExecSetTupleBound(int64 tuples_needed, PlanState *child_node)
849 : : {
850 : : /*
851 : : * Since this function recurses, in principle we should check stack depth
852 : : * here. In practice, it's probably pointless since the earlier node
853 : : * initialization tree traversal would surely have consumed more stack.
854 : : */
855 : :
856 [ + + ]: 10982 : if (IsA(child_node, SortState))
857 : : {
858 : : /*
859 : : * If it is a Sort node, notify it that it can use bounded sort.
860 : : *
861 : : * Note: it is the responsibility of nodeSort.c to react properly to
862 : : * changes of these parameters. If we ever redesign this, it'd be a
863 : : * good idea to integrate this signaling with the parameter-change
864 : : * mechanism.
865 : : */
866 : 170 : SortState *sortState = (SortState *) child_node;
867 : :
868 [ + + ]: 170 : if (tuples_needed < 0)
869 : : {
870 : : /* make sure flag gets reset if needed upon rescan */
871 : 50 : sortState->bounded = false;
872 : 50 : }
873 : : else
874 : : {
875 : 120 : sortState->bounded = true;
876 : 120 : sortState->bound = tuples_needed;
877 : : }
878 : 170 : }
879 [ + + ]: 10812 : else if (IsA(child_node, IncrementalSortState))
880 : : {
881 : : /*
882 : : * If it is an IncrementalSort node, notify it that it can use bounded
883 : : * sort.
884 : : *
885 : : * Note: it is the responsibility of nodeIncrementalSort.c to react
886 : : * properly to changes of these parameters. If we ever redesign this,
887 : : * it'd be a good idea to integrate this signaling with the
888 : : * parameter-change mechanism.
889 : : */
890 : 24 : IncrementalSortState *sortState = (IncrementalSortState *) child_node;
891 : :
892 [ - + ]: 24 : if (tuples_needed < 0)
893 : : {
894 : : /* make sure flag gets reset if needed upon rescan */
895 : 0 : sortState->bounded = false;
896 : 0 : }
897 : : else
898 : : {
899 : 24 : sortState->bounded = true;
900 : 24 : sortState->bound = tuples_needed;
901 : : }
902 : 24 : }
903 [ + + ]: 10788 : else if (IsA(child_node, AppendState))
904 : : {
905 : : /*
906 : : * If it is an Append, we can apply the bound to any nodes that are
907 : : * children of the Append, since the Append surely need read no more
908 : : * than that many tuples from any one input.
909 : : */
910 : 21 : AppendState *aState = (AppendState *) child_node;
911 : 21 : int i;
912 : :
913 [ + + ]: 67 : for (i = 0; i < aState->as_nplans; i++)
914 : 46 : ExecSetTupleBound(tuples_needed, aState->appendplans[i]);
915 : 21 : }
916 [ + + ]: 10767 : else if (IsA(child_node, MergeAppendState))
917 : : {
918 : : /*
919 : : * If it is a MergeAppend, we can apply the bound to any nodes that
920 : : * are children of the MergeAppend, since the MergeAppend surely need
921 : : * read no more than that many tuples from any one input.
922 : : */
923 : 11 : MergeAppendState *maState = (MergeAppendState *) child_node;
924 : 11 : int i;
925 : :
926 [ + + ]: 44 : for (i = 0; i < maState->ms_nplans; i++)
927 : 33 : ExecSetTupleBound(tuples_needed, maState->mergeplans[i]);
928 : 11 : }
929 [ + + ]: 10756 : else if (IsA(child_node, ResultState))
930 : : {
931 : : /*
932 : : * Similarly, for a projecting Result, we can apply the bound to its
933 : : * child node.
934 : : *
935 : : * If Result supported qual checking, we'd have to punt on seeing a
936 : : * qual. Note that having a resconstantqual is not a showstopper: if
937 : : * that condition succeeds it affects nothing, while if it fails, no
938 : : * rows will be demanded from the Result child anyway.
939 : : */
940 [ + + ]: 101 : if (outerPlanState(child_node))
941 : 18 : ExecSetTupleBound(tuples_needed, outerPlanState(child_node));
942 : 101 : }
943 [ + + ]: 10655 : else if (IsA(child_node, SubqueryScanState))
944 : : {
945 : : /*
946 : : * We can also descend through SubqueryScan, but only if it has no
947 : : * qual (otherwise it might discard rows).
948 : : */
949 : 5 : SubqueryScanState *subqueryState = (SubqueryScanState *) child_node;
950 : :
951 [ + + ]: 5 : if (subqueryState->ss.ps.qual == NULL)
952 : 2 : ExecSetTupleBound(tuples_needed, subqueryState->subplan);
953 : 5 : }
954 [ - + ]: 10650 : else if (IsA(child_node, GatherState))
955 : : {
956 : : /*
957 : : * A Gather node can propagate the bound to its workers. As with
958 : : * MergeAppend, no one worker could possibly need to return more
959 : : * tuples than the Gather itself needs to.
960 : : *
961 : : * Note: As with Sort, the Gather node is responsible for reacting
962 : : * properly to changes to this parameter.
963 : : */
964 : 0 : GatherState *gstate = (GatherState *) child_node;
965 : :
966 : 0 : gstate->tuples_needed = tuples_needed;
967 : :
968 : : /* Also pass down the bound to our own copy of the child plan */
969 : 0 : ExecSetTupleBound(tuples_needed, outerPlanState(child_node));
970 : 0 : }
971 [ + + ]: 10650 : else if (IsA(child_node, GatherMergeState))
972 : : {
973 : : /* Same comments as for Gather */
974 : 5 : GatherMergeState *gstate = (GatherMergeState *) child_node;
975 : :
976 : 5 : gstate->tuples_needed = tuples_needed;
977 : :
978 : 5 : ExecSetTupleBound(tuples_needed, outerPlanState(child_node));
979 : 5 : }
980 : :
981 : : /*
982 : : * In principle we could descend through any plan node type that is
983 : : * certain not to discard or combine input rows; but on seeing a node that
984 : : * can do that, we can't propagate the bound any further. For the moment
985 : : * it's unclear that any other cases are worth checking here.
986 : : */
987 : 10982 : }
|