1 /*-------------------------------------------------------------------------
4 * miscellaneous executor access method routines
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * src/backend/executor/execAmi.c
11 *-------------------------------------------------------------------------
15 #include "access/amapi.h"
16 #include "access/htup_details.h"
17 #include "catalog/pg_class.h"
18 #include "executor/nodeAgg.h"
19 #include "executor/nodeAppend.h"
20 #include "executor/nodeBitmapAnd.h"
21 #include "executor/nodeBitmapHeapscan.h"
22 #include "executor/nodeBitmapIndexscan.h"
23 #include "executor/nodeBitmapOr.h"
24 #include "executor/nodeCtescan.h"
25 #include "executor/nodeCustom.h"
26 #include "executor/nodeForeignscan.h"
27 #include "executor/nodeFunctionscan.h"
28 #include "executor/nodeGather.h"
29 #include "executor/nodeGatherMerge.h"
30 #include "executor/nodeGroup.h"
31 #include "executor/nodeHash.h"
32 #include "executor/nodeHashjoin.h"
33 #include "executor/nodeIncrementalSort.h"
34 #include "executor/nodeIndexonlyscan.h"
35 #include "executor/nodeIndexscan.h"
36 #include "executor/nodeLimit.h"
37 #include "executor/nodeLockRows.h"
38 #include "executor/nodeMaterial.h"
39 #include "executor/nodeMemoize.h"
40 #include "executor/nodeMergeAppend.h"
41 #include "executor/nodeMergejoin.h"
42 #include "executor/nodeModifyTable.h"
43 #include "executor/nodeNamedtuplestorescan.h"
44 #include "executor/nodeNestloop.h"
45 #include "executor/nodeProjectSet.h"
46 #include "executor/nodeRecursiveunion.h"
47 #include "executor/nodeResult.h"
48 #include "executor/nodeSamplescan.h"
49 #include "executor/nodeSeqscan.h"
50 #include "executor/nodeSetOp.h"
51 #include "executor/nodeSort.h"
52 #include "executor/nodeSubplan.h"
53 #include "executor/nodeSubqueryscan.h"
54 #include "executor/nodeTableFuncscan.h"
55 #include "executor/nodeTidrangescan.h"
56 #include "executor/nodeTidscan.h"
57 #include "executor/nodeUnique.h"
58 #include "executor/nodeValuesscan.h"
59 #include "executor/nodeWindowAgg.h"
60 #include "executor/nodeWorktablescan.h"
61 #include "nodes/extensible.h"
62 #include "nodes/pathnodes.h"
63 #include "utils/syscache.h"
65 static bool IndexSupportsBackwardScan(Oid indexid
);
70 * Reset a plan node so that its output can be re-scanned.
72 * Note that if the plan node has parameters that have changed value,
73 * the output might be different from last time.
76 ExecReScan(PlanState
*node
)
78 /* If collecting timing stats, update them */
80 InstrEndLoop(node
->instrument
);
83 * If we have changed parameters, propagate that info.
85 * Note: ExecReScanSetParamPlan() can add bits to node->chgParam,
86 * corresponding to the output param(s) that the InitPlan will update.
87 * Since we make only one pass over the list, that means that an InitPlan
88 * can depend on the output param(s) of a sibling InitPlan only if that
89 * sibling appears earlier in the list. This is workable for now given
90 * the limited ways in which one InitPlan could depend on another, but
91 * eventually we might need to work harder (or else make the planner
92 * enlarge the extParam/allParam sets to include the params of depended-on
95 if (node
->chgParam
!= NULL
)
99 foreach(l
, node
->initPlan
)
101 SubPlanState
*sstate
= (SubPlanState
*) lfirst(l
);
102 PlanState
*splan
= sstate
->planstate
;
104 if (splan
->plan
->extParam
!= NULL
) /* don't care about child
106 UpdateChangedParamSet(splan
, node
->chgParam
);
107 if (splan
->chgParam
!= NULL
)
108 ExecReScanSetParamPlan(sstate
, node
);
110 foreach(l
, node
->subPlan
)
112 SubPlanState
*sstate
= (SubPlanState
*) lfirst(l
);
113 PlanState
*splan
= sstate
->planstate
;
115 if (splan
->plan
->extParam
!= NULL
)
116 UpdateChangedParamSet(splan
, node
->chgParam
);
118 /* Well. Now set chgParam for child trees. */
119 if (outerPlanState(node
) != NULL
)
120 UpdateChangedParamSet(outerPlanState(node
), node
->chgParam
);
121 if (innerPlanState(node
) != NULL
)
122 UpdateChangedParamSet(innerPlanState(node
), node
->chgParam
);
125 /* Call expression callbacks */
126 if (node
->ps_ExprContext
)
127 ReScanExprContext(node
->ps_ExprContext
);
129 /* And do node-type-specific processing */
130 switch (nodeTag(node
))
133 ExecReScanResult((ResultState
*) node
);
136 case T_ProjectSetState
:
137 ExecReScanProjectSet((ProjectSetState
*) node
);
140 case T_ModifyTableState
:
141 ExecReScanModifyTable((ModifyTableState
*) node
);
145 ExecReScanAppend((AppendState
*) node
);
148 case T_MergeAppendState
:
149 ExecReScanMergeAppend((MergeAppendState
*) node
);
152 case T_RecursiveUnionState
:
153 ExecReScanRecursiveUnion((RecursiveUnionState
*) node
);
156 case T_BitmapAndState
:
157 ExecReScanBitmapAnd((BitmapAndState
*) node
);
160 case T_BitmapOrState
:
161 ExecReScanBitmapOr((BitmapOrState
*) node
);
165 ExecReScanSeqScan((SeqScanState
*) node
);
168 case T_SampleScanState
:
169 ExecReScanSampleScan((SampleScanState
*) node
);
173 ExecReScanGather((GatherState
*) node
);
176 case T_GatherMergeState
:
177 ExecReScanGatherMerge((GatherMergeState
*) node
);
180 case T_IndexScanState
:
181 ExecReScanIndexScan((IndexScanState
*) node
);
184 case T_IndexOnlyScanState
:
185 ExecReScanIndexOnlyScan((IndexOnlyScanState
*) node
);
188 case T_BitmapIndexScanState
:
189 ExecReScanBitmapIndexScan((BitmapIndexScanState
*) node
);
192 case T_BitmapHeapScanState
:
193 ExecReScanBitmapHeapScan((BitmapHeapScanState
*) node
);
197 ExecReScanTidScan((TidScanState
*) node
);
200 case T_TidRangeScanState
:
201 ExecReScanTidRangeScan((TidRangeScanState
*) node
);
204 case T_SubqueryScanState
:
205 ExecReScanSubqueryScan((SubqueryScanState
*) node
);
208 case T_FunctionScanState
:
209 ExecReScanFunctionScan((FunctionScanState
*) node
);
212 case T_TableFuncScanState
:
213 ExecReScanTableFuncScan((TableFuncScanState
*) node
);
216 case T_ValuesScanState
:
217 ExecReScanValuesScan((ValuesScanState
*) node
);
221 ExecReScanCteScan((CteScanState
*) node
);
224 case T_NamedTuplestoreScanState
:
225 ExecReScanNamedTuplestoreScan((NamedTuplestoreScanState
*) node
);
228 case T_WorkTableScanState
:
229 ExecReScanWorkTableScan((WorkTableScanState
*) node
);
232 case T_ForeignScanState
:
233 ExecReScanForeignScan((ForeignScanState
*) node
);
236 case T_CustomScanState
:
237 ExecReScanCustomScan((CustomScanState
*) node
);
240 case T_NestLoopState
:
241 ExecReScanNestLoop((NestLoopState
*) node
);
244 case T_MergeJoinState
:
245 ExecReScanMergeJoin((MergeJoinState
*) node
);
248 case T_HashJoinState
:
249 ExecReScanHashJoin((HashJoinState
*) node
);
252 case T_MaterialState
:
253 ExecReScanMaterial((MaterialState
*) node
);
257 ExecReScanMemoize((MemoizeState
*) node
);
261 ExecReScanSort((SortState
*) node
);
264 case T_IncrementalSortState
:
265 ExecReScanIncrementalSort((IncrementalSortState
*) node
);
269 ExecReScanGroup((GroupState
*) node
);
273 ExecReScanAgg((AggState
*) node
);
276 case T_WindowAggState
:
277 ExecReScanWindowAgg((WindowAggState
*) node
);
281 ExecReScanUnique((UniqueState
*) node
);
285 ExecReScanHash((HashState
*) node
);
289 ExecReScanSetOp((SetOpState
*) node
);
292 case T_LockRowsState
:
293 ExecReScanLockRows((LockRowsState
*) node
);
297 ExecReScanLimit((LimitState
*) node
);
301 elog(ERROR
, "unrecognized node type: %d", (int) nodeTag(node
));
305 if (node
->chgParam
!= NULL
)
307 bms_free(node
->chgParam
);
308 node
->chgParam
= NULL
;
315 * Marks the current scan position.
317 * NOTE: mark/restore capability is currently needed only for plan nodes
318 * that are the immediate inner child of a MergeJoin node. Since MergeJoin
319 * requires sorted input, there is never any need to support mark/restore in
320 * node types that cannot produce sorted output. There are some cases in
321 * which a node can pass through sorted data from its child; if we don't
322 * implement mark/restore for such a node type, the planner compensates by
323 * inserting a Material node above that node.
326 ExecMarkPos(PlanState
*node
)
328 switch (nodeTag(node
))
330 case T_IndexScanState
:
331 ExecIndexMarkPos((IndexScanState
*) node
);
334 case T_IndexOnlyScanState
:
335 ExecIndexOnlyMarkPos((IndexOnlyScanState
*) node
);
338 case T_CustomScanState
:
339 ExecCustomMarkPos((CustomScanState
*) node
);
342 case T_MaterialState
:
343 ExecMaterialMarkPos((MaterialState
*) node
);
347 ExecSortMarkPos((SortState
*) node
);
351 ExecResultMarkPos((ResultState
*) node
);
355 /* don't make hard error unless caller asks to restore... */
356 elog(DEBUG2
, "unrecognized node type: %d", (int) nodeTag(node
));
364 * restores the scan position previously saved with ExecMarkPos()
366 * NOTE: the semantics of this are that the first ExecProcNode following
367 * the restore operation will yield the same tuple as the first one following
368 * the mark operation. It is unspecified what happens to the plan node's
369 * result TupleTableSlot. (In most cases the result slot is unchanged by
370 * a restore, but the node may choose to clear it or to load it with the
371 * restored-to tuple.) Hence the caller should discard any previously
372 * returned TupleTableSlot after doing a restore.
375 ExecRestrPos(PlanState
*node
)
377 switch (nodeTag(node
))
379 case T_IndexScanState
:
380 ExecIndexRestrPos((IndexScanState
*) node
);
383 case T_IndexOnlyScanState
:
384 ExecIndexOnlyRestrPos((IndexOnlyScanState
*) node
);
387 case T_CustomScanState
:
388 ExecCustomRestrPos((CustomScanState
*) node
);
391 case T_MaterialState
:
392 ExecMaterialRestrPos((MaterialState
*) node
);
396 ExecSortRestrPos((SortState
*) node
);
400 ExecResultRestrPos((ResultState
*) node
);
404 elog(ERROR
, "unrecognized node type: %d", (int) nodeTag(node
));
410 * ExecSupportsMarkRestore - does a Path support mark/restore?
412 * This is used during planning and so must accept a Path, not a Plan.
413 * We keep it here to be adjacent to the routines above, which also must
414 * know which plan types support mark/restore.
417 ExecSupportsMarkRestore(Path
*pathnode
)
420 * For consistency with the routines above, we do not examine the nodeTag
421 * but rather the pathtype, which is the Plan node type the Path would
424 switch (pathnode
->pathtype
)
427 case T_IndexOnlyScan
:
430 * Not all index types support mark/restore.
432 return castNode(IndexPath
, pathnode
)->indexinfo
->amcanmarkpos
;
439 if (castNode(CustomPath
, pathnode
)->flags
& CUSTOMPATH_SUPPORT_MARK_RESTORE
)
446 * Result supports mark/restore iff it has a child plan that does.
448 * We have to be careful here because there is more than one Path
449 * type that can produce a Result plan node.
451 if (IsA(pathnode
, ProjectionPath
))
452 return ExecSupportsMarkRestore(((ProjectionPath
*) pathnode
)->subpath
);
453 else if (IsA(pathnode
, MinMaxAggPath
))
454 return false; /* childless Result */
455 else if (IsA(pathnode
, GroupResultPath
))
456 return false; /* childless Result */
459 /* Simple RTE_RESULT base relation */
460 Assert(IsA(pathnode
, Path
));
461 return false; /* childless Result */
466 AppendPath
*appendPath
= castNode(AppendPath
, pathnode
);
469 * If there's exactly one child, then there will be no Append
470 * in the final plan, so we can handle mark/restore if the
471 * child plan node can.
473 if (list_length(appendPath
->subpaths
) == 1)
474 return ExecSupportsMarkRestore((Path
*) linitial(appendPath
->subpaths
));
475 /* Otherwise, Append can't handle it */
481 MergeAppendPath
*mapath
= castNode(MergeAppendPath
, pathnode
);
484 * Like the Append case above, single-subpath MergeAppends
485 * won't be in the final plan, so just return the child's
486 * mark/restore ability.
488 if (list_length(mapath
->subpaths
) == 1)
489 return ExecSupportsMarkRestore((Path
*) linitial(mapath
->subpaths
));
490 /* Otherwise, MergeAppend can't handle it */
502 * ExecSupportsBackwardScan - does a plan type support backwards scanning?
504 * Ideally, all plan types would support backwards scan, but that seems
505 * unlikely to happen soon. In some cases, a plan node passes the backwards
506 * scan down to its children, and so supports backwards scan only if its
507 * children do. Therefore, this routine must be passed a complete plan tree.
510 ExecSupportsBackwardScan(Plan
*node
)
516 * Parallel-aware nodes return a subset of the tuples in each worker, and
517 * in general we can't expect to have enough bookkeeping state to know
518 * which ones we returned in this worker as opposed to some other worker.
520 if (node
->parallel_aware
)
523 switch (nodeTag(node
))
526 if (outerPlan(node
) != NULL
)
527 return ExecSupportsBackwardScan(outerPlan(node
));
535 /* With async, tuples may be interleaved, so can't back up. */
536 if (((Append
*) node
)->nasyncplans
> 0)
539 foreach(l
, ((Append
*) node
)->appendplans
)
541 if (!ExecSupportsBackwardScan((Plan
*) lfirst(l
)))
544 /* need not check tlist because Append doesn't evaluate it */
549 /* Simplify life for tablesample methods by disallowing this */
556 return IndexSupportsBackwardScan(((IndexScan
*) node
)->indexid
);
558 case T_IndexOnlyScan
:
559 return IndexSupportsBackwardScan(((IndexOnlyScan
*) node
)->indexid
);
562 return ExecSupportsBackwardScan(((SubqueryScan
*) node
)->subplan
);
565 if (((CustomScan
*) node
)->flags
& CUSTOMPATH_SUPPORT_BACKWARD_SCAN
)
577 /* these don't evaluate tlist */
580 case T_IncrementalSort
:
583 * Unlike full sort, incremental sort keeps only a single group of
584 * tuples in memory, so it can't scan backwards.
590 return ExecSupportsBackwardScan(outerPlan(node
));
598 * An IndexScan or IndexOnlyScan node supports backward scan only if the
602 IndexSupportsBackwardScan(Oid indexid
)
606 Form_pg_class idxrelrec
;
607 IndexAmRoutine
*amroutine
;
609 /* Fetch the pg_class tuple of the index relation */
610 ht_idxrel
= SearchSysCache1(RELOID
, ObjectIdGetDatum(indexid
));
611 if (!HeapTupleIsValid(ht_idxrel
))
612 elog(ERROR
, "cache lookup failed for relation %u", indexid
);
613 idxrelrec
= (Form_pg_class
) GETSTRUCT(ht_idxrel
);
615 /* Fetch the index AM's API struct */
616 amroutine
= GetIndexAmRoutineByAmId(idxrelrec
->relam
, false);
618 result
= amroutine
->amcanbackward
;
621 ReleaseSysCache(ht_idxrel
);
627 * ExecMaterializesOutput - does a plan type materialize its output?
629 * Returns true if the plan node type is one that automatically materializes
630 * its output (typically by keeping it in a tuplestore). For such plans,
631 * a rescan without any parameter change will have zero startup cost and
632 * very low per-tuple cost.
635 ExecMaterializesOutput(NodeTag plantype
)
641 case T_TableFuncScan
:
643 case T_NamedTuplestoreScan
:
644 case T_WorkTableScan
: