Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * execAmi.c
4 : * miscellaneous executor access method routines
5 : *
6 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : * src/backend/executor/execAmi.c
10 : *
11 : *-------------------------------------------------------------------------
12 : */
13 : #include "postgres.h"
14 :
15 : #include "access/amapi.h"
16 : #include "access/htup_details.h"
17 : #include "catalog/pg_class.h"
18 : #include "executor/executor.h"
19 : #include "executor/nodeAgg.h"
20 : #include "executor/nodeAppend.h"
21 : #include "executor/nodeBitmapAnd.h"
22 : #include "executor/nodeBitmapHeapscan.h"
23 : #include "executor/nodeBitmapIndexscan.h"
24 : #include "executor/nodeBitmapOr.h"
25 : #include "executor/nodeCtescan.h"
26 : #include "executor/nodeCustom.h"
27 : #include "executor/nodeForeignscan.h"
28 : #include "executor/nodeFunctionscan.h"
29 : #include "executor/nodeGather.h"
30 : #include "executor/nodeGatherMerge.h"
31 : #include "executor/nodeGroup.h"
32 : #include "executor/nodeHash.h"
33 : #include "executor/nodeHashjoin.h"
34 : #include "executor/nodeIncrementalSort.h"
35 : #include "executor/nodeIndexonlyscan.h"
36 : #include "executor/nodeIndexscan.h"
37 : #include "executor/nodeLimit.h"
38 : #include "executor/nodeLockRows.h"
39 : #include "executor/nodeMaterial.h"
40 : #include "executor/nodeMemoize.h"
41 : #include "executor/nodeMergeAppend.h"
42 : #include "executor/nodeMergejoin.h"
43 : #include "executor/nodeModifyTable.h"
44 : #include "executor/nodeNamedtuplestorescan.h"
45 : #include "executor/nodeNestloop.h"
46 : #include "executor/nodeProjectSet.h"
47 : #include "executor/nodeRecursiveunion.h"
48 : #include "executor/nodeResult.h"
49 : #include "executor/nodeSamplescan.h"
50 : #include "executor/nodeSeqscan.h"
51 : #include "executor/nodeSetOp.h"
52 : #include "executor/nodeSort.h"
53 : #include "executor/nodeSubplan.h"
54 : #include "executor/nodeSubqueryscan.h"
55 : #include "executor/nodeTableFuncscan.h"
56 : #include "executor/nodeTidrangescan.h"
57 : #include "executor/nodeTidscan.h"
58 : #include "executor/nodeUnique.h"
59 : #include "executor/nodeValuesscan.h"
60 : #include "executor/nodeWindowAgg.h"
61 : #include "executor/nodeWorktablescan.h"
62 : #include "nodes/extensible.h"
63 : #include "nodes/pathnodes.h"
64 : #include "utils/syscache.h"
65 :
66 : static bool IndexSupportsBackwardScan(Oid indexid);
67 :
68 :
69 : /*
70 : * ExecReScan
71 : * Reset a plan node so that its output can be re-scanned.
72 : *
73 : * Note that if the plan node has parameters that have changed value,
74 : * the output might be different from last time.
75 : */
76 : void
77 3068736 : ExecReScan(PlanState *node)
78 : {
79 : /* If collecting timing stats, update them */
80 3068736 : if (node->instrument)
81 42238 : InstrEndLoop(node->instrument);
82 :
83 : /*
84 : * If we have changed parameters, propagate that info.
85 : *
86 : * Note: ExecReScanSetParamPlan() can add bits to node->chgParam,
87 : * corresponding to the output param(s) that the InitPlan will update.
88 : * Since we make only one pass over the list, that means that an InitPlan
89 : * can depend on the output param(s) of a sibling InitPlan only if that
90 : * sibling appears earlier in the list. This is workable for now given
91 : * the limited ways in which one InitPlan could depend on another, but
92 : * eventually we might need to work harder (or else make the planner
93 : * enlarge the extParam/allParam sets to include the params of depended-on
94 : * InitPlans).
95 : */
96 3068736 : if (node->chgParam != NULL)
97 : {
98 : ListCell *l;
99 :
100 2787208 : foreach(l, node->initPlan)
101 : {
102 1682 : SubPlanState *sstate = (SubPlanState *) lfirst(l);
103 1682 : PlanState *splan = sstate->planstate;
104 :
105 1682 : if (splan->plan->extParam != NULL) /* don't care about child
106 : * local Params */
107 1528 : UpdateChangedParamSet(splan, node->chgParam);
108 1682 : if (splan->chgParam != NULL)
109 1288 : ExecReScanSetParamPlan(sstate, node);
110 : }
111 2786378 : foreach(l, node->subPlan)
112 : {
113 852 : SubPlanState *sstate = (SubPlanState *) lfirst(l);
114 852 : PlanState *splan = sstate->planstate;
115 :
116 852 : if (splan->plan->extParam != NULL)
117 846 : UpdateChangedParamSet(splan, node->chgParam);
118 : }
119 : /* Well. Now set chgParam for child trees. */
120 2785526 : if (outerPlanState(node) != NULL)
121 729944 : UpdateChangedParamSet(outerPlanState(node), node->chgParam);
122 2785526 : if (innerPlanState(node) != NULL)
123 16872 : UpdateChangedParamSet(innerPlanState(node), node->chgParam);
124 : }
125 :
126 : /* Call expression callbacks */
127 3068736 : if (node->ps_ExprContext)
128 2841730 : ReScanExprContext(node->ps_ExprContext);
129 :
130 : /* And do node-type-specific processing */
131 3068736 : switch (nodeTag(node))
132 : {
133 42746 : case T_ResultState:
134 42746 : ExecReScanResult((ResultState *) node);
135 42746 : break;
136 :
137 15920 : case T_ProjectSetState:
138 15920 : ExecReScanProjectSet((ProjectSetState *) node);
139 15920 : break;
140 :
141 0 : case T_ModifyTableState:
142 0 : ExecReScanModifyTable((ModifyTableState *) node);
143 0 : break;
144 :
145 20068 : case T_AppendState:
146 20068 : ExecReScanAppend((AppendState *) node);
147 20068 : break;
148 :
149 18 : case T_MergeAppendState:
150 18 : ExecReScanMergeAppend((MergeAppendState *) node);
151 18 : break;
152 :
153 12 : case T_RecursiveUnionState:
154 12 : ExecReScanRecursiveUnion((RecursiveUnionState *) node);
155 12 : break;
156 :
157 130 : case T_BitmapAndState:
158 130 : ExecReScanBitmapAnd((BitmapAndState *) node);
159 130 : break;
160 :
161 32 : case T_BitmapOrState:
162 32 : ExecReScanBitmapOr((BitmapOrState *) node);
163 32 : break;
164 :
165 1190484 : case T_SeqScanState:
166 1190484 : ExecReScanSeqScan((SeqScanState *) node);
167 1190484 : break;
168 :
169 58 : case T_SampleScanState:
170 58 : ExecReScanSampleScan((SampleScanState *) node);
171 58 : break;
172 :
173 300 : case T_GatherState:
174 300 : ExecReScanGather((GatherState *) node);
175 300 : break;
176 :
177 48 : case T_GatherMergeState:
178 48 : ExecReScanGatherMerge((GatherMergeState *) node);
179 48 : break;
180 :
181 526200 : case T_IndexScanState:
182 526200 : ExecReScanIndexScan((IndexScanState *) node);
183 526194 : break;
184 :
185 215278 : case T_IndexOnlyScanState:
186 215278 : ExecReScanIndexOnlyScan((IndexOnlyScanState *) node);
187 215278 : break;
188 :
189 11284 : case T_BitmapIndexScanState:
190 11284 : ExecReScanBitmapIndexScan((BitmapIndexScanState *) node);
191 11284 : break;
192 :
193 10578 : case T_BitmapHeapScanState:
194 10578 : ExecReScanBitmapHeapScan((BitmapHeapScanState *) node);
195 10578 : break;
196 :
197 18 : case T_TidScanState:
198 18 : ExecReScanTidScan((TidScanState *) node);
199 18 : break;
200 :
201 66 : case T_TidRangeScanState:
202 66 : ExecReScanTidRangeScan((TidRangeScanState *) node);
203 66 : break;
204 :
205 422 : case T_SubqueryScanState:
206 422 : ExecReScanSubqueryScan((SubqueryScanState *) node);
207 422 : break;
208 :
209 115088 : case T_FunctionScanState:
210 115088 : ExecReScanFunctionScan((FunctionScanState *) node);
211 115088 : break;
212 :
213 444 : case T_TableFuncScanState:
214 444 : ExecReScanTableFuncScan((TableFuncScanState *) node);
215 444 : break;
216 :
217 60398 : case T_ValuesScanState:
218 60398 : ExecReScanValuesScan((ValuesScanState *) node);
219 60398 : break;
220 :
221 6610 : case T_CteScanState:
222 6610 : ExecReScanCteScan((CteScanState *) node);
223 6610 : break;
224 :
225 0 : case T_NamedTuplestoreScanState:
226 0 : ExecReScanNamedTuplestoreScan((NamedTuplestoreScanState *) node);
227 0 : break;
228 :
229 6502 : case T_WorkTableScanState:
230 6502 : ExecReScanWorkTableScan((WorkTableScanState *) node);
231 6502 : break;
232 :
233 808 : case T_ForeignScanState:
234 808 : ExecReScanForeignScan((ForeignScanState *) node);
235 808 : break;
236 :
237 0 : case T_CustomScanState:
238 0 : ExecReScanCustomScan((CustomScanState *) node);
239 0 : break;
240 :
241 12940 : case T_NestLoopState:
242 12940 : ExecReScanNestLoop((NestLoopState *) node);
243 12940 : break;
244 :
245 670 : case T_MergeJoinState:
246 670 : ExecReScanMergeJoin((MergeJoinState *) node);
247 670 : break;
248 :
249 3392 : case T_HashJoinState:
250 3392 : ExecReScanHashJoin((HashJoinState *) node);
251 3392 : break;
252 :
253 143738 : case T_MaterialState:
254 143738 : ExecReScanMaterial((MaterialState *) node);
255 143738 : break;
256 :
257 517258 : case T_MemoizeState:
258 517258 : ExecReScanMemoize((MemoizeState *) node);
259 517258 : break;
260 :
261 51696 : case T_SortState:
262 51696 : ExecReScanSort((SortState *) node);
263 51696 : break;
264 :
265 12 : case T_IncrementalSortState:
266 12 : ExecReScanIncrementalSort((IncrementalSortState *) node);
267 12 : break;
268 :
269 24 : case T_GroupState:
270 24 : ExecReScanGroup((GroupState *) node);
271 24 : break;
272 :
273 51528 : case T_AggState:
274 51528 : ExecReScanAgg((AggState *) node);
275 51528 : break;
276 :
277 78 : case T_WindowAggState:
278 78 : ExecReScanWindowAgg((WindowAggState *) node);
279 78 : break;
280 :
281 0 : case T_UniqueState:
282 0 : ExecReScanUnique((UniqueState *) node);
283 0 : break;
284 :
285 1682 : case T_HashState:
286 1682 : ExecReScanHash((HashState *) node);
287 1682 : break;
288 :
289 1200 : case T_SetOpState:
290 1200 : ExecReScanSetOp((SetOpState *) node);
291 1200 : break;
292 :
293 16 : case T_LockRowsState:
294 16 : ExecReScanLockRows((LockRowsState *) node);
295 16 : break;
296 :
297 60990 : case T_LimitState:
298 60990 : ExecReScanLimit((LimitState *) node);
299 60990 : break;
300 :
301 0 : default:
302 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
303 : break;
304 : }
305 :
306 3068730 : if (node->chgParam != NULL)
307 : {
308 2785526 : bms_free(node->chgParam);
309 2785526 : node->chgParam = NULL;
310 : }
311 3068730 : }
312 :
313 : /*
314 : * ExecMarkPos
315 : *
316 : * Marks the current scan position.
317 : *
318 : * NOTE: mark/restore capability is currently needed only for plan nodes
319 : * that are the immediate inner child of a MergeJoin node. Since MergeJoin
320 : * requires sorted input, there is never any need to support mark/restore in
321 : * node types that cannot produce sorted output. There are some cases in
322 : * which a node can pass through sorted data from its child; if we don't
323 : * implement mark/restore for such a node type, the planner compensates by
324 : * inserting a Material node above that node.
325 : */
326 : void
327 716946 : ExecMarkPos(PlanState *node)
328 : {
329 716946 : switch (nodeTag(node))
330 : {
331 6040 : case T_IndexScanState:
332 6040 : ExecIndexMarkPos((IndexScanState *) node);
333 6040 : break;
334 :
335 124036 : case T_IndexOnlyScanState:
336 124036 : ExecIndexOnlyMarkPos((IndexOnlyScanState *) node);
337 124036 : break;
338 :
339 0 : case T_CustomScanState:
340 0 : ExecCustomMarkPos((CustomScanState *) node);
341 0 : break;
342 :
343 6540 : case T_MaterialState:
344 6540 : ExecMaterialMarkPos((MaterialState *) node);
345 6540 : break;
346 :
347 580330 : case T_SortState:
348 580330 : ExecSortMarkPos((SortState *) node);
349 580330 : break;
350 :
351 0 : case T_ResultState:
352 0 : ExecResultMarkPos((ResultState *) node);
353 0 : break;
354 :
355 0 : default:
356 : /* don't make hard error unless caller asks to restore... */
357 0 : elog(DEBUG2, "unrecognized node type: %d", (int) nodeTag(node));
358 0 : break;
359 : }
360 716946 : }
361 :
362 : /*
363 : * ExecRestrPos
364 : *
365 : * restores the scan position previously saved with ExecMarkPos()
366 : *
367 : * NOTE: the semantics of this are that the first ExecProcNode following
368 : * the restore operation will yield the same tuple as the first one following
369 : * the mark operation. It is unspecified what happens to the plan node's
370 : * result TupleTableSlot. (In most cases the result slot is unchanged by
371 : * a restore, but the node may choose to clear it or to load it with the
372 : * restored-to tuple.) Hence the caller should discard any previously
373 : * returned TupleTableSlot after doing a restore.
374 : */
375 : void
376 138700 : ExecRestrPos(PlanState *node)
377 : {
378 138700 : switch (nodeTag(node))
379 : {
380 54018 : case T_IndexScanState:
381 54018 : ExecIndexRestrPos((IndexScanState *) node);
382 54018 : break;
383 :
384 0 : case T_IndexOnlyScanState:
385 0 : ExecIndexOnlyRestrPos((IndexOnlyScanState *) node);
386 0 : break;
387 :
388 0 : case T_CustomScanState:
389 0 : ExecCustomRestrPos((CustomScanState *) node);
390 0 : break;
391 :
392 54032 : case T_MaterialState:
393 54032 : ExecMaterialRestrPos((MaterialState *) node);
394 54032 : break;
395 :
396 30650 : case T_SortState:
397 30650 : ExecSortRestrPos((SortState *) node);
398 30650 : break;
399 :
400 0 : case T_ResultState:
401 0 : ExecResultRestrPos((ResultState *) node);
402 0 : break;
403 :
404 0 : default:
405 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
406 : break;
407 : }
408 138700 : }
409 :
410 : /*
411 : * ExecSupportsMarkRestore - does a Path support mark/restore?
412 : *
413 : * This is used during planning and so must accept a Path, not a Plan.
414 : * We keep it here to be adjacent to the routines above, which also must
415 : * know which plan types support mark/restore.
416 : */
417 : bool
418 14088 : ExecSupportsMarkRestore(Path *pathnode)
419 : {
420 : /*
421 : * For consistency with the routines above, we do not examine the nodeTag
422 : * but rather the pathtype, which is the Plan node type the Path would
423 : * produce.
424 : */
425 14088 : switch (pathnode->pathtype)
426 : {
427 9742 : case T_IndexScan:
428 : case T_IndexOnlyScan:
429 :
430 : /*
431 : * Not all index types support mark/restore.
432 : */
433 9742 : return castNode(IndexPath, pathnode)->indexinfo->amcanmarkpos;
434 :
435 0 : case T_Material:
436 : case T_Sort:
437 0 : return true;
438 :
439 0 : case T_CustomScan:
440 0 : if (castNode(CustomPath, pathnode)->flags & CUSTOMPATH_SUPPORT_MARK_RESTORE)
441 0 : return true;
442 0 : return false;
443 :
444 0 : case T_Result:
445 :
446 : /*
447 : * Result supports mark/restore iff it has a child plan that does.
448 : *
449 : * We have to be careful here because there is more than one Path
450 : * type that can produce a Result plan node.
451 : */
452 0 : if (IsA(pathnode, ProjectionPath))
453 0 : return ExecSupportsMarkRestore(((ProjectionPath *) pathnode)->subpath);
454 0 : else if (IsA(pathnode, MinMaxAggPath))
455 0 : return false; /* childless Result */
456 0 : else if (IsA(pathnode, GroupResultPath))
457 0 : return false; /* childless Result */
458 : else
459 : {
460 : /* Simple RTE_RESULT base relation */
461 : Assert(IsA(pathnode, Path));
462 0 : return false; /* childless Result */
463 : }
464 :
465 84 : case T_Append:
466 : {
467 84 : AppendPath *appendPath = castNode(AppendPath, pathnode);
468 :
469 : /*
470 : * If there's exactly one child, then there will be no Append
471 : * in the final plan, so we can handle mark/restore if the
472 : * child plan node can.
473 : */
474 84 : if (list_length(appendPath->subpaths) == 1)
475 0 : return ExecSupportsMarkRestore((Path *) linitial(appendPath->subpaths));
476 : /* Otherwise, Append can't handle it */
477 84 : return false;
478 : }
479 :
480 44 : case T_MergeAppend:
481 : {
482 44 : MergeAppendPath *mapath = castNode(MergeAppendPath, pathnode);
483 :
484 : /*
485 : * Like the Append case above, single-subpath MergeAppends
486 : * won't be in the final plan, so just return the child's
487 : * mark/restore ability.
488 : */
489 44 : if (list_length(mapath->subpaths) == 1)
490 0 : return ExecSupportsMarkRestore((Path *) linitial(mapath->subpaths));
491 : /* Otherwise, MergeAppend can't handle it */
492 44 : return false;
493 : }
494 :
495 4218 : default:
496 4218 : break;
497 : }
498 :
499 4218 : return false;
500 : }
501 :
502 : /*
503 : * ExecSupportsBackwardScan - does a plan type support backwards scanning?
504 : *
505 : * Ideally, all plan types would support backwards scan, but that seems
506 : * unlikely to happen soon. In some cases, a plan node passes the backwards
507 : * scan down to its children, and so supports backwards scan only if its
508 : * children do. Therefore, this routine must be passed a complete plan tree.
509 : */
510 : bool
511 4970 : ExecSupportsBackwardScan(Plan *node)
512 : {
513 4970 : if (node == NULL)
514 0 : return false;
515 :
516 : /*
517 : * Parallel-aware nodes return a subset of the tuples in each worker, and
518 : * in general we can't expect to have enough bookkeeping state to know
519 : * which ones we returned in this worker as opposed to some other worker.
520 : */
521 4970 : if (node->parallel_aware)
522 0 : return false;
523 :
524 4970 : switch (nodeTag(node))
525 : {
526 72 : case T_Result:
527 72 : if (outerPlan(node) != NULL)
528 0 : return ExecSupportsBackwardScan(outerPlan(node));
529 : else
530 72 : return false;
531 :
532 40 : case T_Append:
533 : {
534 : ListCell *l;
535 :
536 : /* With async, tuples may be interleaved, so can't back up. */
537 40 : if (((Append *) node)->nasyncplans > 0)
538 0 : return false;
539 :
540 136 : foreach(l, ((Append *) node)->appendplans)
541 : {
542 98 : if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
543 2 : return false;
544 : }
545 : /* need not check tlist because Append doesn't evaluate it */
546 38 : return true;
547 : }
548 :
549 6 : case T_SampleScan:
550 : /* Simplify life for tablesample methods by disallowing this */
551 6 : return false;
552 :
553 0 : case T_Gather:
554 0 : return false;
555 :
556 402 : case T_IndexScan:
557 402 : return IndexSupportsBackwardScan(((IndexScan *) node)->indexid);
558 :
559 48 : case T_IndexOnlyScan:
560 48 : return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid);
561 :
562 0 : case T_SubqueryScan:
563 0 : return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
564 :
565 0 : case T_CustomScan:
566 0 : if (((CustomScan *) node)->flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
567 0 : return true;
568 0 : return false;
569 :
570 3530 : case T_SeqScan:
571 : case T_TidScan:
572 : case T_TidRangeScan:
573 : case T_FunctionScan:
574 : case T_ValuesScan:
575 : case T_CteScan:
576 : case T_Material:
577 : case T_Sort:
578 : /* these don't evaluate tlist */
579 3530 : return true;
580 :
581 4 : case T_IncrementalSort:
582 :
583 : /*
584 : * Unlike full sort, incremental sort keeps only a single group of
585 : * tuples in memory, so it can't scan backwards.
586 : */
587 4 : return false;
588 :
589 148 : case T_LockRows:
590 : case T_Limit:
591 148 : return ExecSupportsBackwardScan(outerPlan(node));
592 :
593 720 : default:
594 720 : return false;
595 : }
596 : }
597 :
598 : /*
599 : * An IndexScan or IndexOnlyScan node supports backward scan only if the
600 : * index's AM does.
601 : */
602 : static bool
603 450 : IndexSupportsBackwardScan(Oid indexid)
604 : {
605 : bool result;
606 : HeapTuple ht_idxrel;
607 : Form_pg_class idxrelrec;
608 : IndexAmRoutine *amroutine;
609 :
610 : /* Fetch the pg_class tuple of the index relation */
611 450 : ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid));
612 450 : if (!HeapTupleIsValid(ht_idxrel))
613 0 : elog(ERROR, "cache lookup failed for relation %u", indexid);
614 450 : idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
615 :
616 : /* Fetch the index AM's API struct */
617 450 : amroutine = GetIndexAmRoutineByAmId(idxrelrec->relam, false);
618 :
619 450 : result = amroutine->amcanbackward;
620 :
621 450 : pfree(amroutine);
622 450 : ReleaseSysCache(ht_idxrel);
623 :
624 450 : return result;
625 : }
626 :
627 : /*
628 : * ExecMaterializesOutput - does a plan type materialize its output?
629 : *
630 : * Returns true if the plan node type is one that automatically materializes
631 : * its output (typically by keeping it in a tuplestore). For such plans,
632 : * a rescan without any parameter change will have zero startup cost and
633 : * very low per-tuple cost.
634 : */
635 : bool
636 539268 : ExecMaterializesOutput(NodeTag plantype)
637 : {
638 539268 : switch (plantype)
639 : {
640 24268 : case T_Material:
641 : case T_FunctionScan:
642 : case T_TableFuncScan:
643 : case T_CteScan:
644 : case T_NamedTuplestoreScan:
645 : case T_WorkTableScan:
646 : case T_Sort:
647 24268 : return true;
648 :
649 515000 : default:
650 515000 : break;
651 : }
652 :
653 515000 : return false;
654 : }
|