Coverage Report

Created: 2026-08-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}