Age Owner Branch data TLA 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/instrument.h"
77 : : #include "executor/nodeAgg.h"
78 : : #include "executor/nodeAppend.h"
79 : : #include "executor/nodeBitmapAnd.h"
80 : : #include "executor/nodeBitmapHeapscan.h"
81 : : #include "executor/nodeBitmapIndexscan.h"
82 : : #include "executor/nodeBitmapOr.h"
83 : : #include "executor/nodeCtescan.h"
84 : : #include "executor/nodeCustom.h"
85 : : #include "executor/nodeForeignscan.h"
86 : : #include "executor/nodeFunctionscan.h"
87 : : #include "executor/nodeGather.h"
88 : : #include "executor/nodeGatherMerge.h"
89 : : #include "executor/nodeGroup.h"
90 : : #include "executor/nodeHash.h"
91 : : #include "executor/nodeHashjoin.h"
92 : : #include "executor/nodeIncrementalSort.h"
93 : : #include "executor/nodeIndexonlyscan.h"
94 : : #include "executor/nodeIndexscan.h"
95 : : #include "executor/nodeLimit.h"
96 : : #include "executor/nodeLockRows.h"
97 : : #include "executor/nodeMaterial.h"
98 : : #include "executor/nodeMemoize.h"
99 : : #include "executor/nodeMergeAppend.h"
100 : : #include "executor/nodeMergejoin.h"
101 : : #include "executor/nodeModifyTable.h"
102 : : #include "executor/nodeNamedtuplestorescan.h"
103 : : #include "executor/nodeNestloop.h"
104 : : #include "executor/nodeProjectSet.h"
105 : : #include "executor/nodeRecursiveunion.h"
106 : : #include "executor/nodeResult.h"
107 : : #include "executor/nodeSamplescan.h"
108 : : #include "executor/nodeSeqscan.h"
109 : : #include "executor/nodeSetOp.h"
110 : : #include "executor/nodeSort.h"
111 : : #include "executor/nodeSubplan.h"
112 : : #include "executor/nodeSubqueryscan.h"
113 : : #include "executor/nodeTableFuncscan.h"
114 : : #include "executor/nodeTidrangescan.h"
115 : : #include "executor/nodeTidscan.h"
116 : : #include "executor/nodeUnique.h"
117 : : #include "executor/nodeValuesscan.h"
118 : : #include "executor/nodeWindowAgg.h"
119 : : #include "executor/nodeWorktablescan.h"
120 : : #include "miscadmin.h"
121 : : #include "nodes/nodeFuncs.h"
122 : :
123 : : static TupleTableSlot *ExecProcNodeFirst(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 *
7371 tgl@sss.pgh.pa.us 142 :CBC 1058395 : ExecInitNode(Plan *node, EState *estate, int eflags)
143 : : {
144 : : PlanState *result;
145 : : List *subps;
146 : : ListCell *l;
147 : :
148 : : /*
149 : : * do nothing when we get to the end of a leaf on tree.
150 : : */
10467 bruce@momjian.us 151 [ + + ]: 1058395 : if (node == NULL)
8552 tgl@sss.pgh.pa.us 152 : 161246 : 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 : : */
3214 andres@anarazel.de 159 : 897149 : check_stack_depth();
160 : :
10467 bruce@momjian.us 161 [ + + + + : 897149 : switch (nodeTag(node))
+ + + + +
+ + + + +
+ + + + +
+ + + + +
- + + + +
+ + + + +
+ + + + +
+ + + - ]
162 : : {
163 : : /*
164 : : * control nodes
165 : : */
10466 166 : 168099 : case T_Result:
7371 tgl@sss.pgh.pa.us 167 : 168099 : result = (PlanState *) ExecInitResult((Result *) node,
168 : : estate, eflags);
10466 bruce@momjian.us 169 : 168059 : break;
170 : :
3394 andres@anarazel.de 171 : 10057 : case T_ProjectSet:
172 : 10057 : result = (PlanState *) ExecInitProjectSet((ProjectSet *) node,
173 : : estate, eflags);
174 : 10056 : break;
175 : :
6051 tgl@sss.pgh.pa.us 176 : 72701 : case T_ModifyTable:
177 : 72701 : result = (PlanState *) ExecInitModifyTable((ModifyTable *) node,
178 : : estate, eflags);
179 : 72461 : break;
180 : :
10466 bruce@momjian.us 181 : 12580 : case T_Append:
7371 tgl@sss.pgh.pa.us 182 : 12580 : result = (PlanState *) ExecInitAppend((Append *) node,
183 : : estate, eflags);
10466 bruce@momjian.us 184 : 12580 : break;
185 : :
5682 tgl@sss.pgh.pa.us 186 : 406 : case T_MergeAppend:
187 : 406 : result = (PlanState *) ExecInitMergeAppend((MergeAppend *) node,
188 : : estate, eflags);
189 : 406 : break;
190 : :
6422 191 : 617 : case T_RecursiveUnion:
192 : 617 : result = (PlanState *) ExecInitRecursiveUnion((RecursiveUnion *) node,
193 : : estate, eflags);
194 : 617 : break;
195 : :
7686 196 : 146 : case T_BitmapAnd:
7371 197 : 146 : result = (PlanState *) ExecInitBitmapAnd((BitmapAnd *) node,
198 : : estate, eflags);
7686 199 : 146 : break;
200 : :
201 : 254 : case T_BitmapOr:
7371 202 : 254 : result = (PlanState *) ExecInitBitmapOr((BitmapOr *) node,
203 : : estate, eflags);
7686 204 : 254 : break;
205 : :
206 : : /*
207 : : * scan nodes
208 : : */
10466 bruce@momjian.us 209 : 169446 : case T_SeqScan:
7371 tgl@sss.pgh.pa.us 210 : 169446 : result = (PlanState *) ExecInitSeqScan((SeqScan *) node,
211 : : estate, eflags);
10466 bruce@momjian.us 212 : 169438 : break;
213 : :
4008 simon@2ndQuadrant.co 214 : 200 : case T_SampleScan:
215 : 200 : result = (PlanState *) ExecInitSampleScan((SampleScan *) node,
216 : : estate, eflags);
217 : 200 : break;
218 : :
10466 bruce@momjian.us 219 : 105770 : case T_IndexScan:
7371 tgl@sss.pgh.pa.us 220 : 105770 : result = (PlanState *) ExecInitIndexScan((IndexScan *) node,
221 : : estate, eflags);
10466 bruce@momjian.us 222 : 105770 : break;
223 : :
5320 tgl@sss.pgh.pa.us 224 : 11608 : case T_IndexOnlyScan:
225 : 11608 : result = (PlanState *) ExecInitIndexOnlyScan((IndexOnlyScan *) node,
226 : : estate, eflags);
227 : 11608 : break;
228 : :
7686 229 : 16181 : case T_BitmapIndexScan:
7371 230 : 16181 : result = (PlanState *) ExecInitBitmapIndexScan((BitmapIndexScan *) node,
231 : : estate, eflags);
7686 232 : 16181 : break;
233 : :
234 : 15777 : case T_BitmapHeapScan:
7371 235 : 15777 : result = (PlanState *) ExecInitBitmapHeapScan((BitmapHeapScan *) node,
236 : : estate, eflags);
7686 237 : 15777 : break;
238 : :
9349 239 : 540 : case T_TidScan:
7371 240 : 540 : result = (PlanState *) ExecInitTidScan((TidScan *) node,
241 : : estate, eflags);
9349 242 : 540 : break;
243 : :
1893 drowley@postgresql.o 244 : 1398 : case T_TidRangeScan:
245 : 1398 : result = (PlanState *) ExecInitTidRangeScan((TidRangeScan *) node,
246 : : estate, eflags);
247 : 1398 : break;
248 : :
9349 tgl@sss.pgh.pa.us 249 : 14751 : case T_SubqueryScan:
7371 250 : 14751 : result = (PlanState *) ExecInitSubqueryScan((SubqueryScan *) node,
251 : : estate, eflags);
9349 252 : 14751 : break;
253 : :
8759 254 : 44397 : case T_FunctionScan:
7371 255 : 44397 : result = (PlanState *) ExecInitFunctionScan((FunctionScan *) node,
256 : : estate, eflags);
8759 257 : 44393 : break;
258 : :
3345 alvherre@alvh.no-ip. 259 : 414 : case T_TableFuncScan:
260 : 414 : result = (PlanState *) ExecInitTableFuncScan((TableFuncScan *) node,
261 : : estate, eflags);
262 : 414 : break;
263 : :
7216 mail@joeconway.com 264 : 6267 : case T_ValuesScan:
265 : 6267 : result = (PlanState *) ExecInitValuesScan((ValuesScan *) node,
266 : : estate, eflags);
267 : 6267 : break;
268 : :
6422 tgl@sss.pgh.pa.us 269 : 2675 : case T_CteScan:
270 : 2675 : result = (PlanState *) ExecInitCteScan((CteScan *) node,
271 : : estate, eflags);
272 : 2675 : break;
273 : :
3322 kgrittn@postgresql.o 274 : 530 : case T_NamedTuplestoreScan:
275 : 530 : result = (PlanState *) ExecInitNamedTuplestoreScan((NamedTuplestoreScan *) node,
276 : : estate, eflags);
277 : 530 : break;
278 : :
6422 tgl@sss.pgh.pa.us 279 : 617 : case T_WorkTableScan:
280 : 617 : result = (PlanState *) ExecInitWorkTableScan((WorkTableScan *) node,
281 : : estate, eflags);
282 : 617 : break;
283 : :
5553 284 : 1062 : case T_ForeignScan:
285 : 1062 : result = (PlanState *) ExecInitForeignScan((ForeignScan *) node,
286 : : estate, eflags);
287 : 1050 : break;
288 : :
4197 rhaas@postgresql.org 289 :UBC 0 : case T_CustomScan:
290 : 0 : result = (PlanState *) ExecInitCustomScan((CustomScan *) node,
291 : : estate, eflags);
292 : 0 : break;
293 : :
294 : : /*
295 : : * join nodes
296 : : */
10466 bruce@momjian.us 297 :CBC 69052 : case T_NestLoop:
7371 tgl@sss.pgh.pa.us 298 : 69052 : result = (PlanState *) ExecInitNestLoop((NestLoop *) node,
299 : : estate, eflags);
10466 bruce@momjian.us 300 : 69052 : break;
301 : :
302 : 4979 : case T_MergeJoin:
7371 tgl@sss.pgh.pa.us 303 : 4979 : result = (PlanState *) ExecInitMergeJoin((MergeJoin *) node,
304 : : estate, eflags);
9349 305 : 4979 : break;
306 : :
307 : 27387 : case T_HashJoin:
7371 308 : 27387 : result = (PlanState *) ExecInitHashJoin((HashJoin *) node,
309 : : estate, eflags);
9349 310 : 27387 : break;
311 : :
312 : : /*
313 : : * materialization nodes
314 : : */
10466 bruce@momjian.us 315 : 2832 : case T_Material:
7371 tgl@sss.pgh.pa.us 316 : 2832 : result = (PlanState *) ExecInitMaterial((Material *) node,
317 : : estate, eflags);
10466 bruce@momjian.us 318 : 2832 : break;
319 : :
320 : 55890 : case T_Sort:
7371 tgl@sss.pgh.pa.us 321 : 55890 : result = (PlanState *) ExecInitSort((Sort *) node,
322 : : estate, eflags);
10466 bruce@momjian.us 323 : 55886 : break;
324 : :
2220 tomas.vondra@postgre 325 : 639 : case T_IncrementalSort:
326 : 639 : result = (PlanState *) ExecInitIncrementalSort((IncrementalSort *) node,
327 : : estate, eflags);
328 : 639 : break;
329 : :
1756 drowley@postgresql.o 330 : 1367 : case T_Memoize:
331 : 1367 : result = (PlanState *) ExecInitMemoize((Memoize *) node, estate,
332 : : eflags);
1859 333 : 1367 : break;
334 : :
8552 tgl@sss.pgh.pa.us 335 : 166 : case T_Group:
7371 336 : 166 : result = (PlanState *) ExecInitGroup((Group *) node,
337 : : estate, eflags);
10466 bruce@momjian.us 338 : 166 : break;
339 : :
8552 tgl@sss.pgh.pa.us 340 : 34615 : case T_Agg:
7371 341 : 34615 : result = (PlanState *) ExecInitAgg((Agg *) node,
342 : : estate, eflags);
9343 343 : 34611 : break;
344 : :
6337 345 : 1910 : case T_WindowAgg:
346 : 1910 : result = (PlanState *) ExecInitWindowAgg((WindowAgg *) node,
347 : : estate, eflags);
348 : 1910 : break;
349 : :
8552 350 : 3577 : case T_Unique:
7371 351 : 3577 : result = (PlanState *) ExecInitUnique((Unique *) node,
352 : : estate, eflags);
9322 353 : 3577 : break;
354 : :
3870 rhaas@postgresql.org 355 : 780 : case T_Gather:
356 : 780 : result = (PlanState *) ExecInitGather((Gather *) node,
357 : : estate, eflags);
358 : 780 : break;
359 : :
3344 360 : 256 : case T_GatherMerge:
361 : 256 : result = (PlanState *) ExecInitGatherMerge((GatherMerge *) node,
362 : : estate, eflags);
363 : 256 : break;
364 : :
8552 tgl@sss.pgh.pa.us 365 : 27387 : case T_Hash:
7371 366 : 27387 : result = (PlanState *) ExecInitHash((Hash *) node,
367 : : estate, eflags);
10466 bruce@momjian.us 368 : 27387 : break;
369 : :
8552 tgl@sss.pgh.pa.us 370 : 480 : case T_SetOp:
7371 371 : 480 : result = (PlanState *) ExecInitSetOp((SetOp *) node,
372 : : estate, eflags);
8552 373 : 480 : break;
374 : :
6049 375 : 6163 : case T_LockRows:
376 : 6163 : result = (PlanState *) ExecInitLockRows((LockRows *) node,
377 : : estate, eflags);
378 : 6163 : break;
379 : :
8552 380 : 3176 : case T_Limit:
7371 381 : 3176 : result = (PlanState *) ExecInitLimit((Limit *) node,
382 : : estate, eflags);
10466 bruce@momjian.us 383 : 3176 : break;
384 : :
10466 bruce@momjian.us 385 :UBC 0 : default:
8324 tgl@sss.pgh.pa.us 386 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
387 : : result = NULL; /* keep compiler quiet */
388 : : break;
389 : : }
390 : :
3065 andres@anarazel.de 391 :CBC 896836 : 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 : : */
8552 tgl@sss.pgh.pa.us 401 : 896836 : subps = NIL;
8014 neilc@samurai.com 402 [ + + + + : 907102 : foreach(l, node->initPlan)
+ + ]
403 : : {
404 : 10266 : SubPlan *subplan = (SubPlan *) lfirst(l);
405 : : SubPlanState *sstate;
406 : :
8543 tgl@sss.pgh.pa.us 407 [ - + ]: 10266 : Assert(IsA(subplan, SubPlan));
643 andres@anarazel.de 408 [ - + ]: 10266 : Assert(subplan->args == NIL);
7007 tgl@sss.pgh.pa.us 409 : 10266 : sstate = ExecInitSubPlan(subplan, result);
8544 410 : 10266 : subps = lappend(subps, sstate);
411 : : }
8552 412 : 896836 : result->initPlan = subps;
413 : :
414 : : /* Set up instrumentation for this node if requested */
415 [ + + ]: 896836 : if (estate->es_instrument)
30 andres@anarazel.de 416 :GNC 6995 : result->instrument = InstrAllocNode(estate->es_instrument,
417 : 6995 : result->async_capable);
418 : :
10467 bruce@momjian.us 419 :CBC 896836 : return result;
420 : : }
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
3065 andres@anarazel.de 430 : 897132 : 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 : 897132 : node->ExecProcNodeReal = function;
439 : 897132 : node->ExecProcNode = ExecProcNodeFirst;
440 : 897132 : }
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 *
3214 448 : 741179 : 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 : 741179 : 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 : : */
8995 tgl@sss.pgh.pa.us 464 [ + + ]: 741179 : if (node->instrument)
3214 andres@anarazel.de 465 : 5435 : node->ExecProcNode = ExecProcNodeInstr;
466 : : else
467 : 735744 : node->ExecProcNode = node->ExecProcNodeReal;
468 : :
469 : 741179 : return node->ExecProcNode(node);
470 : : }
471 : :
472 : :
473 : :
474 : : /* ----------------------------------------------------------------
475 : : * MultiExecProcNode
476 : : *
477 : : * Execute a node that doesn't return individual tuples
478 : : * (it might return a hashtable, bitmap, etc). Caller should
479 : : * check it got back the expected kind of Node.
480 : : *
481 : : * This has essentially the same responsibilities as ExecProcNode,
482 : : * but it does not do InstrStartNode/InstrStopNode (mainly because
483 : : * it can't tell how many returned tuples to count). Each per-node
484 : : * function must provide its own instrumentation support.
485 : : * ----------------------------------------------------------------
486 : : */
487 : : Node *
7689 tgl@sss.pgh.pa.us 488 : 34351 : MultiExecProcNode(PlanState *node)
489 : : {
490 : : Node *result;
491 : :
3214 andres@anarazel.de 492 : 34351 : check_stack_depth();
493 : :
7689 tgl@sss.pgh.pa.us 494 [ - + ]: 34351 : CHECK_FOR_INTERRUPTS();
495 : :
496 [ + + ]: 34351 : if (node->chgParam != NULL) /* something changed */
5776 497 : 3690 : ExecReScan(node); /* let ReScan handle this */
498 : :
7689 499 [ + + + + : 34351 : switch (nodeTag(node))
- ]
500 : : {
501 : : /*
502 : : * Only node types that actually support multiexec will be listed
503 : : */
504 : :
505 : 18886 : case T_HashState:
506 : 18886 : result = MultiExecHash((HashState *) node);
507 : 18884 : break;
508 : :
7686 509 : 15174 : case T_BitmapIndexScanState:
510 : 15174 : result = MultiExecBitmapIndexScan((BitmapIndexScanState *) node);
511 : 15174 : break;
512 : :
513 : 114 : case T_BitmapAndState:
514 : 114 : result = MultiExecBitmapAnd((BitmapAndState *) node);
515 : 114 : break;
516 : :
517 : 177 : case T_BitmapOrState:
518 : 177 : result = MultiExecBitmapOr((BitmapOrState *) node);
519 : 177 : break;
520 : :
7689 tgl@sss.pgh.pa.us 521 :UBC 0 : default:
522 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
523 : : result = NULL;
524 : : break;
525 : : }
526 : :
7689 tgl@sss.pgh.pa.us 527 :CBC 34349 : return result;
528 : : }
529 : :
530 : :
531 : : /* ----------------------------------------------------------------
532 : : * ExecEndNode
533 : : *
534 : : * Recursively cleans up all the nodes in the plan rooted
535 : : * at 'node'.
536 : : *
537 : : * After this operation, the query plan will not be able to be
538 : : * processed any further. This should be called only after
539 : : * the query plan has been fully executed.
540 : : * ----------------------------------------------------------------
541 : : */
542 : : void
8306 bruce@momjian.us 543 : 1022187 : ExecEndNode(PlanState *node)
544 : : {
545 : : /*
546 : : * do nothing when we get to the end of a leaf on tree.
547 : : */
10467 548 [ + + ]: 1022187 : if (node == NULL)
549 : 149426 : return;
550 : :
551 : : /*
552 : : * Make sure there's enough stack available. Need to check here, in
553 : : * addition to ExecProcNode() (via ExecProcNodeFirst()), because it's not
554 : : * guaranteed that ExecProcNode() is reached for all nodes.
555 : : */
3214 andres@anarazel.de 556 : 872761 : check_stack_depth();
557 : :
8486 tgl@sss.pgh.pa.us 558 [ + + ]: 872761 : if (node->chgParam != NULL)
559 : : {
560 : 5348 : bms_free(node->chgParam);
561 : 5348 : node->chgParam = NULL;
562 : : }
563 : :
10467 bruce@momjian.us 564 [ + + + + : 872761 : switch (nodeTag(node))
+ + + + +
+ + + + +
+ + + + +
+ + + + -
+ + + + +
+ + + + +
+ + + + +
+ - ]
565 : : {
566 : : /*
567 : : * control nodes
568 : : */
8552 tgl@sss.pgh.pa.us 569 : 156300 : case T_ResultState:
570 : 156300 : ExecEndResult((ResultState *) node);
10466 bruce@momjian.us 571 : 156300 : break;
572 : :
3394 andres@anarazel.de 573 : 8917 : case T_ProjectSetState:
574 : 8917 : ExecEndProjectSet((ProjectSetState *) node);
575 : 8917 : break;
576 : :
6051 tgl@sss.pgh.pa.us 577 : 69388 : case T_ModifyTableState:
578 : 69388 : ExecEndModifyTable((ModifyTableState *) node);
579 : 69388 : break;
580 : :
8552 581 : 12379 : case T_AppendState:
582 : 12379 : ExecEndAppend((AppendState *) node);
10466 bruce@momjian.us 583 : 12379 : break;
584 : :
5682 tgl@sss.pgh.pa.us 585 : 406 : case T_MergeAppendState:
586 : 406 : ExecEndMergeAppend((MergeAppendState *) node);
587 : 406 : break;
588 : :
6422 589 : 617 : case T_RecursiveUnionState:
590 : 617 : ExecEndRecursiveUnion((RecursiveUnionState *) node);
591 : 617 : break;
592 : :
7686 593 : 146 : case T_BitmapAndState:
594 : 146 : ExecEndBitmapAnd((BitmapAndState *) node);
595 : 146 : break;
596 : :
597 : 254 : case T_BitmapOrState:
598 : 254 : ExecEndBitmapOr((BitmapOrState *) node);
599 : 254 : break;
600 : :
601 : : /*
602 : : * scan nodes
603 : : */
8552 604 : 167583 : case T_SeqScanState:
605 : 167583 : ExecEndSeqScan((SeqScanState *) node);
10466 bruce@momjian.us 606 : 167583 : break;
607 : :
4008 simon@2ndQuadrant.co 608 : 174 : case T_SampleScanState:
609 : 174 : ExecEndSampleScan((SampleScanState *) node);
610 : 174 : break;
611 : :
3870 rhaas@postgresql.org 612 : 772 : case T_GatherState:
613 : 772 : ExecEndGather((GatherState *) node);
614 : 772 : break;
615 : :
3344 616 : 256 : case T_GatherMergeState:
617 : 256 : ExecEndGatherMerge((GatherMergeState *) node);
618 : 256 : break;
619 : :
8552 tgl@sss.pgh.pa.us 620 : 105219 : case T_IndexScanState:
621 : 105219 : ExecEndIndexScan((IndexScanState *) node);
10466 bruce@momjian.us 622 : 105219 : break;
623 : :
5320 tgl@sss.pgh.pa.us 624 : 11575 : case T_IndexOnlyScanState:
625 : 11575 : ExecEndIndexOnlyScan((IndexOnlyScanState *) node);
626 : 11575 : break;
627 : :
7686 628 : 16100 : case T_BitmapIndexScanState:
629 : 16100 : ExecEndBitmapIndexScan((BitmapIndexScanState *) node);
630 : 16100 : break;
631 : :
632 : 15696 : case T_BitmapHeapScanState:
633 : 15696 : ExecEndBitmapHeapScan((BitmapHeapScanState *) node);
634 : 15696 : break;
635 : :
8552 636 : 445 : case T_TidScanState:
637 : 445 : ExecEndTidScan((TidScanState *) node);
9349 638 : 445 : break;
639 : :
1893 drowley@postgresql.o 640 : 243 : case T_TidRangeScanState:
641 : 243 : ExecEndTidRangeScan((TidRangeScanState *) node);
642 : 243 : break;
643 : :
8552 tgl@sss.pgh.pa.us 644 : 14745 : case T_SubqueryScanState:
645 : 14745 : ExecEndSubqueryScan((SubqueryScanState *) node);
9349 646 : 14745 : break;
647 : :
8552 648 : 41488 : case T_FunctionScanState:
649 : 41488 : ExecEndFunctionScan((FunctionScanState *) node);
8759 650 : 41488 : break;
651 : :
3345 alvherre@alvh.no-ip. 652 : 338 : case T_TableFuncScanState:
653 : 338 : ExecEndTableFuncScan((TableFuncScanState *) node);
654 : 338 : break;
655 : :
6422 tgl@sss.pgh.pa.us 656 : 2659 : case T_CteScanState:
657 : 2659 : ExecEndCteScan((CteScanState *) node);
658 : 2659 : break;
659 : :
5553 660 : 1010 : case T_ForeignScanState:
661 : 1010 : ExecEndForeignScan((ForeignScanState *) node);
662 : 1010 : break;
663 : :
4197 rhaas@postgresql.org 664 :UBC 0 : case T_CustomScanState:
665 : 0 : ExecEndCustomScan((CustomScanState *) node);
666 : 0 : break;
667 : :
668 : : /*
669 : : * join nodes
670 : : */
8552 tgl@sss.pgh.pa.us 671 :CBC 68906 : case T_NestLoopState:
672 : 68906 : ExecEndNestLoop((NestLoopState *) node);
10466 bruce@momjian.us 673 : 68906 : break;
674 : :
8552 tgl@sss.pgh.pa.us 675 : 4975 : case T_MergeJoinState:
676 : 4975 : ExecEndMergeJoin((MergeJoinState *) node);
9349 677 : 4975 : break;
678 : :
8552 679 : 27313 : case T_HashJoinState:
680 : 27313 : ExecEndHashJoin((HashJoinState *) node);
9349 681 : 27313 : break;
682 : :
683 : : /*
684 : : * materialization nodes
685 : : */
8552 686 : 2790 : case T_MaterialState:
687 : 2790 : ExecEndMaterial((MaterialState *) node);
10466 bruce@momjian.us 688 : 2790 : break;
689 : :
8552 tgl@sss.pgh.pa.us 690 : 55778 : case T_SortState:
691 : 55778 : ExecEndSort((SortState *) node);
10466 bruce@momjian.us 692 : 55778 : break;
693 : :
2220 tomas.vondra@postgre 694 : 639 : case T_IncrementalSortState:
695 : 639 : ExecEndIncrementalSort((IncrementalSortState *) node);
696 : 639 : break;
697 : :
1756 drowley@postgresql.o 698 : 1367 : case T_MemoizeState:
699 : 1367 : ExecEndMemoize((MemoizeState *) node);
1859 700 : 1367 : break;
701 : :
8552 tgl@sss.pgh.pa.us 702 : 166 : case T_GroupState:
703 : 166 : ExecEndGroup((GroupState *) node);
10466 bruce@momjian.us 704 : 166 : break;
705 : :
8552 tgl@sss.pgh.pa.us 706 : 34482 : case T_AggState:
707 : 34482 : ExecEndAgg((AggState *) node);
9343 708 : 34482 : break;
709 : :
6337 710 : 1774 : case T_WindowAggState:
711 : 1774 : ExecEndWindowAgg((WindowAggState *) node);
712 : 1774 : break;
713 : :
8552 714 : 3577 : case T_UniqueState:
715 : 3577 : ExecEndUnique((UniqueState *) node);
9322 716 : 3577 : break;
717 : :
8552 718 : 27313 : case T_HashState:
719 : 27313 : ExecEndHash((HashState *) node);
10466 bruce@momjian.us 720 : 27313 : break;
721 : :
8552 tgl@sss.pgh.pa.us 722 : 480 : case T_SetOpState:
723 : 480 : ExecEndSetOp((SetOpState *) node);
724 : 480 : break;
725 : :
6049 726 : 6105 : case T_LockRowsState:
727 : 6105 : ExecEndLockRows((LockRowsState *) node);
728 : 6105 : break;
729 : :
8552 730 : 3134 : case T_LimitState:
731 : 3134 : ExecEndLimit((LimitState *) node);
10466 bruce@momjian.us 732 : 3134 : break;
733 : :
734 : : /* No clean up actions for these nodes. */
950 amitlan@postgresql.o 735 : 7252 : case T_ValuesScanState:
736 : : case T_NamedTuplestoreScanState:
737 : : case T_WorkTableScanState:
738 : 7252 : break;
739 : :
10466 bruce@momjian.us 740 :UBC 0 : default:
8324 tgl@sss.pgh.pa.us 741 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
742 : : break;
743 : : }
744 : : }
745 : :
746 : : /*
747 : : * ExecShutdownNode
748 : : *
749 : : * Give execution nodes a chance to stop asynchronous resource consumption
750 : : * and release any resources still held.
751 : : */
752 : : void
3870 rhaas@postgresql.org 753 :CBC 333670 : ExecShutdownNode(PlanState *node)
754 : : {
1324 tgl@sss.pgh.pa.us 755 : 333670 : (void) ExecShutdownNode_walker(node, NULL);
756 : 333670 : }
757 : :
758 : : static bool
759 : 828992 : ExecShutdownNode_walker(PlanState *node, void *context)
760 : : {
3870 rhaas@postgresql.org 761 [ - + ]: 828992 : if (node == NULL)
3870 rhaas@postgresql.org 762 :UBC 0 : return false;
763 : :
3214 andres@anarazel.de 764 :CBC 828992 : check_stack_depth();
765 : :
766 : : /*
767 : : * Treat the node as running while we shut it down, but only if it's run
768 : : * at least once already. We don't expect much CPU consumption during
769 : : * node shutdown, but in the case of Gather or Gather Merge, we may shut
770 : : * down workers at this stage. If so, their buffer usage will get
771 : : * propagated into pgBufferUsage at this point, and we want to make sure
772 : : * that it gets associated with the Gather node. We skip this if the node
773 : : * has never been executed, so as to avoid incorrectly making it appear
774 : : * that it has.
775 : : */
2832 akapila@postgresql.o 776 [ + + + + ]: 828992 : if (node->instrument && node->instrument->running)
777 : 5950 : InstrStartNode(node->instrument);
778 : :
1324 tgl@sss.pgh.pa.us 779 : 828992 : planstate_tree_walker(node, ExecShutdownNode_walker, context);
780 : :
3870 rhaas@postgresql.org 781 [ + + - + : 828992 : switch (nodeTag(node))
+ + + ]
782 : : {
783 : 448 : case T_GatherState:
3848 784 : 448 : ExecShutdownGather((GatherState *) node);
3870 785 : 448 : break;
3355 786 : 586 : case T_ForeignScanState:
787 : 586 : ExecShutdownForeignScan((ForeignScanState *) node);
788 : 586 : break;
3355 rhaas@postgresql.org 789 :UBC 0 : case T_CustomScanState:
790 : 0 : ExecShutdownCustomScan((CustomScanState *) node);
791 : 0 : break;
3344 rhaas@postgresql.org 792 :CBC 104 : case T_GatherMergeState:
793 : 104 : ExecShutdownGatherMerge((GatherMergeState *) node);
794 : 104 : break;
3073 andres@anarazel.de 795 : 24492 : case T_HashState:
796 : 24492 : ExecShutdownHash((HashState *) node);
797 : 24492 : break;
3058 798 : 24492 : case T_HashJoinState:
799 : 24492 : ExecShutdownHashJoin((HashJoinState *) node);
800 : 24492 : break;
3870 rhaas@postgresql.org 801 : 778870 : default:
802 : 778870 : break;
803 : : }
804 : :
805 : : /* Stop the node if we started it above, reporting 0 tuples. */
2832 akapila@postgresql.o 806 [ + + + + ]: 828992 : if (node->instrument && node->instrument->running)
807 : 5950 : InstrStopNode(node->instrument, 0);
808 : :
3359 rhaas@postgresql.org 809 : 828992 : return false;
810 : : }
811 : :
812 : : /*
813 : : * ExecSetTupleBound
814 : : *
815 : : * Set a tuple bound for a planstate node. This lets child plan nodes
816 : : * optimize based on the knowledge that the maximum number of tuples that
817 : : * their parent will demand is limited. The tuple bound for a node may
818 : : * only be changed between scans (i.e., after node initialization or just
819 : : * before an ExecReScan call).
820 : : *
821 : : * Any negative tuples_needed value means "no limit", which should be the
822 : : * default assumption when this is not called at all for a particular node.
823 : : *
824 : : * Note: if this is called repeatedly on a plan tree, the exact same set
825 : : * of nodes must be updated with the new limit each time; be careful that
826 : : * only unchanging conditions are tested here.
827 : : */
828 : : void
3171 829 : 45065 : ExecSetTupleBound(int64 tuples_needed, PlanState *child_node)
830 : : {
831 : : /*
832 : : * Since this function recurses, in principle we should check stack depth
833 : : * here. In practice, it's probably pointless since the earlier node
834 : : * initialization tree traversal would surely have consumed more stack.
835 : : */
836 : :
837 [ + + ]: 45065 : if (IsA(child_node, SortState))
838 : : {
839 : : /*
840 : : * If it is a Sort node, notify it that it can use bounded sort.
841 : : *
842 : : * Note: it is the responsibility of nodeSort.c to react properly to
843 : : * changes of these parameters. If we ever redesign this, it'd be a
844 : : * good idea to integrate this signaling with the parameter-change
845 : : * mechanism.
846 : : */
847 : 856 : SortState *sortState = (SortState *) child_node;
848 : :
2220 tomas.vondra@postgre 849 [ + + ]: 856 : if (tuples_needed < 0)
850 : : {
851 : : /* make sure flag gets reset if needed upon rescan */
852 : 234 : sortState->bounded = false;
853 : : }
854 : : else
855 : : {
856 : 622 : sortState->bounded = true;
857 : 622 : sortState->bound = tuples_needed;
858 : : }
859 : : }
860 [ + + ]: 44209 : else if (IsA(child_node, IncrementalSortState))
861 : : {
862 : : /*
863 : : * If it is an IncrementalSort node, notify it that it can use bounded
864 : : * sort.
865 : : *
866 : : * Note: it is the responsibility of nodeIncrementalSort.c to react
867 : : * properly to changes of these parameters. If we ever redesign this,
868 : : * it'd be a good idea to integrate this signaling with the
869 : : * parameter-change mechanism.
870 : : */
871 : 97 : IncrementalSortState *sortState = (IncrementalSortState *) child_node;
872 : :
3171 rhaas@postgresql.org 873 [ - + ]: 97 : if (tuples_needed < 0)
874 : : {
875 : : /* make sure flag gets reset if needed upon rescan */
3171 rhaas@postgresql.org 876 :UBC 0 : sortState->bounded = false;
877 : : }
878 : : else
879 : : {
3171 rhaas@postgresql.org 880 :CBC 97 : sortState->bounded = true;
881 : 97 : sortState->bound = tuples_needed;
882 : : }
883 : : }
2587 tgl@sss.pgh.pa.us 884 [ + + ]: 44112 : else if (IsA(child_node, AppendState))
885 : : {
886 : : /*
887 : : * If it is an Append, we can apply the bound to any nodes that are
888 : : * children of the Append, since the Append surely need read no more
889 : : * than that many tuples from any one input.
890 : : */
891 : 105 : AppendState *aState = (AppendState *) child_node;
892 : : int i;
893 : :
894 [ + + ]: 333 : for (i = 0; i < aState->as_nplans; i++)
895 : 228 : ExecSetTupleBound(tuples_needed, aState->appendplans[i]);
896 : : }
3171 rhaas@postgresql.org 897 [ + + ]: 44007 : else if (IsA(child_node, MergeAppendState))
898 : : {
899 : : /*
900 : : * If it is a MergeAppend, we can apply the bound to any nodes that
901 : : * are children of the MergeAppend, since the MergeAppend surely need
902 : : * read no more than that many tuples from any one input.
903 : : */
904 : 44 : MergeAppendState *maState = (MergeAppendState *) child_node;
905 : : int i;
906 : :
907 [ + + ]: 176 : for (i = 0; i < maState->ms_nplans; i++)
908 : 132 : ExecSetTupleBound(tuples_needed, maState->mergeplans[i]);
909 : : }
910 [ + + ]: 43963 : else if (IsA(child_node, ResultState))
911 : : {
912 : : /*
913 : : * Similarly, for a projecting Result, we can apply the bound to its
914 : : * child node.
915 : : *
916 : : * If Result supported qual checking, we'd have to punt on seeing a
917 : : * qual. Note that having a resconstantqual is not a showstopper: if
918 : : * that condition succeeds it affects nothing, while if it fails, no
919 : : * rows will be demanded from the Result child anyway.
920 : : */
921 [ + + ]: 443 : if (outerPlanState(child_node))
922 : 87 : ExecSetTupleBound(tuples_needed, outerPlanState(child_node));
923 : : }
924 [ + + ]: 43520 : else if (IsA(child_node, SubqueryScanState))
925 : : {
926 : : /*
927 : : * We can also descend through SubqueryScan, but only if it has no
928 : : * qual (otherwise it might discard rows).
929 : : */
930 : 52 : SubqueryScanState *subqueryState = (SubqueryScanState *) child_node;
931 : :
932 [ + + ]: 52 : if (subqueryState->ss.ps.qual == NULL)
933 : 38 : ExecSetTupleBound(tuples_needed, subqueryState->subplan);
934 : : }
935 [ - + ]: 43468 : else if (IsA(child_node, GatherState))
936 : : {
937 : : /*
938 : : * A Gather node can propagate the bound to its workers. As with
939 : : * MergeAppend, no one worker could possibly need to return more
940 : : * tuples than the Gather itself needs to.
941 : : *
942 : : * Note: As with Sort, the Gather node is responsible for reacting
943 : : * properly to changes to this parameter.
944 : : */
3171 rhaas@postgresql.org 945 :UBC 0 : GatherState *gstate = (GatherState *) child_node;
946 : :
947 : 0 : gstate->tuples_needed = tuples_needed;
948 : :
949 : : /* Also pass down the bound to our own copy of the child plan */
950 : 0 : ExecSetTupleBound(tuples_needed, outerPlanState(child_node));
951 : : }
3171 rhaas@postgresql.org 952 [ + + ]:CBC 43468 : else if (IsA(child_node, GatherMergeState))
953 : : {
954 : : /* Same comments as for Gather */
955 : 20 : GatherMergeState *gstate = (GatherMergeState *) child_node;
956 : :
957 : 20 : gstate->tuples_needed = tuples_needed;
958 : :
959 : 20 : ExecSetTupleBound(tuples_needed, outerPlanState(child_node));
960 : : }
961 : :
962 : : /*
963 : : * In principle we could descend through any plan node type that is
964 : : * certain not to discard or combine input rows; but on seeing a node that
965 : : * can do that, we can't propagate the bound any further. For the moment
966 : : * it's unclear that any other cases are worth checking here.
967 : : */
968 : 45065 : }
|