1 /*-------------------------------------------------------------------------
4 * miscellaneous executor access method routines
6 * Portions Copyright (c) 1996-2022, 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 "executor/execdebug.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/nodeFuncs.h"
63 #include "nodes/pathnodes.h"
64 #include "utils/rel.h"
65 #include "utils/syscache.h"
67 static bool IndexSupportsBackwardScan(Oid indexid
);
72 * Reset a plan node so that its output can be re-scanned.
74 * Note that if the plan node has parameters that have changed value,
75 * the output might be different from last time.
78 ExecReScan(PlanState
*node
)
80 /* If collecting timing stats, update them */
82 InstrEndLoop(node
->instrument
);
85 * If we have changed parameters, propagate that info.
87 * Note: ExecReScanSetParamPlan() can add bits to node->chgParam,
88 * corresponding to the output param(s) that the InitPlan will update.
89 * Since we make only one pass over the list, that means that an InitPlan
90 * can depend on the output param(s) of a sibling InitPlan only if that
91 * sibling appears earlier in the list. This is workable for now given
92 * the limited ways in which one InitPlan could depend on another, but
93 * eventually we might need to work harder (or else make the planner
94 * enlarge the extParam/allParam sets to include the params of depended-on
97 if (node
->chgParam
!= NULL
)
101 foreach(l
, node
->initPlan
)
103 SubPlanState
*sstate
= (SubPlanState
*) lfirst(l
);
104 PlanState
*splan
= sstate
->planstate
;
106 if (splan
->plan
->extParam
!= NULL
) /* don't care about child
108 UpdateChangedParamSet(splan
, node
->chgParam
);
109 if (splan
->chgParam
!= NULL
)
110 ExecReScanSetParamPlan(sstate
, node
);
112 foreach(l
, node
->subPlan
)
114 SubPlanState
*sstate
= (SubPlanState
*) lfirst(l
);
115 PlanState
*splan
= sstate
->planstate
;
117 if (splan
->plan
->extParam
!= NULL
)
118 UpdateChangedParamSet(splan
, node
->chgParam
);
120 /* Well. Now set chgParam for left/right trees. */
121 if (node
->lefttree
!= NULL
)
122 UpdateChangedParamSet(node
->lefttree
, node
->chgParam
);
123 if (node
->righttree
!= NULL
)
124 UpdateChangedParamSet(node
->righttree
, node
->chgParam
);
127 /* Call expression callbacks */
128 if (node
->ps_ExprContext
)
129 ReScanExprContext(node
->ps_ExprContext
);
131 /* And do node-type-specific processing */
132 switch (nodeTag(node
))
135 ExecReScanResult((ResultState
*) node
);
138 case T_ProjectSetState
:
139 ExecReScanProjectSet((ProjectSetState
*) node
);
142 case T_ModifyTableState
:
143 ExecReScanModifyTable((ModifyTableState
*) node
);
147 ExecReScanAppend((AppendState
*) node
);
150 case T_MergeAppendState
:
151 ExecReScanMergeAppend((MergeAppendState
*) node
);
154 case T_RecursiveUnionState
:
155 ExecReScanRecursiveUnion((RecursiveUnionState
*) node
);
158 case T_BitmapAndState
:
159 ExecReScanBitmapAnd((BitmapAndState
*) node
);
162 case T_BitmapOrState
:
163 ExecReScanBitmapOr((BitmapOrState
*) node
);
167 ExecReScanSeqScan((SeqScanState
*) node
);
170 case T_SampleScanState
:
171 ExecReScanSampleScan((SampleScanState
*) node
);
175 ExecReScanGather((GatherState
*) node
);
178 case T_GatherMergeState
:
179 ExecReScanGatherMerge((GatherMergeState
*) node
);
182 case T_IndexScanState
:
183 ExecReScanIndexScan((IndexScanState
*) node
);
186 case T_IndexOnlyScanState
:
187 ExecReScanIndexOnlyScan((IndexOnlyScanState
*) node
);
190 case T_BitmapIndexScanState
:
191 ExecReScanBitmapIndexScan((BitmapIndexScanState
*) node
);
194 case T_BitmapHeapScanState
:
195 ExecReScanBitmapHeapScan((BitmapHeapScanState
*) node
);
199 ExecReScanTidScan((TidScanState
*) node
);
202 case T_TidRangeScanState
:
203 ExecReScanTidRangeScan((TidRangeScanState
*) node
);
206 case T_SubqueryScanState
:
207 ExecReScanSubqueryScan((SubqueryScanState
*) node
);
210 case T_FunctionScanState
:
211 ExecReScanFunctionScan((FunctionScanState
*) node
);
214 case T_TableFuncScanState
:
215 ExecReScanTableFuncScan((TableFuncScanState
*) node
);
218 case T_ValuesScanState
:
219 ExecReScanValuesScan((ValuesScanState
*) node
);
223 ExecReScanCteScan((CteScanState
*) node
);
226 case T_NamedTuplestoreScanState
:
227 ExecReScanNamedTuplestoreScan((NamedTuplestoreScanState
*) node
);
230 case T_WorkTableScanState
:
231 ExecReScanWorkTableScan((WorkTableScanState
*) node
);
234 case T_ForeignScanState
:
235 ExecReScanForeignScan((ForeignScanState
*) node
);
238 case T_CustomScanState
:
239 ExecReScanCustomScan((CustomScanState
*) node
);
242 case T_NestLoopState
:
243 ExecReScanNestLoop((NestLoopState
*) node
);
246 case T_MergeJoinState
:
247 ExecReScanMergeJoin((MergeJoinState
*) node
);
250 case T_HashJoinState
:
251 ExecReScanHashJoin((HashJoinState
*) node
);
254 case T_MaterialState
:
255 ExecReScanMaterial((MaterialState
*) node
);
259 ExecReScanMemoize((MemoizeState
*) node
);
263 ExecReScanSort((SortState
*) node
);
266 case T_IncrementalSortState
:
267 ExecReScanIncrementalSort((IncrementalSortState
*) node
);
271 ExecReScanGroup((GroupState
*) node
);
275 ExecReScanAgg((AggState
*) node
);
278 case T_WindowAggState
:
279 ExecReScanWindowAgg((WindowAggState
*) node
);
283 ExecReScanUnique((UniqueState
*) node
);
287 ExecReScanHash((HashState
*) node
);
291 ExecReScanSetOp((SetOpState
*) node
);
294 case T_LockRowsState
:
295 ExecReScanLockRows((LockRowsState
*) node
);
299 ExecReScanLimit((LimitState
*) node
);
303 elog(ERROR
, "unrecognized node type: %d", (int) nodeTag(node
));
307 if (node
->chgParam
!= NULL
)
309 bms_free(node
->chgParam
);
310 node
->chgParam
= NULL
;
317 * Marks the current scan position.
319 * NOTE: mark/restore capability is currently needed only for plan nodes
320 * that are the immediate inner child of a MergeJoin node. Since MergeJoin
321 * requires sorted input, there is never any need to support mark/restore in
322 * node types that cannot produce sorted output. There are some cases in
323 * which a node can pass through sorted data from its child; if we don't
324 * implement mark/restore for such a node type, the planner compensates by
325 * inserting a Material node above that node.
328 ExecMarkPos(PlanState
*node
)
330 switch (nodeTag(node
))
332 case T_IndexScanState
:
333 ExecIndexMarkPos((IndexScanState
*) node
);
336 case T_IndexOnlyScanState
:
337 ExecIndexOnlyMarkPos((IndexOnlyScanState
*) node
);
340 case T_CustomScanState
:
341 ExecCustomMarkPos((CustomScanState
*) node
);
344 case T_MaterialState
:
345 ExecMaterialMarkPos((MaterialState
*) node
);
349 ExecSortMarkPos((SortState
*) node
);
353 ExecResultMarkPos((ResultState
*) node
);
357 /* don't make hard error unless caller asks to restore... */
358 elog(DEBUG2
, "unrecognized node type: %d", (int) nodeTag(node
));
366 * restores the scan position previously saved with ExecMarkPos()
368 * NOTE: the semantics of this are that the first ExecProcNode following
369 * the restore operation will yield the same tuple as the first one following
370 * the mark operation. It is unspecified what happens to the plan node's
371 * result TupleTableSlot. (In most cases the result slot is unchanged by
372 * a restore, but the node may choose to clear it or to load it with the
373 * restored-to tuple.) Hence the caller should discard any previously
374 * returned TupleTableSlot after doing a restore.
377 ExecRestrPos(PlanState
*node
)
379 switch (nodeTag(node
))
381 case T_IndexScanState
:
382 ExecIndexRestrPos((IndexScanState
*) node
);
385 case T_IndexOnlyScanState
:
386 ExecIndexOnlyRestrPos((IndexOnlyScanState
*) node
);
389 case T_CustomScanState
:
390 ExecCustomRestrPos((CustomScanState
*) node
);
393 case T_MaterialState
:
394 ExecMaterialRestrPos((MaterialState
*) node
);
398 ExecSortRestrPos((SortState
*) node
);
402 ExecResultRestrPos((ResultState
*) node
);
406 elog(ERROR
, "unrecognized node type: %d", (int) nodeTag(node
));
412 * ExecSupportsMarkRestore - does a Path support mark/restore?
414 * This is used during planning and so must accept a Path, not a Plan.
415 * We keep it here to be adjacent to the routines above, which also must
416 * know which plan types support mark/restore.
419 ExecSupportsMarkRestore(Path
*pathnode
)
422 * For consistency with the routines above, we do not examine the nodeTag
423 * but rather the pathtype, which is the Plan node type the Path would
426 switch (pathnode
->pathtype
)
429 case T_IndexOnlyScan
:
432 * Not all index types support mark/restore.
434 return castNode(IndexPath
, pathnode
)->indexinfo
->amcanmarkpos
;
441 if (castNode(CustomPath
, pathnode
)->flags
& CUSTOMPATH_SUPPORT_MARK_RESTORE
)
448 * Result supports mark/restore iff it has a child plan that does.
450 * We have to be careful here because there is more than one Path
451 * type that can produce a Result plan node.
453 if (IsA(pathnode
, ProjectionPath
))
454 return ExecSupportsMarkRestore(((ProjectionPath
*) pathnode
)->subpath
);
455 else if (IsA(pathnode
, MinMaxAggPath
))
456 return false; /* childless Result */
457 else if (IsA(pathnode
, GroupResultPath
))
458 return false; /* childless Result */
461 /* Simple RTE_RESULT base relation */
462 Assert(IsA(pathnode
, Path
));
463 return false; /* childless Result */
468 AppendPath
*appendPath
= castNode(AppendPath
, pathnode
);
471 * If there's exactly one child, then there will be no Append
472 * in the final plan, so we can handle mark/restore if the
473 * child plan node can.
475 if (list_length(appendPath
->subpaths
) == 1)
476 return ExecSupportsMarkRestore((Path
*) linitial(appendPath
->subpaths
));
477 /* Otherwise, Append can't handle it */
483 MergeAppendPath
*mapath
= castNode(MergeAppendPath
, pathnode
);
486 * Like the Append case above, single-subpath MergeAppends
487 * won't be in the final plan, so just return the child's
488 * mark/restore ability.
490 if (list_length(mapath
->subpaths
) == 1)
491 return ExecSupportsMarkRestore((Path
*) linitial(mapath
->subpaths
));
492 /* Otherwise, MergeAppend can't handle it */
504 * ExecSupportsBackwardScan - does a plan type support backwards scanning?
506 * Ideally, all plan types would support backwards scan, but that seems
507 * unlikely to happen soon. In some cases, a plan node passes the backwards
508 * scan down to its children, and so supports backwards scan only if its
509 * children do. Therefore, this routine must be passed a complete plan tree.
512 ExecSupportsBackwardScan(Plan
*node
)
518 * Parallel-aware nodes return a subset of the tuples in each worker, and
519 * in general we can't expect to have enough bookkeeping state to know
520 * which ones we returned in this worker as opposed to some other worker.
522 if (node
->parallel_aware
)
525 switch (nodeTag(node
))
528 if (outerPlan(node
) != NULL
)
529 return ExecSupportsBackwardScan(outerPlan(node
));
537 /* With async, tuples may be interleaved, so can't back up. */
538 if (((Append
*) node
)->nasyncplans
> 0)
541 foreach(l
, ((Append
*) node
)->appendplans
)
543 if (!ExecSupportsBackwardScan((Plan
*) lfirst(l
)))
546 /* need not check tlist because Append doesn't evaluate it */
551 /* Simplify life for tablesample methods by disallowing this */
558 return IndexSupportsBackwardScan(((IndexScan
*) node
)->indexid
);
560 case T_IndexOnlyScan
:
561 return IndexSupportsBackwardScan(((IndexOnlyScan
*) node
)->indexid
);
564 return ExecSupportsBackwardScan(((SubqueryScan
*) node
)->subplan
);
567 if (((CustomScan
*) node
)->flags
& CUSTOMPATH_SUPPORT_BACKWARD_SCAN
)
579 /* these don't evaluate tlist */
582 case T_IncrementalSort
:
585 * Unlike full sort, incremental sort keeps only a single group of
586 * tuples in memory, so it can't scan backwards.
592 return ExecSupportsBackwardScan(outerPlan(node
));
600 * An IndexScan or IndexOnlyScan node supports backward scan only if the
604 IndexSupportsBackwardScan(Oid indexid
)
608 Form_pg_class idxrelrec
;
609 IndexAmRoutine
*amroutine
;
611 /* Fetch the pg_class tuple of the index relation */
612 ht_idxrel
= SearchSysCache1(RELOID
, ObjectIdGetDatum(indexid
));
613 if (!HeapTupleIsValid(ht_idxrel
))
614 elog(ERROR
, "cache lookup failed for relation %u", indexid
);
615 idxrelrec
= (Form_pg_class
) GETSTRUCT(ht_idxrel
);
617 /* Fetch the index AM's API struct */
618 amroutine
= GetIndexAmRoutineByAmId(idxrelrec
->relam
, false);
620 result
= amroutine
->amcanbackward
;
623 ReleaseSysCache(ht_idxrel
);
629 * ExecMaterializesOutput - does a plan type materialize its output?
631 * Returns true if the plan node type is one that automatically materializes
632 * its output (typically by keeping it in a tuplestore). For such plans,
633 * a rescan without any parameter change will have zero startup cost and
634 * very low per-tuple cost.
637 ExecMaterializesOutput(NodeTag plantype
)
643 case T_TableFuncScan
:
645 case T_NamedTuplestoreScan
:
646 case T_WorkTableScan
: