Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * execAmi.c
4 : * miscellaneous executor access method routines
5 : *
6 : * Portions Copyright (c) 1996-2023, 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 "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"
66 :
67 : static 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 : */
77 : void
4654 tgl 78 CBC 1438555 : ExecReScan(PlanState *node)
79 : {
80 : /* If collecting timing stats, update them */
7873 81 1438555 : if (node->instrument)
82 14807 : InstrEndLoop(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 : */
7364 97 1438555 : if (node->chgParam != NULL)
98 : {
99 : ListCell *l;
100 :
6892 neilc 101 1062137 : foreach(l, node->initPlan)
102 : {
103 620 : SubPlanState *sstate = (SubPlanState *) lfirst(l);
7422 tgl 104 620 : PlanState *splan = sstate->planstate;
105 :
7364 106 620 : if (splan->plan->extParam != NULL) /* don't care about child
107 : * local Params */
108 543 : UpdateChangedParamSet(splan, node->chgParam);
109 620 : if (splan->chgParam != NULL)
7422 110 423 : ExecReScanSetParamPlan(sstate, node);
111 : }
6892 neilc 112 1062322 : foreach(l, node->subPlan)
113 : {
114 805 : SubPlanState *sstate = (SubPlanState *) lfirst(l);
7422 tgl 115 805 : PlanState *splan = sstate->planstate;
116 :
7364 117 805 : if (splan->plan->extParam != NULL)
118 802 : UpdateChangedParamSet(splan, node->chgParam);
119 : }
120 : /* Well. Now set chgParam for child trees. */
276 tgl 121 GNC 1061517 : if (outerPlanState(node) != NULL)
122 373034 : UpdateChangedParamSet(outerPlanState(node), node->chgParam);
123 1061517 : if (innerPlanState(node) != NULL)
124 6047 : UpdateChangedParamSet(innerPlanState(node), node->chgParam);
125 : }
126 :
127 : /* Call expression callbacks */
7052 tgl 128 CBC 1438555 : if (node->ps_ExprContext)
129 1109915 : ReScanExprContext(node->ps_ExprContext);
130 :
131 : /* And do node-type-specific processing */
9345 bruce 132 1438555 : switch (nodeTag(node))
133 : {
7430 tgl 134 83622 : case T_ResultState:
4654 135 83622 : ExecReScanResult((ResultState *) node);
9186 vadim4o 136 83622 : break;
137 :
2272 andres 138 39712 : case T_ProjectSetState:
139 39712 : ExecReScanProjectSet((ProjectSetState *) node);
140 39712 : break;
141 :
4929 tgl 142 UBC 0 : case T_ModifyTableState:
4654 143 0 : ExecReScanModifyTable((ModifyTableState *) node);
4929 144 0 : break;
145 :
7430 tgl 146 CBC 41962 : case T_AppendState:
4654 147 41962 : ExecReScanAppend((AppendState *) node);
9186 vadim4o 148 41962 : break;
149 :
4560 tgl 150 9 : case T_MergeAppendState:
151 9 : ExecReScanMergeAppend((MergeAppendState *) node);
152 9 : break;
153 :
5300 154 6 : case T_RecursiveUnionState:
4654 155 6 : ExecReScanRecursiveUnion((RecursiveUnionState *) node);
5300 156 6 : break;
157 :
6564 158 17 : case T_BitmapAndState:
4654 159 17 : ExecReScanBitmapAnd((BitmapAndState *) node);
6564 160 17 : break;
161 :
162 14 : case T_BitmapOrState:
4654 163 14 : ExecReScanBitmapOr((BitmapOrState *) node);
6564 164 14 : break;
165 :
7430 166 387653 : case T_SeqScanState:
4654 167 387653 : ExecReScanSeqScan((SeqScanState *) node);
8227 168 387653 : break;
169 :
2886 simon 170 29 : case T_SampleScanState:
171 29 : ExecReScanSampleScan((SampleScanState *) node);
172 29 : break;
173 :
2748 rhaas 174 150 : case T_GatherState:
175 150 : ExecReScanGather((GatherState *) node);
176 150 : break;
177 :
2063 178 24 : case T_GatherMergeState:
179 24 : ExecReScanGatherMerge((GatherMergeState *) node);
180 24 : break;
181 :
7430 tgl 182 165861 : case T_IndexScanState:
4654 183 165861 : ExecReScanIndexScan((IndexScanState *) node);
8227 184 165858 : break;
185 :
4198 186 41580 : case T_IndexOnlyScanState:
187 41580 : ExecReScanIndexOnlyScan((IndexOnlyScanState *) node);
188 41580 : break;
189 :
6564 190 2014 : case T_BitmapIndexScanState:
4654 191 2014 : ExecReScanBitmapIndexScan((BitmapIndexScanState *) node);
6564 192 2014 : break;
193 :
194 1720 : case T_BitmapHeapScanState:
4654 195 1720 : ExecReScanBitmapHeapScan((BitmapHeapScanState *) node);
6564 196 1720 : break;
197 :
7430 198 9 : case T_TidScanState:
4654 199 9 : ExecReScanTidScan((TidScanState *) node);
7637 200 9 : break;
201 :
771 drowley 202 33 : case T_TidRangeScanState:
203 33 : ExecReScanTidRangeScan((TidRangeScanState *) node);
204 33 : break;
205 :
7430 tgl 206 1081 : case T_SubqueryScanState:
4654 207 1081 : ExecReScanSubqueryScan((SubqueryScanState *) node);
9186 vadim4o 208 1081 : break;
209 :
7430 tgl 210 38925 : case T_FunctionScanState:
4654 211 38925 : ExecReScanFunctionScan((FunctionScanState *) node);
9186 vadim4o 212 38925 : break;
213 :
2223 alvherre 214 96 : case T_TableFuncScanState:
215 96 : ExecReScanTableFuncScan((TableFuncScanState *) node);
216 96 : break;
217 :
6094 mail 218 30193 : case T_ValuesScanState:
4654 tgl 219 30193 : ExecReScanValuesScan((ValuesScanState *) node);
6094 mail 220 30193 : break;
221 :
5300 tgl 222 1861 : case T_CteScanState:
4654 223 1861 : ExecReScanCteScan((CteScanState *) node);
5300 224 1861 : break;
225 :
2200 kgrittn 226 UBC 0 : case T_NamedTuplestoreScanState:
227 0 : ExecReScanNamedTuplestoreScan((NamedTuplestoreScanState *) node);
228 0 : break;
229 :
5300 tgl 230 CBC 3104 : case T_WorkTableScanState:
4654 231 3104 : ExecReScanWorkTableScan((WorkTableScanState *) node);
5300 232 3104 : break;
233 :
4431 234 401 : case T_ForeignScanState:
235 401 : ExecReScanForeignScan((ForeignScanState *) node);
236 401 : break;
237 :
3075 rhaas 238 UBC 0 : case T_CustomScanState:
239 0 : ExecReScanCustomScan((CustomScanState *) node);
240 0 : break;
241 :
7430 tgl 242 CBC 5323 : case T_NestLoopState:
4654 243 5323 : ExecReScanNestLoop((NestLoopState *) node);
9186 vadim4o 244 5323 : break;
245 :
7430 tgl 246 197 : case T_MergeJoinState:
4654 247 197 : ExecReScanMergeJoin((MergeJoinState *) node);
9186 vadim4o 248 197 : break;
249 :
7430 tgl 250 1143 : case T_HashJoinState:
4654 251 1143 : ExecReScanHashJoin((HashJoinState *) node);
9186 vadim4o 252 1143 : break;
253 :
7430 tgl 254 267910 : case T_MaterialState:
4654 255 267910 : ExecReScanMaterial((MaterialState *) node);
9033 bruce 256 267910 : break;
257 :
634 drowley 258 221746 : case T_MemoizeState:
259 221746 : ExecReScanMemoize((MemoizeState *) node);
737 260 221746 : break;
261 :
7430 tgl 262 18328 : case T_SortState:
4654 263 18328 : ExecReScanSort((SortState *) node);
9186 vadim4o 264 18328 : break;
265 :
1098 tomas.vondra 266 6 : case T_IncrementalSortState:
267 6 : ExecReScanIncrementalSort((IncrementalSortState *) node);
268 6 : break;
269 :
7430 tgl 270 12 : case T_GroupState:
4654 271 12 : ExecReScanGroup((GroupState *) node);
9176 vadim4o 272 12 : break;
273 :
7430 tgl 274 82509 : case T_AggState:
4654 275 82509 : ExecReScanAgg((AggState *) node);
8221 276 82509 : break;
277 :
5215 278 39 : case T_WindowAggState:
4654 279 39 : ExecReScanWindowAgg((WindowAggState *) node);
5215 280 39 : break;
281 :
7430 tgl 282 UBC 0 : case T_UniqueState:
4654 283 0 : ExecReScanUnique((UniqueState *) node);
8200 284 0 : break;
285 :
7430 tgl 286 CBC 508 : case T_HashState:
4654 287 508 : ExecReScanHash((HashState *) node);
9176 vadim4o 288 508 : break;
289 :
7430 tgl 290 300 : case T_SetOpState:
4654 291 300 : ExecReScanSetOp((SetOpState *) node);
9172 vadim4o 292 300 : break;
293 :
4927 tgl 294 8 : case T_LockRowsState:
4654 295 8 : ExecReScanLockRows((LockRowsState *) node);
4927 296 8 : break;
297 :
7430 298 450 : case T_LimitState:
4654 299 450 : ExecReScanLimit((LimitState *) node);
9034 bruce 300 450 : break;
301 :
9344 bruce 302 UBC 0 : default:
7202 tgl 303 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
304 : break;
305 : }
306 :
7364 tgl 307 CBC 1438552 : if (node->chgParam != NULL)
308 : {
309 1061517 : bms_free(node->chgParam);
310 1061517 : node->chgParam = NULL;
311 : }
9770 scrappy 312 1438552 : }
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 : */
327 : void
7184 bruce 328 352802 : ExecMarkPos(PlanState *node)
329 : {
9345 330 352802 : switch (nodeTag(node))
331 : {
7430 tgl 332 3025 : case T_IndexScanState:
333 3025 : ExecIndexMarkPos((IndexScanState *) node);
9344 bruce 334 3025 : break;
335 :
4198 tgl 336 62005 : case T_IndexOnlyScanState:
337 62005 : ExecIndexOnlyMarkPos((IndexOnlyScanState *) node);
338 62005 : break;
339 :
3075 rhaas 340 UBC 0 : case T_CustomScanState:
341 0 : ExecCustomMarkPos((CustomScanState *) node);
342 0 : break;
343 :
7430 tgl 344 CBC 3287 : case T_MaterialState:
345 3287 : ExecMaterialMarkPos((MaterialState *) node);
8330 346 3287 : break;
347 :
7430 348 284485 : case T_SortState:
349 284485 : ExecSortMarkPos((SortState *) node);
9344 bruce 350 284485 : break;
351 :
5897 tgl 352 UBC 0 : case T_ResultState:
353 0 : ExecResultMarkPos((ResultState *) node);
354 0 : break;
355 :
9344 bruce 356 0 : default:
357 : /* don't make hard error unless caller asks to restore... */
7202 tgl 358 0 : elog(DEBUG2, "unrecognized node type: %d", (int) nodeTag(node));
9344 bruce 359 0 : break;
360 : }
9770 scrappy 361 CBC 352802 : }
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 : */
376 : void
7184 bruce 377 69046 : ExecRestrPos(PlanState *node)
378 : {
9345 379 69046 : switch (nodeTag(node))
380 : {
7430 tgl 381 27012 : case T_IndexScanState:
382 27012 : ExecIndexRestrPos((IndexScanState *) node);
8293 383 27012 : break;
384 :
4198 385 3 : case T_IndexOnlyScanState:
386 3 : ExecIndexOnlyRestrPos((IndexOnlyScanState *) node);
387 3 : break;
388 :
3075 rhaas 389 UBC 0 : case T_CustomScanState:
390 0 : ExecCustomRestrPos((CustomScanState *) node);
391 0 : break;
392 :
7430 tgl 393 CBC 27122 : case T_MaterialState:
394 27122 : ExecMaterialRestrPos((MaterialState *) node);
8293 395 27122 : break;
396 :
7430 397 14909 : case T_SortState:
398 14909 : ExecSortRestrPos((SortState *) node);
8293 399 14909 : break;
400 :
5897 tgl 401 UBC 0 : case T_ResultState:
402 0 : ExecResultRestrPos((ResultState *) node);
403 0 : break;
404 :
9344 bruce 405 0 : default:
7202 tgl 406 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
407 : break;
408 : }
9770 scrappy 409 CBC 69046 : }
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 : */
418 : bool
3075 rhaas 419 1858 : ExecSupportsMarkRestore(Path *pathnode)
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 1858 : switch (pathnode->pathtype)
427 : {
7435 tgl 428 1504 : case T_IndexScan:
429 : case T_IndexOnlyScan:
430 :
431 : /*
432 : * Not all index types support mark/restore.
433 : */
866 rhodiumtoad 434 1504 : return castNode(IndexPath, pathnode)->indexinfo->amcanmarkpos;
435 :
7435 tgl 436 UBC 0 : case T_Material:
437 : case T_Sort:
438 0 : return true;
439 :
3062 440 0 : case T_CustomScan:
642 441 0 : if (castNode(CustomPath, pathnode)->flags & CUSTOMPATH_SUPPORT_MARK_RESTORE)
442 0 : return true;
443 0 : return false;
444 :
5897 445 0 : 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 : */
2589 453 0 : if (IsA(pathnode, ProjectionPath))
454 0 : return ExecSupportsMarkRestore(((ProjectionPath *) pathnode)->subpath);
455 0 : else if (IsA(pathnode, MinMaxAggPath))
456 0 : return false; /* childless Result */
1532 457 0 : else if (IsA(pathnode, GroupResultPath))
458 0 : return false; /* childless Result */
459 : else
460 : {
461 : /* Simple RTE_RESULT base relation */
462 0 : Assert(IsA(pathnode, Path));
2589 463 0 : return false; /* childless Result */
464 : }
465 :
1476 tgl 466 CBC 42 : case T_Append:
467 : {
468 42 : AppendPath *appendPath = castNode(AppendPath, pathnode);
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 42 : if (list_length(appendPath->subpaths) == 1)
1476 tgl 476 UBC 0 : return ExecSupportsMarkRestore((Path *) linitial(appendPath->subpaths));
477 : /* Otherwise, Append can't handle it */
1476 tgl 478 CBC 42 : return false;
479 : }
480 :
481 18 : case T_MergeAppend:
482 : {
483 18 : MergeAppendPath *mapath = castNode(MergeAppendPath, pathnode);
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 18 : if (list_length(mapath->subpaths) == 1)
1476 tgl 491 UBC 0 : return ExecSupportsMarkRestore((Path *) linitial(mapath->subpaths));
492 : /* Otherwise, MergeAppend can't handle it */
1476 tgl 493 CBC 18 : return false;
494 : }
495 :
7435 496 294 : default:
497 294 : break;
498 : }
499 :
500 294 : 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 : */
511 : bool
7335 512 1552 : ExecSupportsBackwardScan(Plan *node)
513 : {
514 1552 : if (node == NULL)
7335 tgl 515 UBC 0 : 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 : */
2706 rhaas 522 CBC 1552 : if (node->parallel_aware)
2706 rhaas 523 UBC 0 : return false;
524 :
7335 tgl 525 CBC 1552 : switch (nodeTag(node))
526 : {
527 32 : case T_Result:
528 32 : if (outerPlan(node) != NULL)
2271 andres 529 UBC 0 : return ExecSupportsBackwardScan(outerPlan(node));
530 : else
7335 tgl 531 CBC 32 : return false;
532 :
533 20 : case T_Append:
534 : {
535 : ListCell *l;
536 :
537 : /* With async, tuples may be interleaved, so can't back up. */
739 efujita 538 20 : if (((Append *) node)->nasyncplans > 0)
739 efujita 539 UBC 0 : return false;
540 :
7188 bruce 541 CBC 68 : foreach(l, ((Append *) node)->appendplans)
542 : {
543 49 : if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
544 1 : return false;
545 : }
546 : /* need not check tlist because Append doesn't evaluate it */
547 19 : return true;
548 : }
549 :
2815 tgl 550 3 : case T_SampleScan:
551 : /* Simplify life for tablesample methods by disallowing this */
552 3 : return false;
553 :
2748 rhaas 554 UBC 0 : case T_Gather:
555 0 : return false;
556 :
5287 tgl 557 CBC 202 : case T_IndexScan:
2271 andres 558 202 : return IndexSupportsBackwardScan(((IndexScan *) node)->indexid);
559 :
4198 tgl 560 62 : case T_IndexOnlyScan:
2271 andres 561 62 : return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid);
562 :
7335 tgl 563 UBC 0 : case T_SubqueryScan:
2271 andres 564 0 : return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
565 :
3075 rhaas 566 0 : case T_CustomScan:
642 tgl 567 0 : if (((CustomScan *) node)->flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
568 0 : return true;
3075 rhaas 569 0 : return false;
570 :
2271 andres 571 CBC 806 : 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 */
7335 tgl 580 806 : return true;
581 :
1098 tomas.vondra 582 2 : case T_IncrementalSort:
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 2 : return false;
589 :
4927 tgl 590 66 : case T_LockRows:
591 : case T_Limit:
7335 592 66 : return ExecSupportsBackwardScan(outerPlan(node));
593 :
594 359 : default:
595 359 : return false;
596 : }
597 : }
598 :
599 : /*
600 : * An IndexScan or IndexOnlyScan node supports backward scan only if the
601 : * index's AM does.
602 : */
603 : static bool
5287 604 264 : IndexSupportsBackwardScan(Oid indexid)
605 : {
606 : bool result;
607 : HeapTuple ht_idxrel;
608 : Form_pg_class idxrelrec;
609 : IndexAmRoutine *amroutine;
610 :
611 : /* Fetch the pg_class tuple of the index relation */
4802 rhaas 612 264 : ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid));
5287 tgl 613 264 : if (!HeapTupleIsValid(ht_idxrel))
5287 tgl 614 UBC 0 : elog(ERROR, "cache lookup failed for relation %u", indexid);
5287 tgl 615 CBC 264 : idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
616 :
617 : /* Fetch the index AM's API struct */
2430 618 264 : amroutine = GetIndexAmRoutineByAmId(idxrelrec->relam, false);
619 :
2639 620 264 : result = amroutine->amcanbackward;
621 :
622 264 : pfree(amroutine);
5287 623 264 : ReleaseSysCache(ht_idxrel);
624 :
625 264 : return result;
626 : }
627 :
628 : /*
629 : * ExecMaterializesOutput - does a plan type materialize its output?
630 : *
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.
635 : */
636 : bool
4957 637 194563 : ExecMaterializesOutput(NodeTag plantype)
638 : {
639 194563 : switch (plantype)
640 : {
641 8940 : case T_Material:
642 : case T_FunctionScan:
643 : case T_TableFuncScan:
644 : case T_CteScan:
645 : case T_NamedTuplestoreScan:
646 : case T_WorkTableScan:
647 : case T_Sort:
648 8940 : return true;
649 :
650 185623 : default:
651 185623 : break;
652 : }
653 :
654 185623 : return false;
655 : }
|