Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * execAmi.c
4 : * miscellaneous executor access method routines
5 : *
6 : * Portions Copyright (c) 1996-2024, 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/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"
64 :
65 : static bool IndexSupportsBackwardScan(Oid indexid);
66 :
67 :
68 : /*
69 : * ExecReScan
70 : * Reset a plan node so that its output can be re-scanned.
71 : *
72 : * Note that if the plan node has parameters that have changed value,
73 : * the output might be different from last time.
74 : */
75 : void
76 2589514 : ExecReScan(PlanState *node)
77 : {
78 : /* If collecting timing stats, update them */
79 2589514 : if (node->instrument)
80 42190 : InstrEndLoop(node->instrument);
81 :
82 : /*
83 : * If we have changed parameters, propagate that info.
84 : *
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
93 : * InitPlans).
94 : */
95 2589514 : if (node->chgParam != NULL)
96 : {
97 : ListCell *l;
98 :
99 2327086 : foreach(l, node->initPlan)
100 : {
101 1470 : SubPlanState *sstate = (SubPlanState *) lfirst(l);
102 1470 : PlanState *splan = sstate->planstate;
103 :
104 1470 : if (splan->plan->extParam != NULL) /* don't care about child
105 : * local Params */
106 1322 : UpdateChangedParamSet(splan, node->chgParam);
107 1470 : if (splan->chgParam != NULL)
108 1082 : ExecReScanSetParamPlan(sstate, node);
109 : }
110 2326458 : foreach(l, node->subPlan)
111 : {
112 842 : SubPlanState *sstate = (SubPlanState *) lfirst(l);
113 842 : PlanState *splan = sstate->planstate;
114 :
115 842 : if (splan->plan->extParam != NULL)
116 836 : UpdateChangedParamSet(splan, node->chgParam);
117 : }
118 : /* Well. Now set chgParam for child trees. */
119 2325616 : if (outerPlanState(node) != NULL)
120 652820 : UpdateChangedParamSet(outerPlanState(node), node->chgParam);
121 2325616 : if (innerPlanState(node) != NULL)
122 13826 : UpdateChangedParamSet(innerPlanState(node), node->chgParam);
123 : }
124 :
125 : /* Call expression callbacks */
126 2589514 : if (node->ps_ExprContext)
127 2377792 : ReScanExprContext(node->ps_ExprContext);
128 :
129 : /* And do node-type-specific processing */
130 2589514 : switch (nodeTag(node))
131 : {
132 46112 : case T_ResultState:
133 46112 : ExecReScanResult((ResultState *) node);
134 46112 : break;
135 :
136 18106 : case T_ProjectSetState:
137 18106 : ExecReScanProjectSet((ProjectSetState *) node);
138 18106 : break;
139 :
140 0 : case T_ModifyTableState:
141 0 : ExecReScanModifyTable((ModifyTableState *) node);
142 0 : break;
143 :
144 22692 : case T_AppendState:
145 22692 : ExecReScanAppend((AppendState *) node);
146 22692 : break;
147 :
148 18 : case T_MergeAppendState:
149 18 : ExecReScanMergeAppend((MergeAppendState *) node);
150 18 : break;
151 :
152 12 : case T_RecursiveUnionState:
153 12 : ExecReScanRecursiveUnion((RecursiveUnionState *) node);
154 12 : break;
155 :
156 62 : case T_BitmapAndState:
157 62 : ExecReScanBitmapAnd((BitmapAndState *) node);
158 62 : break;
159 :
160 30 : case T_BitmapOrState:
161 30 : ExecReScanBitmapOr((BitmapOrState *) node);
162 30 : break;
163 :
164 1028842 : case T_SeqScanState:
165 1028842 : ExecReScanSeqScan((SeqScanState *) node);
166 1028842 : break;
167 :
168 58 : case T_SampleScanState:
169 58 : ExecReScanSampleScan((SampleScanState *) node);
170 58 : break;
171 :
172 300 : case T_GatherState:
173 300 : ExecReScanGather((GatherState *) node);
174 300 : break;
175 :
176 48 : case T_GatherMergeState:
177 48 : ExecReScanGatherMerge((GatherMergeState *) node);
178 48 : break;
179 :
180 413254 : case T_IndexScanState:
181 413254 : ExecReScanIndexScan((IndexScanState *) node);
182 413248 : break;
183 :
184 90900 : case T_IndexOnlyScanState:
185 90900 : ExecReScanIndexOnlyScan((IndexOnlyScanState *) node);
186 90900 : break;
187 :
188 5496 : case T_BitmapIndexScanState:
189 5496 : ExecReScanBitmapIndexScan((BitmapIndexScanState *) node);
190 5496 : break;
191 :
192 4958 : case T_BitmapHeapScanState:
193 4958 : ExecReScanBitmapHeapScan((BitmapHeapScanState *) node);
194 4958 : break;
195 :
196 18 : case T_TidScanState:
197 18 : ExecReScanTidScan((TidScanState *) node);
198 18 : break;
199 :
200 66 : case T_TidRangeScanState:
201 66 : ExecReScanTidRangeScan((TidRangeScanState *) node);
202 66 : break;
203 :
204 2198 : case T_SubqueryScanState:
205 2198 : ExecReScanSubqueryScan((SubqueryScanState *) node);
206 2198 : break;
207 :
208 112808 : case T_FunctionScanState:
209 112808 : ExecReScanFunctionScan((FunctionScanState *) node);
210 112808 : break;
211 :
212 444 : case T_TableFuncScanState:
213 444 : ExecReScanTableFuncScan((TableFuncScanState *) node);
214 444 : break;
215 :
216 60398 : case T_ValuesScanState:
217 60398 : ExecReScanValuesScan((ValuesScanState *) node);
218 60398 : break;
219 :
220 5906 : case T_CteScanState:
221 5906 : ExecReScanCteScan((CteScanState *) node);
222 5906 : break;
223 :
224 0 : case T_NamedTuplestoreScanState:
225 0 : ExecReScanNamedTuplestoreScan((NamedTuplestoreScanState *) node);
226 0 : break;
227 :
228 6302 : case T_WorkTableScanState:
229 6302 : ExecReScanWorkTableScan((WorkTableScanState *) node);
230 6302 : break;
231 :
232 808 : case T_ForeignScanState:
233 808 : ExecReScanForeignScan((ForeignScanState *) node);
234 808 : break;
235 :
236 0 : case T_CustomScanState:
237 0 : ExecReScanCustomScan((CustomScanState *) node);
238 0 : break;
239 :
240 11950 : case T_NestLoopState:
241 11950 : ExecReScanNestLoop((NestLoopState *) node);
242 11950 : break;
243 :
244 478 : case T_MergeJoinState:
245 478 : ExecReScanMergeJoin((MergeJoinState *) node);
246 478 : break;
247 :
248 2344 : case T_HashJoinState:
249 2344 : ExecReScanHashJoin((HashJoinState *) node);
250 2344 : break;
251 :
252 139542 : case T_MaterialState:
253 139542 : ExecReScanMaterial((MaterialState *) node);
254 139542 : break;
255 :
256 515084 : case T_MemoizeState:
257 515084 : ExecReScanMemoize((MemoizeState *) node);
258 515084 : break;
259 :
260 47110 : case T_SortState:
261 47110 : ExecReScanSort((SortState *) node);
262 47110 : break;
263 :
264 12 : case T_IncrementalSortState:
265 12 : ExecReScanIncrementalSort((IncrementalSortState *) node);
266 12 : break;
267 :
268 24 : case T_GroupState:
269 24 : ExecReScanGroup((GroupState *) node);
270 24 : break;
271 :
272 50076 : case T_AggState:
273 50076 : ExecReScanAgg((AggState *) node);
274 50076 : break;
275 :
276 78 : case T_WindowAggState:
277 78 : ExecReScanWindowAgg((WindowAggState *) node);
278 78 : break;
279 :
280 0 : case T_UniqueState:
281 0 : ExecReScanUnique((UniqueState *) node);
282 0 : break;
283 :
284 1314 : case T_HashState:
285 1314 : ExecReScanHash((HashState *) node);
286 1314 : break;
287 :
288 600 : case T_SetOpState:
289 600 : ExecReScanSetOp((SetOpState *) node);
290 600 : break;
291 :
292 16 : case T_LockRowsState:
293 16 : ExecReScanLockRows((LockRowsState *) node);
294 16 : break;
295 :
296 1050 : case T_LimitState:
297 1050 : ExecReScanLimit((LimitState *) node);
298 1050 : break;
299 :
300 0 : default:
301 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
302 : break;
303 : }
304 :
305 2589508 : if (node->chgParam != NULL)
306 : {
307 2325616 : bms_free(node->chgParam);
308 2325616 : node->chgParam = NULL;
309 : }
310 2589508 : }
311 :
312 : /*
313 : * ExecMarkPos
314 : *
315 : * Marks the current scan position.
316 : *
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.
324 : */
325 : void
326 711928 : ExecMarkPos(PlanState *node)
327 : {
328 711928 : switch (nodeTag(node))
329 : {
330 6040 : case T_IndexScanState:
331 6040 : ExecIndexMarkPos((IndexScanState *) node);
332 6040 : break;
333 :
334 124004 : case T_IndexOnlyScanState:
335 124004 : ExecIndexOnlyMarkPos((IndexOnlyScanState *) node);
336 124004 : break;
337 :
338 0 : case T_CustomScanState:
339 0 : ExecCustomMarkPos((CustomScanState *) node);
340 0 : break;
341 :
342 6440 : case T_MaterialState:
343 6440 : ExecMaterialMarkPos((MaterialState *) node);
344 6440 : break;
345 :
346 575444 : case T_SortState:
347 575444 : ExecSortMarkPos((SortState *) node);
348 575444 : break;
349 :
350 0 : case T_ResultState:
351 0 : ExecResultMarkPos((ResultState *) node);
352 0 : break;
353 :
354 0 : default:
355 : /* don't make hard error unless caller asks to restore... */
356 0 : elog(DEBUG2, "unrecognized node type: %d", (int) nodeTag(node));
357 0 : break;
358 : }
359 711928 : }
360 :
361 : /*
362 : * ExecRestrPos
363 : *
364 : * restores the scan position previously saved with ExecMarkPos()
365 : *
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.
373 : */
374 : void
375 138378 : ExecRestrPos(PlanState *node)
376 : {
377 138378 : switch (nodeTag(node))
378 : {
379 54018 : case T_IndexScanState:
380 54018 : ExecIndexRestrPos((IndexScanState *) node);
381 54018 : break;
382 :
383 0 : case T_IndexOnlyScanState:
384 0 : ExecIndexOnlyRestrPos((IndexOnlyScanState *) node);
385 0 : break;
386 :
387 0 : case T_CustomScanState:
388 0 : ExecCustomRestrPos((CustomScanState *) node);
389 0 : break;
390 :
391 54032 : case T_MaterialState:
392 54032 : ExecMaterialRestrPos((MaterialState *) node);
393 54032 : break;
394 :
395 30328 : case T_SortState:
396 30328 : ExecSortRestrPos((SortState *) node);
397 30328 : break;
398 :
399 0 : case T_ResultState:
400 0 : ExecResultRestrPos((ResultState *) node);
401 0 : break;
402 :
403 0 : default:
404 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
405 : break;
406 : }
407 138378 : }
408 :
409 : /*
410 : * ExecSupportsMarkRestore - does a Path support mark/restore?
411 : *
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.
415 : */
416 : bool
417 10840 : ExecSupportsMarkRestore(Path *pathnode)
418 : {
419 : /*
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
422 : * produce.
423 : */
424 10840 : switch (pathnode->pathtype)
425 : {
426 9432 : case T_IndexScan:
427 : case T_IndexOnlyScan:
428 :
429 : /*
430 : * Not all index types support mark/restore.
431 : */
432 9432 : return castNode(IndexPath, pathnode)->indexinfo->amcanmarkpos;
433 :
434 0 : case T_Material:
435 : case T_Sort:
436 0 : return true;
437 :
438 0 : case T_CustomScan:
439 0 : if (castNode(CustomPath, pathnode)->flags & CUSTOMPATH_SUPPORT_MARK_RESTORE)
440 0 : return true;
441 0 : return false;
442 :
443 0 : case T_Result:
444 :
445 : /*
446 : * Result supports mark/restore iff it has a child plan that does.
447 : *
448 : * We have to be careful here because there is more than one Path
449 : * type that can produce a Result plan node.
450 : */
451 0 : if (IsA(pathnode, ProjectionPath))
452 0 : return ExecSupportsMarkRestore(((ProjectionPath *) pathnode)->subpath);
453 0 : else if (IsA(pathnode, MinMaxAggPath))
454 0 : return false; /* childless Result */
455 0 : else if (IsA(pathnode, GroupResultPath))
456 0 : return false; /* childless Result */
457 : else
458 : {
459 : /* Simple RTE_RESULT base relation */
460 : Assert(IsA(pathnode, Path));
461 0 : return false; /* childless Result */
462 : }
463 :
464 84 : case T_Append:
465 : {
466 84 : AppendPath *appendPath = castNode(AppendPath, pathnode);
467 :
468 : /*
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.
472 : */
473 84 : if (list_length(appendPath->subpaths) == 1)
474 0 : return ExecSupportsMarkRestore((Path *) linitial(appendPath->subpaths));
475 : /* Otherwise, Append can't handle it */
476 84 : return false;
477 : }
478 :
479 44 : case T_MergeAppend:
480 : {
481 44 : MergeAppendPath *mapath = castNode(MergeAppendPath, pathnode);
482 :
483 : /*
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.
487 : */
488 44 : if (list_length(mapath->subpaths) == 1)
489 0 : return ExecSupportsMarkRestore((Path *) linitial(mapath->subpaths));
490 : /* Otherwise, MergeAppend can't handle it */
491 44 : return false;
492 : }
493 :
494 1280 : default:
495 1280 : break;
496 : }
497 :
498 1280 : return false;
499 : }
500 :
501 : /*
502 : * ExecSupportsBackwardScan - does a plan type support backwards scanning?
503 : *
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.
508 : */
509 : bool
510 3222 : ExecSupportsBackwardScan(Plan *node)
511 : {
512 3222 : if (node == NULL)
513 0 : return false;
514 :
515 : /*
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.
519 : */
520 3222 : if (node->parallel_aware)
521 0 : return false;
522 :
523 3222 : switch (nodeTag(node))
524 : {
525 70 : case T_Result:
526 70 : if (outerPlan(node) != NULL)
527 0 : return ExecSupportsBackwardScan(outerPlan(node));
528 : else
529 70 : return false;
530 :
531 40 : case T_Append:
532 : {
533 : ListCell *l;
534 :
535 : /* With async, tuples may be interleaved, so can't back up. */
536 40 : if (((Append *) node)->nasyncplans > 0)
537 0 : return false;
538 :
539 136 : foreach(l, ((Append *) node)->appendplans)
540 : {
541 98 : if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
542 2 : return false;
543 : }
544 : /* need not check tlist because Append doesn't evaluate it */
545 38 : return true;
546 : }
547 :
548 6 : case T_SampleScan:
549 : /* Simplify life for tablesample methods by disallowing this */
550 6 : return false;
551 :
552 0 : case T_Gather:
553 0 : return false;
554 :
555 400 : case T_IndexScan:
556 400 : return IndexSupportsBackwardScan(((IndexScan *) node)->indexid);
557 :
558 44 : case T_IndexOnlyScan:
559 44 : return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid);
560 :
561 0 : case T_SubqueryScan:
562 0 : return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
563 :
564 0 : case T_CustomScan:
565 0 : if (((CustomScan *) node)->flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
566 0 : return true;
567 0 : return false;
568 :
569 1780 : case T_SeqScan:
570 : case T_TidScan:
571 : case T_TidRangeScan:
572 : case T_FunctionScan:
573 : case T_ValuesScan:
574 : case T_CteScan:
575 : case T_Material:
576 : case T_Sort:
577 : /* these don't evaluate tlist */
578 1780 : return true;
579 :
580 4 : case T_IncrementalSort:
581 :
582 : /*
583 : * Unlike full sort, incremental sort keeps only a single group of
584 : * tuples in memory, so it can't scan backwards.
585 : */
586 4 : return false;
587 :
588 146 : case T_LockRows:
589 : case T_Limit:
590 146 : return ExecSupportsBackwardScan(outerPlan(node));
591 :
592 732 : default:
593 732 : return false;
594 : }
595 : }
596 :
597 : /*
598 : * An IndexScan or IndexOnlyScan node supports backward scan only if the
599 : * index's AM does.
600 : */
601 : static bool
602 444 : IndexSupportsBackwardScan(Oid indexid)
603 : {
604 : bool result;
605 : HeapTuple ht_idxrel;
606 : Form_pg_class idxrelrec;
607 : IndexAmRoutine *amroutine;
608 :
609 : /* Fetch the pg_class tuple of the index relation */
610 444 : ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid));
611 444 : if (!HeapTupleIsValid(ht_idxrel))
612 0 : elog(ERROR, "cache lookup failed for relation %u", indexid);
613 444 : idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
614 :
615 : /* Fetch the index AM's API struct */
616 444 : amroutine = GetIndexAmRoutineByAmId(idxrelrec->relam, false);
617 :
618 444 : result = amroutine->amcanbackward;
619 :
620 444 : pfree(amroutine);
621 444 : ReleaseSysCache(ht_idxrel);
622 :
623 444 : return result;
624 : }
625 :
626 : /*
627 : * ExecMaterializesOutput - does a plan type materialize its output?
628 : *
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.
633 : */
634 : bool
635 476914 : ExecMaterializesOutput(NodeTag plantype)
636 : {
637 476914 : switch (plantype)
638 : {
639 21828 : case T_Material:
640 : case T_FunctionScan:
641 : case T_TableFuncScan:
642 : case T_CteScan:
643 : case T_NamedTuplestoreScan:
644 : case T_WorkTableScan:
645 : case T_Sort:
646 21828 : return true;
647 :
648 455086 : default:
649 455086 : break;
650 : }
651 :
652 455086 : return false;
653 : }
|