/src/postgres/src/backend/executor/execProcnode.c
Line | Count | Source |
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 * |
142 | | ExecInitNode(Plan *node, EState *estate, int eflags) |
143 | 0 | { |
144 | 0 | PlanState *result; |
145 | 0 | List *subps; |
146 | 0 | ListCell *l; |
147 | | |
148 | | /* |
149 | | * do nothing when we get to the end of a leaf on tree. |
150 | | */ |
151 | 0 | if (node == NULL) |
152 | 0 | 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 | 0 | check_stack_depth(); |
160 | |
|
161 | 0 | switch (nodeTag(node)) |
162 | 0 | { |
163 | | /* |
164 | | * control nodes |
165 | | */ |
166 | 0 | case T_Result: |
167 | 0 | result = (PlanState *) ExecInitResult((Result *) node, |
168 | 0 | estate, eflags); |
169 | 0 | break; |
170 | | |
171 | 0 | case T_ProjectSet: |
172 | 0 | result = (PlanState *) ExecInitProjectSet((ProjectSet *) node, |
173 | 0 | estate, eflags); |
174 | 0 | break; |
175 | | |
176 | 0 | case T_ModifyTable: |
177 | 0 | result = (PlanState *) ExecInitModifyTable((ModifyTable *) node, |
178 | 0 | estate, eflags); |
179 | 0 | break; |
180 | | |
181 | 0 | case T_Append: |
182 | 0 | result = (PlanState *) ExecInitAppend((Append *) node, |
183 | 0 | estate, eflags); |
184 | 0 | break; |
185 | | |
186 | 0 | case T_MergeAppend: |
187 | 0 | result = (PlanState *) ExecInitMergeAppend((MergeAppend *) node, |
188 | 0 | estate, eflags); |
189 | 0 | break; |
190 | | |
191 | 0 | case T_RecursiveUnion: |
192 | 0 | result = (PlanState *) ExecInitRecursiveUnion((RecursiveUnion *) node, |
193 | 0 | estate, eflags); |
194 | 0 | break; |
195 | | |
196 | 0 | case T_BitmapAnd: |
197 | 0 | result = (PlanState *) ExecInitBitmapAnd((BitmapAnd *) node, |
198 | 0 | estate, eflags); |
199 | 0 | break; |
200 | | |
201 | 0 | case T_BitmapOr: |
202 | 0 | result = (PlanState *) ExecInitBitmapOr((BitmapOr *) node, |
203 | 0 | estate, eflags); |
204 | 0 | break; |
205 | | |
206 | | /* |
207 | | * scan nodes |
208 | | */ |
209 | 0 | case T_SeqScan: |
210 | 0 | result = (PlanState *) ExecInitSeqScan((SeqScan *) node, |
211 | 0 | estate, eflags); |
212 | 0 | break; |
213 | | |
214 | 0 | case T_SampleScan: |
215 | 0 | result = (PlanState *) ExecInitSampleScan((SampleScan *) node, |
216 | 0 | estate, eflags); |
217 | 0 | break; |
218 | | |
219 | 0 | case T_IndexScan: |
220 | 0 | result = (PlanState *) ExecInitIndexScan((IndexScan *) node, |
221 | 0 | estate, eflags); |
222 | 0 | break; |
223 | | |
224 | 0 | case T_IndexOnlyScan: |
225 | 0 | result = (PlanState *) ExecInitIndexOnlyScan((IndexOnlyScan *) node, |
226 | 0 | estate, eflags); |
227 | 0 | break; |
228 | | |
229 | 0 | case T_BitmapIndexScan: |
230 | 0 | result = (PlanState *) ExecInitBitmapIndexScan((BitmapIndexScan *) node, |
231 | 0 | estate, eflags); |
232 | 0 | break; |
233 | | |
234 | 0 | case T_BitmapHeapScan: |
235 | 0 | result = (PlanState *) ExecInitBitmapHeapScan((BitmapHeapScan *) node, |
236 | 0 | estate, eflags); |
237 | 0 | break; |
238 | | |
239 | 0 | case T_TidScan: |
240 | 0 | result = (PlanState *) ExecInitTidScan((TidScan *) node, |
241 | 0 | estate, eflags); |
242 | 0 | break; |
243 | | |
244 | 0 | case T_TidRangeScan: |
245 | 0 | result = (PlanState *) ExecInitTidRangeScan((TidRangeScan *) node, |
246 | 0 | estate, eflags); |
247 | 0 | break; |
248 | | |
249 | 0 | case T_SubqueryScan: |
250 | 0 | result = (PlanState *) ExecInitSubqueryScan((SubqueryScan *) node, |
251 | 0 | estate, eflags); |
252 | 0 | break; |
253 | | |
254 | 0 | case T_FunctionScan: |
255 | 0 | result = (PlanState *) ExecInitFunctionScan((FunctionScan *) node, |
256 | 0 | estate, eflags); |
257 | 0 | break; |
258 | | |
259 | 0 | case T_TableFuncScan: |
260 | 0 | result = (PlanState *) ExecInitTableFuncScan((TableFuncScan *) node, |
261 | 0 | estate, eflags); |
262 | 0 | break; |
263 | | |
264 | 0 | case T_ValuesScan: |
265 | 0 | result = (PlanState *) ExecInitValuesScan((ValuesScan *) node, |
266 | 0 | estate, eflags); |
267 | 0 | break; |
268 | | |
269 | 0 | case T_CteScan: |
270 | 0 | result = (PlanState *) ExecInitCteScan((CteScan *) node, |
271 | 0 | estate, eflags); |
272 | 0 | break; |
273 | | |
274 | 0 | case T_NamedTuplestoreScan: |
275 | 0 | result = (PlanState *) ExecInitNamedTuplestoreScan((NamedTuplestoreScan *) node, |
276 | 0 | estate, eflags); |
277 | 0 | break; |
278 | | |
279 | 0 | case T_WorkTableScan: |
280 | 0 | result = (PlanState *) ExecInitWorkTableScan((WorkTableScan *) node, |
281 | 0 | estate, eflags); |
282 | 0 | break; |
283 | | |
284 | 0 | case T_ForeignScan: |
285 | 0 | result = (PlanState *) ExecInitForeignScan((ForeignScan *) node, |
286 | 0 | estate, eflags); |
287 | 0 | break; |
288 | | |
289 | 0 | case T_CustomScan: |
290 | 0 | result = (PlanState *) ExecInitCustomScan((CustomScan *) node, |
291 | 0 | estate, eflags); |
292 | 0 | break; |
293 | | |
294 | | /* |
295 | | * join nodes |
296 | | */ |
297 | 0 | case T_NestLoop: |
298 | 0 | result = (PlanState *) ExecInitNestLoop((NestLoop *) node, |
299 | 0 | estate, eflags); |
300 | 0 | break; |
301 | | |
302 | 0 | case T_MergeJoin: |
303 | 0 | result = (PlanState *) ExecInitMergeJoin((MergeJoin *) node, |
304 | 0 | estate, eflags); |
305 | 0 | break; |
306 | | |
307 | 0 | case T_HashJoin: |
308 | 0 | result = (PlanState *) ExecInitHashJoin((HashJoin *) node, |
309 | 0 | estate, eflags); |
310 | 0 | break; |
311 | | |
312 | | /* |
313 | | * materialization nodes |
314 | | */ |
315 | 0 | case T_Material: |
316 | 0 | result = (PlanState *) ExecInitMaterial((Material *) node, |
317 | 0 | estate, eflags); |
318 | 0 | break; |
319 | | |
320 | 0 | case T_Sort: |
321 | 0 | result = (PlanState *) ExecInitSort((Sort *) node, |
322 | 0 | estate, eflags); |
323 | 0 | break; |
324 | | |
325 | 0 | case T_IncrementalSort: |
326 | 0 | result = (PlanState *) ExecInitIncrementalSort((IncrementalSort *) node, |
327 | 0 | estate, eflags); |
328 | 0 | break; |
329 | | |
330 | 0 | case T_Memoize: |
331 | 0 | result = (PlanState *) ExecInitMemoize((Memoize *) node, estate, |
332 | 0 | eflags); |
333 | 0 | break; |
334 | | |
335 | 0 | case T_Group: |
336 | 0 | result = (PlanState *) ExecInitGroup((Group *) node, |
337 | 0 | estate, eflags); |
338 | 0 | break; |
339 | | |
340 | 0 | case T_Agg: |
341 | 0 | result = (PlanState *) ExecInitAgg((Agg *) node, |
342 | 0 | estate, eflags); |
343 | 0 | break; |
344 | | |
345 | 0 | case T_WindowAgg: |
346 | 0 | result = (PlanState *) ExecInitWindowAgg((WindowAgg *) node, |
347 | 0 | estate, eflags); |
348 | 0 | break; |
349 | | |
350 | 0 | case T_Unique: |
351 | 0 | result = (PlanState *) ExecInitUnique((Unique *) node, |
352 | 0 | estate, eflags); |
353 | 0 | break; |
354 | | |
355 | 0 | case T_Gather: |
356 | 0 | result = (PlanState *) ExecInitGather((Gather *) node, |
357 | 0 | estate, eflags); |
358 | 0 | break; |
359 | | |
360 | 0 | case T_GatherMerge: |
361 | 0 | result = (PlanState *) ExecInitGatherMerge((GatherMerge *) node, |
362 | 0 | estate, eflags); |
363 | 0 | break; |
364 | | |
365 | 0 | case T_Hash: |
366 | 0 | result = (PlanState *) ExecInitHash((Hash *) node, |
367 | 0 | estate, eflags); |
368 | 0 | break; |
369 | | |
370 | 0 | case T_SetOp: |
371 | 0 | result = (PlanState *) ExecInitSetOp((SetOp *) node, |
372 | 0 | estate, eflags); |
373 | 0 | break; |
374 | | |
375 | 0 | case T_LockRows: |
376 | 0 | result = (PlanState *) ExecInitLockRows((LockRows *) node, |
377 | 0 | estate, eflags); |
378 | 0 | break; |
379 | | |
380 | 0 | case T_Limit: |
381 | 0 | result = (PlanState *) ExecInitLimit((Limit *) node, |
382 | 0 | estate, eflags); |
383 | 0 | break; |
384 | | |
385 | 0 | default: |
386 | 0 | elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); |
387 | 0 | result = NULL; /* keep compiler quiet */ |
388 | 0 | break; |
389 | 0 | } |
390 | | |
391 | 0 | 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 | 0 | subps = NIL; |
402 | 0 | foreach(l, node->initPlan) |
403 | 0 | { |
404 | 0 | SubPlan *subplan = (SubPlan *) lfirst(l); |
405 | 0 | SubPlanState *sstate; |
406 | |
|
407 | 0 | Assert(IsA(subplan, SubPlan)); |
408 | 0 | Assert(subplan->args == NIL); |
409 | 0 | sstate = ExecInitSubPlan(subplan, result); |
410 | 0 | subps = lappend(subps, sstate); |
411 | 0 | } |
412 | 0 | result->initPlan = subps; |
413 | | |
414 | | /* Set up instrumentation for this node if requested */ |
415 | 0 | if (estate->es_instrument) |
416 | 0 | result->instrument = InstrAllocNode(estate->es_instrument, |
417 | 0 | result->async_capable); |
418 | |
|
419 | 0 | return result; |
420 | 0 | } |
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 | | ExecSetExecProcNode(PlanState *node, ExecProcNodeMtd function) |
431 | 0 | { |
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 | 0 | node->ExecProcNodeReal = function; |
439 | 0 | node->ExecProcNode = ExecProcNodeFirst; |
440 | 0 | } |
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 | | ExecProcNodeFirst(PlanState *node) |
449 | 0 | { |
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 | 0 | 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 | 0 | if (node->instrument) |
465 | 0 | node->ExecProcNode = ExecProcNodeInstr; |
466 | 0 | else |
467 | 0 | node->ExecProcNode = node->ExecProcNodeReal; |
468 | |
|
469 | 0 | return node->ExecProcNode(node); |
470 | 0 | } |
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 * |
488 | | MultiExecProcNode(PlanState *node) |
489 | 0 | { |
490 | 0 | Node *result; |
491 | |
|
492 | 0 | check_stack_depth(); |
493 | |
|
494 | 0 | CHECK_FOR_INTERRUPTS(); |
495 | |
|
496 | 0 | if (node->chgParam != NULL) /* something changed */ |
497 | 0 | ExecReScan(node); /* let ReScan handle this */ |
498 | |
|
499 | 0 | switch (nodeTag(node)) |
500 | 0 | { |
501 | | /* |
502 | | * Only node types that actually support multiexec will be listed |
503 | | */ |
504 | | |
505 | 0 | case T_HashState: |
506 | 0 | result = MultiExecHash((HashState *) node); |
507 | 0 | break; |
508 | | |
509 | 0 | case T_BitmapIndexScanState: |
510 | 0 | result = MultiExecBitmapIndexScan((BitmapIndexScanState *) node); |
511 | 0 | break; |
512 | | |
513 | 0 | case T_BitmapAndState: |
514 | 0 | result = MultiExecBitmapAnd((BitmapAndState *) node); |
515 | 0 | break; |
516 | | |
517 | 0 | case T_BitmapOrState: |
518 | 0 | result = MultiExecBitmapOr((BitmapOrState *) node); |
519 | 0 | break; |
520 | | |
521 | 0 | default: |
522 | 0 | elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); |
523 | 0 | result = NULL; |
524 | 0 | break; |
525 | 0 | } |
526 | | |
527 | 0 | return result; |
528 | 0 | } |
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 |
543 | | ExecEndNode(PlanState *node) |
544 | 0 | { |
545 | | /* |
546 | | * do nothing when we get to the end of a leaf on tree. |
547 | | */ |
548 | 0 | if (node == NULL) |
549 | 0 | 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 | | */ |
556 | 0 | check_stack_depth(); |
557 | |
|
558 | 0 | if (node->chgParam != NULL) |
559 | 0 | { |
560 | 0 | bms_free(node->chgParam); |
561 | 0 | node->chgParam = NULL; |
562 | 0 | } |
563 | |
|
564 | 0 | switch (nodeTag(node)) |
565 | 0 | { |
566 | | /* |
567 | | * control nodes |
568 | | */ |
569 | 0 | case T_ResultState: |
570 | 0 | ExecEndResult((ResultState *) node); |
571 | 0 | break; |
572 | | |
573 | 0 | case T_ProjectSetState: |
574 | 0 | ExecEndProjectSet((ProjectSetState *) node); |
575 | 0 | break; |
576 | | |
577 | 0 | case T_ModifyTableState: |
578 | 0 | ExecEndModifyTable((ModifyTableState *) node); |
579 | 0 | break; |
580 | | |
581 | 0 | case T_AppendState: |
582 | 0 | ExecEndAppend((AppendState *) node); |
583 | 0 | break; |
584 | | |
585 | 0 | case T_MergeAppendState: |
586 | 0 | ExecEndMergeAppend((MergeAppendState *) node); |
587 | 0 | break; |
588 | | |
589 | 0 | case T_RecursiveUnionState: |
590 | 0 | ExecEndRecursiveUnion((RecursiveUnionState *) node); |
591 | 0 | break; |
592 | | |
593 | 0 | case T_BitmapAndState: |
594 | 0 | ExecEndBitmapAnd((BitmapAndState *) node); |
595 | 0 | break; |
596 | | |
597 | 0 | case T_BitmapOrState: |
598 | 0 | ExecEndBitmapOr((BitmapOrState *) node); |
599 | 0 | break; |
600 | | |
601 | | /* |
602 | | * scan nodes |
603 | | */ |
604 | 0 | case T_SeqScanState: |
605 | 0 | ExecEndSeqScan((SeqScanState *) node); |
606 | 0 | break; |
607 | | |
608 | 0 | case T_SampleScanState: |
609 | 0 | ExecEndSampleScan((SampleScanState *) node); |
610 | 0 | break; |
611 | | |
612 | 0 | case T_GatherState: |
613 | 0 | ExecEndGather((GatherState *) node); |
614 | 0 | break; |
615 | | |
616 | 0 | case T_GatherMergeState: |
617 | 0 | ExecEndGatherMerge((GatherMergeState *) node); |
618 | 0 | break; |
619 | | |
620 | 0 | case T_IndexScanState: |
621 | 0 | ExecEndIndexScan((IndexScanState *) node); |
622 | 0 | break; |
623 | | |
624 | 0 | case T_IndexOnlyScanState: |
625 | 0 | ExecEndIndexOnlyScan((IndexOnlyScanState *) node); |
626 | 0 | break; |
627 | | |
628 | 0 | case T_BitmapIndexScanState: |
629 | 0 | ExecEndBitmapIndexScan((BitmapIndexScanState *) node); |
630 | 0 | break; |
631 | | |
632 | 0 | case T_BitmapHeapScanState: |
633 | 0 | ExecEndBitmapHeapScan((BitmapHeapScanState *) node); |
634 | 0 | break; |
635 | | |
636 | 0 | case T_TidScanState: |
637 | 0 | ExecEndTidScan((TidScanState *) node); |
638 | 0 | break; |
639 | | |
640 | 0 | case T_TidRangeScanState: |
641 | 0 | ExecEndTidRangeScan((TidRangeScanState *) node); |
642 | 0 | break; |
643 | | |
644 | 0 | case T_SubqueryScanState: |
645 | 0 | ExecEndSubqueryScan((SubqueryScanState *) node); |
646 | 0 | break; |
647 | | |
648 | 0 | case T_FunctionScanState: |
649 | 0 | ExecEndFunctionScan((FunctionScanState *) node); |
650 | 0 | break; |
651 | | |
652 | 0 | case T_TableFuncScanState: |
653 | 0 | ExecEndTableFuncScan((TableFuncScanState *) node); |
654 | 0 | break; |
655 | | |
656 | 0 | case T_CteScanState: |
657 | 0 | ExecEndCteScan((CteScanState *) node); |
658 | 0 | break; |
659 | | |
660 | 0 | case T_ForeignScanState: |
661 | 0 | ExecEndForeignScan((ForeignScanState *) node); |
662 | 0 | break; |
663 | | |
664 | 0 | case T_CustomScanState: |
665 | 0 | ExecEndCustomScan((CustomScanState *) node); |
666 | 0 | break; |
667 | | |
668 | | /* |
669 | | * join nodes |
670 | | */ |
671 | 0 | case T_NestLoopState: |
672 | 0 | ExecEndNestLoop((NestLoopState *) node); |
673 | 0 | break; |
674 | | |
675 | 0 | case T_MergeJoinState: |
676 | 0 | ExecEndMergeJoin((MergeJoinState *) node); |
677 | 0 | break; |
678 | | |
679 | 0 | case T_HashJoinState: |
680 | 0 | ExecEndHashJoin((HashJoinState *) node); |
681 | 0 | break; |
682 | | |
683 | | /* |
684 | | * materialization nodes |
685 | | */ |
686 | 0 | case T_MaterialState: |
687 | 0 | ExecEndMaterial((MaterialState *) node); |
688 | 0 | break; |
689 | | |
690 | 0 | case T_SortState: |
691 | 0 | ExecEndSort((SortState *) node); |
692 | 0 | break; |
693 | | |
694 | 0 | case T_IncrementalSortState: |
695 | 0 | ExecEndIncrementalSort((IncrementalSortState *) node); |
696 | 0 | break; |
697 | | |
698 | 0 | case T_MemoizeState: |
699 | 0 | ExecEndMemoize((MemoizeState *) node); |
700 | 0 | break; |
701 | | |
702 | 0 | case T_GroupState: |
703 | 0 | ExecEndGroup((GroupState *) node); |
704 | 0 | break; |
705 | | |
706 | 0 | case T_AggState: |
707 | 0 | ExecEndAgg((AggState *) node); |
708 | 0 | break; |
709 | | |
710 | 0 | case T_WindowAggState: |
711 | 0 | ExecEndWindowAgg((WindowAggState *) node); |
712 | 0 | break; |
713 | | |
714 | 0 | case T_UniqueState: |
715 | 0 | ExecEndUnique((UniqueState *) node); |
716 | 0 | break; |
717 | | |
718 | 0 | case T_HashState: |
719 | 0 | ExecEndHash((HashState *) node); |
720 | 0 | break; |
721 | | |
722 | 0 | case T_SetOpState: |
723 | 0 | ExecEndSetOp((SetOpState *) node); |
724 | 0 | break; |
725 | | |
726 | 0 | case T_LockRowsState: |
727 | 0 | ExecEndLockRows((LockRowsState *) node); |
728 | 0 | break; |
729 | | |
730 | 0 | case T_LimitState: |
731 | 0 | ExecEndLimit((LimitState *) node); |
732 | 0 | break; |
733 | | |
734 | | /* No clean up actions for these nodes. */ |
735 | 0 | case T_ValuesScanState: |
736 | 0 | case T_NamedTuplestoreScanState: |
737 | 0 | case T_WorkTableScanState: |
738 | 0 | break; |
739 | | |
740 | 0 | default: |
741 | 0 | elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); |
742 | 0 | break; |
743 | 0 | } |
744 | 0 | } |
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 |
753 | | ExecShutdownNode(PlanState *node) |
754 | 0 | { |
755 | 0 | (void) ExecShutdownNode_walker(node, NULL); |
756 | 0 | } |
757 | | |
758 | | static bool |
759 | | ExecShutdownNode_walker(PlanState *node, void *context) |
760 | 0 | { |
761 | 0 | if (node == NULL) |
762 | 0 | return false; |
763 | | |
764 | 0 | 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 | | */ |
776 | 0 | if (node->instrument && node->instrument->running) |
777 | 0 | InstrStartNode(node->instrument); |
778 | |
|
779 | 0 | planstate_tree_walker(node, ExecShutdownNode_walker, context); |
780 | |
|
781 | 0 | switch (nodeTag(node)) |
782 | 0 | { |
783 | 0 | case T_GatherState: |
784 | 0 | ExecShutdownGather((GatherState *) node); |
785 | 0 | break; |
786 | 0 | case T_ForeignScanState: |
787 | 0 | ExecShutdownForeignScan((ForeignScanState *) node); |
788 | 0 | break; |
789 | 0 | case T_CustomScanState: |
790 | 0 | ExecShutdownCustomScan((CustomScanState *) node); |
791 | 0 | break; |
792 | 0 | case T_GatherMergeState: |
793 | 0 | ExecShutdownGatherMerge((GatherMergeState *) node); |
794 | 0 | break; |
795 | 0 | case T_HashState: |
796 | 0 | ExecShutdownHash((HashState *) node); |
797 | 0 | break; |
798 | 0 | case T_HashJoinState: |
799 | 0 | ExecShutdownHashJoin((HashJoinState *) node); |
800 | 0 | break; |
801 | 0 | default: |
802 | 0 | break; |
803 | 0 | } |
804 | | |
805 | | /* Stop the node if we started it above, reporting 0 tuples. */ |
806 | 0 | if (node->instrument && node->instrument->running) |
807 | 0 | InstrStopNode(node->instrument, 0); |
808 | |
|
809 | 0 | return false; |
810 | 0 | } |
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 |
829 | | ExecSetTupleBound(int64 tuples_needed, PlanState *child_node) |
830 | 0 | { |
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 | 0 | if (IsA(child_node, SortState)) |
838 | 0 | { |
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 | 0 | SortState *sortState = (SortState *) child_node; |
848 | |
|
849 | 0 | if (tuples_needed < 0) |
850 | 0 | { |
851 | | /* make sure flag gets reset if needed upon rescan */ |
852 | 0 | sortState->bounded = false; |
853 | 0 | } |
854 | 0 | else |
855 | 0 | { |
856 | 0 | sortState->bounded = true; |
857 | 0 | sortState->bound = tuples_needed; |
858 | 0 | } |
859 | 0 | } |
860 | 0 | else if (IsA(child_node, IncrementalSortState)) |
861 | 0 | { |
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 | 0 | IncrementalSortState *sortState = (IncrementalSortState *) child_node; |
872 | |
|
873 | 0 | if (tuples_needed < 0) |
874 | 0 | { |
875 | | /* make sure flag gets reset if needed upon rescan */ |
876 | 0 | sortState->bounded = false; |
877 | 0 | } |
878 | 0 | else |
879 | 0 | { |
880 | 0 | sortState->bounded = true; |
881 | 0 | sortState->bound = tuples_needed; |
882 | 0 | } |
883 | 0 | } |
884 | 0 | else if (IsA(child_node, AppendState)) |
885 | 0 | { |
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 | 0 | AppendState *aState = (AppendState *) child_node; |
892 | 0 | int i; |
893 | |
|
894 | 0 | for (i = 0; i < aState->as_nplans; i++) |
895 | 0 | ExecSetTupleBound(tuples_needed, aState->appendplans[i]); |
896 | 0 | } |
897 | 0 | else if (IsA(child_node, MergeAppendState)) |
898 | 0 | { |
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 | 0 | MergeAppendState *maState = (MergeAppendState *) child_node; |
905 | 0 | int i; |
906 | |
|
907 | 0 | for (i = 0; i < maState->ms_nplans; i++) |
908 | 0 | ExecSetTupleBound(tuples_needed, maState->mergeplans[i]); |
909 | 0 | } |
910 | 0 | else if (IsA(child_node, ResultState)) |
911 | 0 | { |
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 | 0 | if (outerPlanState(child_node)) |
922 | 0 | ExecSetTupleBound(tuples_needed, outerPlanState(child_node)); |
923 | 0 | } |
924 | 0 | else if (IsA(child_node, SubqueryScanState)) |
925 | 0 | { |
926 | | /* |
927 | | * We can also descend through SubqueryScan, but only if it has no |
928 | | * qual (otherwise it might discard rows). |
929 | | */ |
930 | 0 | SubqueryScanState *subqueryState = (SubqueryScanState *) child_node; |
931 | |
|
932 | 0 | if (subqueryState->ss.ps.qual == NULL) |
933 | 0 | ExecSetTupleBound(tuples_needed, subqueryState->subplan); |
934 | 0 | } |
935 | 0 | else if (IsA(child_node, GatherState)) |
936 | 0 | { |
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 | | */ |
945 | 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 | 0 | } |
952 | 0 | else if (IsA(child_node, GatherMergeState)) |
953 | 0 | { |
954 | | /* Same comments as for Gather */ |
955 | 0 | GatherMergeState *gstate = (GatherMergeState *) child_node; |
956 | |
|
957 | 0 | gstate->tuples_needed = tuples_needed; |
958 | |
|
959 | 0 | ExecSetTupleBound(tuples_needed, outerPlanState(child_node)); |
960 | 0 | } |
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 | 0 | } |