PostgreSQL Source Code git master
Loading...
Searching...
No Matches
execAmi.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * execAmi.c
4 * miscellaneous executor access method routines
5 *
6 * Portions Copyright (c) 1996-2026, 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/instrument.h"
20#include "executor/nodeAgg.h"
21#include "executor/nodeAppend.h"
27#include "executor/nodeCustom.h"
30#include "executor/nodeGather.h"
32#include "executor/nodeGroup.h"
33#include "executor/nodeHash.h"
38#include "executor/nodeLimit.h"
49#include "executor/nodeResult.h"
52#include "executor/nodeSetOp.h"
53#include "executor/nodeSort.h"
59#include "executor/nodeUnique.h"
63#include "nodes/extensible.h"
64#include "nodes/pathnodes.h"
65#include "utils/syscache.h"
66
67static bool IndexSupportsBackwardScan(Oid indexid);
68
69
70/*
71 * ExecReScan
72 * Reset a plan node so that its output can be re-scanned.
73 *
74 * Note that if the plan node has parameters that have changed value,
75 * the output might be different from last time.
76 */
77void
79{
80 /* If collecting timing stats, update them */
81 if (node->instrument)
83
84 /*
85 * If we have changed parameters, propagate that info.
86 *
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
95 * InitPlans).
96 */
97 if (node->chgParam != NULL)
98 {
99 ListCell *l;
100
101 foreach(l, node->initPlan)
102 {
103 SubPlanState *sstate = (SubPlanState *) lfirst(l);
104 PlanState *splan = sstate->planstate;
105
106 if (splan->plan->extParam != NULL) /* don't care about child
107 * local Params */
108 UpdateChangedParamSet(splan, node->chgParam);
109 if (splan->chgParam != NULL)
110 ExecReScanSetParamPlan(sstate, node);
111 }
112 foreach(l, node->subPlan)
113 {
114 SubPlanState *sstate = (SubPlanState *) lfirst(l);
115 PlanState *splan = sstate->planstate;
116
117 if (splan->plan->extParam != NULL)
118 UpdateChangedParamSet(splan, node->chgParam);
119 }
120 /* Well. Now set chgParam for child trees. */
121 if (outerPlanState(node) != NULL)
123 if (innerPlanState(node) != NULL)
125 }
126
127 /* Call expression callbacks */
128 if (node->ps_ExprContext)
130
131 /* And do node-type-specific processing */
132 switch (nodeTag(node))
133 {
134 case T_ResultState:
136 break;
137
140 break;
141
144 break;
145
146 case T_AppendState:
148 break;
149
152 break;
153
156 break;
157
158 case T_BitmapAndState:
160 break;
161
162 case T_BitmapOrState:
164 break;
165
166 case T_SeqScanState:
168 break;
169
172 break;
173
174 case T_GatherState:
176 break;
177
180 break;
181
182 case T_IndexScanState:
184 break;
185
188 break;
189
192 break;
193
196 break;
197
198 case T_TidScanState:
200 break;
201
204 break;
205
208 break;
209
212 break;
213
216 break;
217
220 break;
221
222 case T_CteScanState:
224 break;
225
228 break;
229
232 break;
233
236 break;
237
240 break;
241
242 case T_NestLoopState:
244 break;
245
246 case T_MergeJoinState:
248 break;
249
250 case T_HashJoinState:
252 break;
253
254 case T_MaterialState:
256 break;
257
258 case T_MemoizeState:
260 break;
261
262 case T_SortState:
263 ExecReScanSort((SortState *) node);
264 break;
265
268 break;
269
270 case T_GroupState:
271 ExecReScanGroup((GroupState *) node);
272 break;
273
274 case T_AggState:
275 ExecReScanAgg((AggState *) node);
276 break;
277
278 case T_WindowAggState:
280 break;
281
282 case T_UniqueState:
284 break;
285
286 case T_HashState:
287 ExecReScanHash((HashState *) node);
288 break;
289
290 case T_SetOpState:
291 ExecReScanSetOp((SetOpState *) node);
292 break;
293
294 case T_LockRowsState:
296 break;
297
298 case T_LimitState:
299 ExecReScanLimit((LimitState *) node);
300 break;
301
302 default:
303 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
304 break;
305 }
306
307 if (node->chgParam != NULL)
308 {
309 bms_free(node->chgParam);
310 node->chgParam = NULL;
311 }
312}
313
314/*
315 * ExecMarkPos
316 *
317 * Marks the current scan position.
318 *
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.
326 */
327void
329{
330 switch (nodeTag(node))
331 {
332 case T_IndexScanState:
334 break;
335
338 break;
339
342 break;
343
344 case T_MaterialState:
346 break;
347
348 case T_SortState:
349 ExecSortMarkPos((SortState *) node);
350 break;
351
352 case T_ResultState:
354 break;
355
356 default:
357 /* don't make hard error unless caller asks to restore... */
358 elog(DEBUG2, "unrecognized node type: %d", (int) nodeTag(node));
359 break;
360 }
361}
362
363/*
364 * ExecRestrPos
365 *
366 * restores the scan position previously saved with ExecMarkPos()
367 *
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.
375 */
376void
378{
379 switch (nodeTag(node))
380 {
381 case T_IndexScanState:
383 break;
384
387 break;
388
391 break;
392
393 case T_MaterialState:
395 break;
396
397 case T_SortState:
398 ExecSortRestrPos((SortState *) node);
399 break;
400
401 case T_ResultState:
403 break;
404
405 default:
406 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
407 break;
408 }
409}
410
411/*
412 * ExecSupportsMarkRestore - does a Path support mark/restore?
413 *
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.
417 */
418bool
420{
421 /*
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
424 * produce.
425 */
426 switch (pathnode->pathtype)
427 {
428 case T_IndexScan:
429 case T_IndexOnlyScan:
430
431 /*
432 * Not all index types support mark/restore.
433 */
434 return castNode(IndexPath, pathnode)->indexinfo->amcanmarkpos;
435
436 case T_Material:
437 case T_Sort:
438 return true;
439
440 case T_CustomScan:
442 return true;
443 return false;
444
445 case T_Result:
446
447 /*
448 * Result supports mark/restore iff it has a child plan that does.
449 *
450 * We have to be careful here because there is more than one Path
451 * type that can produce a Result plan node.
452 */
455 else if (IsA(pathnode, MinMaxAggPath))
456 return false; /* childless Result */
457 else if (IsA(pathnode, GroupResultPath))
458 return false; /* childless Result */
459 else
460 {
461 /* Simple RTE_RESULT base relation */
463 return false; /* childless Result */
464 }
465
466 case T_Append:
467 {
469
470 /*
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.
474 */
475 if (list_length(appendPath->subpaths) == 1)
476 return ExecSupportsMarkRestore((Path *) linitial(appendPath->subpaths));
477 /* Otherwise, Append can't handle it */
478 return false;
479 }
480
481 case T_MergeAppend:
482 {
484
485 /*
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.
489 */
490 if (list_length(mapath->subpaths) == 1)
491 return ExecSupportsMarkRestore((Path *) linitial(mapath->subpaths));
492 /* Otherwise, MergeAppend can't handle it */
493 return false;
494 }
495
496 default:
497 break;
498 }
499
500 return false;
501}
502
503/*
504 * ExecSupportsBackwardScan - does a plan type support backwards scanning?
505 *
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.
510 */
511bool
513{
514 if (node == NULL)
515 return false;
516
517 /*
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.
521 */
522 if (node->parallel_aware)
523 return false;
524
525 switch (nodeTag(node))
526 {
527 case T_Result:
528 if (outerPlan(node) != NULL)
530 else
531 return false;
532
533 case T_Append:
534 {
535 ListCell *l;
536
537 /* With async, tuples may be interleaved, so can't back up. */
538 if (((Append *) node)->nasyncplans > 0)
539 return false;
540
541 foreach(l, ((Append *) node)->appendplans)
542 {
544 return false;
545 }
546 /* need not check tlist because Append doesn't evaluate it */
547 return true;
548 }
549
550 case T_SampleScan:
551 /* Simplify life for tablesample methods by disallowing this */
552 return false;
553
554 case T_Gather:
555 return false;
556
557 case T_IndexScan:
558 return IndexSupportsBackwardScan(((IndexScan *) node)->indexid);
559
560 case T_IndexOnlyScan:
561 return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid);
562
563 case T_SubqueryScan:
564 return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
565
566 case T_CustomScan:
567 if (((CustomScan *) node)->flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
568 return true;
569 return false;
570
571 case T_SeqScan:
572 case T_TidScan:
573 case T_TidRangeScan:
574 case T_FunctionScan:
575 case T_ValuesScan:
576 case T_CteScan:
577 case T_Material:
578 case T_Sort:
579 /* these don't evaluate tlist */
580 return true;
581
583
584 /*
585 * Unlike full sort, incremental sort keeps only a single group of
586 * tuples in memory, so it can't scan backwards.
587 */
588 return false;
589
590 case T_LockRows:
591 case T_Limit:
593
594 default:
595 return false;
596 }
597}
598
599/*
600 * An IndexScan or IndexOnlyScan node supports backward scan only if the
601 * index's AM does.
602 */
603static bool
605{
606 bool result;
610
611 /* Fetch the pg_class tuple of the index relation */
614 elog(ERROR, "cache lookup failed for relation %u", indexid);
616
617 /* Fetch the index AM's API struct */
619
620 result = amroutine->amcanbackward;
621
623
624 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 */
635bool
637{
638 switch (plantype)
639 {
640 case T_Material:
641 case T_FunctionScan:
642 case T_TableFuncScan:
643 case T_CteScan:
645 case T_WorkTableScan:
646 case T_Sort:
647 return true;
648
649 default:
650 break;
651 }
652
653 return false;
654}
const IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition amapi.c:69
void bms_free(Bitmapset *a)
Definition bitmapset.c:239
#define Assert(condition)
Definition c.h:945
#define DEBUG2
Definition elog.h:29
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
void ExecMarkPos(PlanState *node)
Definition execAmi.c:328
bool ExecSupportsMarkRestore(Path *pathnode)
Definition execAmi.c:419
static bool IndexSupportsBackwardScan(Oid indexid)
Definition execAmi.c:604
bool ExecMaterializesOutput(NodeTag plantype)
Definition execAmi.c:636
bool ExecSupportsBackwardScan(Plan *node)
Definition execAmi.c:512
void ExecReScan(PlanState *node)
Definition execAmi.c:78
void ExecRestrPos(PlanState *node)
Definition execAmi.c:377
void ReScanExprContext(ExprContext *econtext)
Definition execUtils.c:448
void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
Definition execUtils.c:915
#define outerPlanState(node)
Definition execnodes.h:1273
#define innerPlanState(node)
Definition execnodes.h:1272
#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN
Definition extensible.h:84
#define CUSTOMPATH_SUPPORT_MARK_RESTORE
Definition extensible.h:85
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
void InstrEndLoop(Instrumentation *instr)
Definition instrument.c:144
Datum subpath(PG_FUNCTION_ARGS)
Definition ltree_op.c:311
void ExecReScanAgg(AggState *node)
Definition nodeAgg.c:4462
void ExecReScanAppend(AppendState *node)
Definition nodeAppend.c:423
void ExecReScanBitmapAnd(BitmapAndState *node)
void ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
void ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
void ExecReScanBitmapOr(BitmapOrState *node)
void ExecReScanCteScan(CteScanState *node)
void ExecCustomRestrPos(CustomScanState *node)
Definition nodeCustom.c:150
void ExecReScanCustomScan(CustomScanState *node)
Definition nodeCustom.c:132
void ExecCustomMarkPos(CustomScanState *node)
Definition nodeCustom.c:139
void ExecReScanForeignScan(ForeignScanState *node)
void ExecReScanFunctionScan(FunctionScanState *node)
void ExecReScanGatherMerge(GatherMergeState *node)
void ExecReScanGather(GatherState *node)
Definition nodeGather.c:443
void ExecReScanGroup(GroupState *node)
Definition nodeGroup.c:236
void ExecReScanHash(HashState *node)
Definition nodeHash.c:2407
void ExecReScanHashJoin(HashJoinState *node)
void ExecReScanIncrementalSort(IncrementalSortState *node)
void ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
void ExecIndexOnlyRestrPos(IndexOnlyScanState *node)
void ExecIndexOnlyMarkPos(IndexOnlyScanState *node)
void ExecReScanIndexScan(IndexScanState *node)
void ExecIndexRestrPos(IndexScanState *node)
void ExecIndexMarkPos(IndexScanState *node)
void ExecReScanLimit(LimitState *node)
Definition nodeLimit.c:541
void ExecReScanLockRows(LockRowsState *node)
void ExecReScanMaterial(MaterialState *node)
void ExecMaterialMarkPos(MaterialState *node)
void ExecMaterialRestrPos(MaterialState *node)
void ExecReScanMemoize(MemoizeState *node)
void ExecReScanMergeAppend(MergeAppendState *node)
void ExecReScanMergeJoin(MergeJoinState *node)
void ExecReScanModifyTable(ModifyTableState *node)
void ExecReScanNamedTuplestoreScan(NamedTuplestoreScanState *node)
void ExecReScanNestLoop(NestLoopState *node)
void ExecReScanProjectSet(ProjectSetState *node)
void ExecReScanRecursiveUnion(RecursiveUnionState *node)
void ExecReScanResult(ResultState *node)
Definition nodeResult.c:249
void ExecResultRestrPos(ResultState *node)
Definition nodeResult.c:161
void ExecResultMarkPos(ResultState *node)
Definition nodeResult.c:146
void ExecReScanSampleScan(SampleScanState *node)
void ExecReScanSeqScan(SeqScanState *node)
void ExecReScanSetOp(SetOpState *node)
Definition nodeSetOp.c:704
void ExecSortMarkPos(SortState *node)
Definition nodeSort.c:329
void ExecReScanSort(SortState *node)
Definition nodeSort.c:362
void ExecSortRestrPos(SortState *node)
Definition nodeSort.c:347
void ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
void ExecReScanSubqueryScan(SubqueryScanState *node)
void ExecReScanTableFuncScan(TableFuncScanState *node)
void ExecReScanTidRangeScan(TidRangeScanState *node)
void ExecReScanTidScan(TidScanState *node)
void ExecReScanUnique(UniqueState *node)
Definition nodeUnique.c:175
void ExecReScanValuesScan(ValuesScanState *node)
void ExecReScanWindowAgg(WindowAggState *node)
void ExecReScanWorkTableScan(WorkTableScanState *node)
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define nodeTag(nodeptr)
Definition nodes.h:139
NodeTag
Definition nodes.h:27
#define castNode(_type_, nodeptr)
Definition nodes.h:182
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
#define linitial(l)
Definition pg_list.h:178
#define outerPlan(node)
Definition plannodes.h:265
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
unsigned int Oid
static int fb(int x)
Instrumentation * instrument
Definition execnodes.h:1187
Plan * plan
Definition execnodes.h:1177
List * subPlan
Definition execnodes.h:1204
List * initPlan
Definition execnodes.h:1202
Bitmapset * chgParam
Definition execnodes.h:1209
ExprContext * ps_ExprContext
Definition execnodes.h:1216
Bitmapset * extParam
Definition plannodes.h:253
bool parallel_aware
Definition plannodes.h:217
PlanState * planstate
Definition execnodes.h:1025
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:220