Age Owner Branch data TLA 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
5025 tgl@sss.pgh.pa.us 76 :CBC 1221028 : ExecReScan(PlanState *node)
77 : : {
78 : : /* If collecting timing stats, update them */
8244 79 [ + + ]: 1221028 : if (node->instrument)
80 : 15029 : 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 : : */
7735 95 [ + + ]: 1221028 : if (node->chgParam != NULL)
96 : : {
97 : : ListCell *l;
98 : :
7263 neilc@samurai.com 99 [ + + + + : 1115542 : foreach(l, node->initPlan)
+ + ]
100 : : {
101 : 663 : SubPlanState *sstate = (SubPlanState *) lfirst(l);
7793 tgl@sss.pgh.pa.us 102 : 663 : PlanState *splan = sstate->planstate;
103 : :
7735 104 [ + + ]: 663 : if (splan->plan->extParam != NULL) /* don't care about child
105 : : * local Params */
106 : 586 : UpdateChangedParamSet(splan, node->chgParam);
107 [ + + ]: 663 : if (splan->chgParam != NULL)
7793 108 : 466 : ExecReScanSetParamPlan(sstate, node);
109 : : }
7263 neilc@samurai.com 110 [ + + + + : 1115306 : foreach(l, node->subPlan)
+ + ]
111 : : {
112 : 427 : SubPlanState *sstate = (SubPlanState *) lfirst(l);
7793 tgl@sss.pgh.pa.us 113 : 427 : PlanState *splan = sstate->planstate;
114 : :
7735 115 [ + + ]: 427 : if (splan->plan->extParam != NULL)
116 : 424 : UpdateChangedParamSet(splan, node->chgParam);
117 : : }
118 : : /* Well. Now set chgParam for child trees. */
647 119 [ + + ]: 1114879 : if (outerPlanState(node) != NULL)
120 : 296330 : UpdateChangedParamSet(outerPlanState(node), node->chgParam);
121 [ + + ]: 1114879 : if (innerPlanState(node) != NULL)
122 : 6775 : UpdateChangedParamSet(innerPlanState(node), node->chgParam);
123 : : }
124 : :
125 : : /* Call expression callbacks */
7423 126 [ + + ]: 1221028 : if (node->ps_ExprContext)
127 : 1129928 : ReScanExprContext(node->ps_ExprContext);
128 : :
129 : : /* And do node-type-specific processing */
9716 bruce@momjian.us 130 [ + + - + : 1221028 : switch (nodeTag(node))
+ + + + +
+ + + + +
+ + + + +
+ + + + -
+ + - + +
+ + + + +
+ + + + +
+ + + - ]
131 : : {
7801 tgl@sss.pgh.pa.us 132 : 16651 : case T_ResultState:
5025 133 : 16651 : ExecReScanResult((ResultState *) node);
9557 vadim4o@yahoo.com 134 : 16651 : break;
135 : :
2643 andres@anarazel.de 136 : 6005 : case T_ProjectSetState:
137 : 6005 : ExecReScanProjectSet((ProjectSetState *) node);
138 : 6005 : break;
139 : :
5300 tgl@sss.pgh.pa.us 140 :UBC 0 : case T_ModifyTableState:
5025 141 : 0 : ExecReScanModifyTable((ModifyTableState *) node);
5300 142 : 0 : break;
143 : :
7801 tgl@sss.pgh.pa.us 144 :CBC 8310 : case T_AppendState:
5025 145 : 8310 : ExecReScanAppend((AppendState *) node);
9557 vadim4o@yahoo.com 146 : 8310 : break;
147 : :
4931 tgl@sss.pgh.pa.us 148 : 9 : case T_MergeAppendState:
149 : 9 : ExecReScanMergeAppend((MergeAppendState *) node);
150 : 9 : break;
151 : :
5671 152 : 6 : case T_RecursiveUnionState:
5025 153 : 6 : ExecReScanRecursiveUnion((RecursiveUnionState *) node);
5671 154 : 6 : break;
155 : :
6935 156 : 29 : case T_BitmapAndState:
5025 157 : 29 : ExecReScanBitmapAnd((BitmapAndState *) node);
6935 158 : 29 : break;
159 : :
160 : 14 : case T_BitmapOrState:
5025 161 : 14 : ExecReScanBitmapOr((BitmapOrState *) node);
6935 162 : 14 : break;
163 : :
7801 164 : 507215 : case T_SeqScanState:
5025 165 : 507215 : ExecReScanSeqScan((SeqScanState *) node);
8598 166 : 507215 : break;
167 : :
3257 simon@2ndQuadrant.co 168 : 29 : case T_SampleScanState:
169 : 29 : ExecReScanSampleScan((SampleScanState *) node);
170 : 29 : break;
171 : :
3119 rhaas@postgresql.org 172 : 150 : case T_GatherState:
173 : 150 : ExecReScanGather((GatherState *) node);
174 : 150 : break;
175 : :
2434 176 : 24 : case T_GatherMergeState:
177 : 24 : ExecReScanGatherMerge((GatherMergeState *) node);
178 : 24 : break;
179 : :
7801 tgl@sss.pgh.pa.us 180 : 202154 : case T_IndexScanState:
5025 181 : 202154 : ExecReScanIndexScan((IndexScanState *) node);
8598 182 : 202151 : break;
183 : :
4569 184 : 40844 : case T_IndexOnlyScanState:
185 : 40844 : ExecReScanIndexOnlyScan((IndexOnlyScanState *) node);
186 : 40844 : break;
187 : :
6935 188 : 2586 : case T_BitmapIndexScanState:
5025 189 : 2586 : ExecReScanBitmapIndexScan((BitmapIndexScanState *) node);
6935 190 : 2586 : break;
191 : :
192 : 2259 : case T_BitmapHeapScanState:
5025 193 : 2259 : ExecReScanBitmapHeapScan((BitmapHeapScanState *) node);
6935 194 : 2259 : break;
195 : :
7801 196 : 9 : case T_TidScanState:
5025 197 : 9 : ExecReScanTidScan((TidScanState *) node);
8008 198 : 9 : break;
199 : :
1142 drowley@postgresql.o 200 : 33 : case T_TidRangeScanState:
201 : 33 : ExecReScanTidRangeScan((TidRangeScanState *) node);
202 : 33 : break;
203 : :
7801 tgl@sss.pgh.pa.us 204 : 1093 : case T_SubqueryScanState:
5025 205 : 1093 : ExecReScanSubqueryScan((SubqueryScanState *) node);
9557 vadim4o@yahoo.com 206 : 1093 : break;
207 : :
7801 tgl@sss.pgh.pa.us 208 : 49865 : case T_FunctionScanState:
5025 209 : 49865 : ExecReScanFunctionScan((FunctionScanState *) node);
9557 vadim4o@yahoo.com 210 : 49865 : break;
211 : :
2594 alvherre@alvh.no-ip. 212 : 219 : case T_TableFuncScanState:
213 : 219 : ExecReScanTableFuncScan((TableFuncScanState *) node);
214 : 219 : break;
215 : :
6465 mail@joeconway.com 216 : 30199 : case T_ValuesScanState:
5025 tgl@sss.pgh.pa.us 217 : 30199 : ExecReScanValuesScan((ValuesScanState *) node);
6465 mail@joeconway.com 218 : 30199 : break;
219 : :
5671 tgl@sss.pgh.pa.us 220 : 2619 : case T_CteScanState:
5025 221 : 2619 : ExecReScanCteScan((CteScanState *) node);
5671 222 : 2619 : break;
223 : :
2571 kgrittn@postgresql.o 224 :UBC 0 : case T_NamedTuplestoreScanState:
225 : 0 : ExecReScanNamedTuplestoreScan((NamedTuplestoreScanState *) node);
226 : 0 : break;
227 : :
5671 tgl@sss.pgh.pa.us 228 :CBC 3151 : case T_WorkTableScanState:
5025 229 : 3151 : ExecReScanWorkTableScan((WorkTableScanState *) node);
5671 230 : 3151 : break;
231 : :
4802 232 : 402 : case T_ForeignScanState:
233 : 402 : ExecReScanForeignScan((ForeignScanState *) node);
234 : 402 : break;
235 : :
3446 rhaas@postgresql.org 236 :UBC 0 : case T_CustomScanState:
237 : 0 : ExecReScanCustomScan((CustomScanState *) node);
238 : 0 : break;
239 : :
7801 tgl@sss.pgh.pa.us 240 :CBC 5865 : case T_NestLoopState:
5025 241 : 5865 : ExecReScanNestLoop((NestLoopState *) node);
9557 vadim4o@yahoo.com 242 : 5865 : break;
243 : :
7801 tgl@sss.pgh.pa.us 244 : 239 : case T_MergeJoinState:
5025 245 : 239 : ExecReScanMergeJoin((MergeJoinState *) node);
9557 vadim4o@yahoo.com 246 : 239 : break;
247 : :
7801 tgl@sss.pgh.pa.us 248 : 1117 : case T_HashJoinState:
5025 249 : 1117 : ExecReScanHashJoin((HashJoinState *) node);
9557 vadim4o@yahoo.com 250 : 1117 : break;
251 : :
7801 tgl@sss.pgh.pa.us 252 : 60884 : case T_MaterialState:
5025 253 : 60884 : ExecReScanMaterial((MaterialState *) node);
9404 bruce@momjian.us 254 : 60884 : break;
255 : :
1005 drowley@postgresql.o 256 : 233521 : case T_MemoizeState:
257 : 233521 : ExecReScanMemoize((MemoizeState *) node);
1108 258 : 233521 : break;
259 : :
7801 tgl@sss.pgh.pa.us 260 : 20882 : case T_SortState:
5025 261 : 20882 : ExecReScanSort((SortState *) node);
9557 vadim4o@yahoo.com 262 : 20882 : break;
263 : :
1469 tomas.vondra@postgre 264 : 6 : case T_IncrementalSortState:
265 : 6 : ExecReScanIncrementalSort((IncrementalSortState *) node);
266 : 6 : break;
267 : :
7801 tgl@sss.pgh.pa.us 268 : 12 : case T_GroupState:
5025 269 : 12 : ExecReScanGroup((GroupState *) node);
9547 vadim4o@yahoo.com 270 : 12 : break;
271 : :
7801 tgl@sss.pgh.pa.us 272 : 18481 : case T_AggState:
5025 273 : 18481 : ExecReScanAgg((AggState *) node);
8592 274 : 18481 : break;
275 : :
5586 276 : 39 : case T_WindowAggState:
5025 277 : 39 : ExecReScanWindowAgg((WindowAggState *) node);
5586 278 : 39 : break;
279 : :
7801 tgl@sss.pgh.pa.us 280 :GBC 4736 : case T_UniqueState:
5025 281 : 4736 : ExecReScanUnique((UniqueState *) node);
8571 282 : 4736 : break;
283 : :
7801 tgl@sss.pgh.pa.us 284 :CBC 613 : case T_HashState:
5025 285 : 613 : ExecReScanHash((HashState *) node);
9547 vadim4o@yahoo.com 286 : 613 : break;
287 : :
7801 tgl@sss.pgh.pa.us 288 : 300 : case T_SetOpState:
5025 289 : 300 : ExecReScanSetOp((SetOpState *) node);
9543 vadim4o@yahoo.com 290 : 300 : break;
291 : :
5298 tgl@sss.pgh.pa.us 292 : 8 : case T_LockRowsState:
5025 293 : 8 : ExecReScanLockRows((LockRowsState *) node);
5298 294 : 8 : break;
295 : :
7801 296 : 450 : case T_LimitState:
5025 297 : 450 : ExecReScanLimit((LimitState *) node);
9405 bruce@momjian.us 298 : 450 : break;
299 : :
9715 bruce@momjian.us 300 :UBC 0 : default:
7573 tgl@sss.pgh.pa.us 301 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
302 : : break;
303 : : }
304 : :
7735 tgl@sss.pgh.pa.us 305 [ + + ]:CBC 1221025 : if (node->chgParam != NULL)
306 : : {
307 : 1114879 : bms_free(node->chgParam);
308 : 1114879 : node->chgParam = NULL;
309 : : }
10141 scrappy@hub.org 310 : 1221025 : }
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
7555 bruce@momjian.us 326 : 358163 : ExecMarkPos(PlanState *node)
327 : : {
9716 328 [ + + - + : 358163 : switch (nodeTag(node))
+ - - ]
329 : : {
7801 tgl@sss.pgh.pa.us 330 : 3038 : case T_IndexScanState:
331 : 3038 : ExecIndexMarkPos((IndexScanState *) node);
9715 bruce@momjian.us 332 : 3038 : break;
333 : :
4569 tgl@sss.pgh.pa.us 334 : 62002 : case T_IndexOnlyScanState:
335 : 62002 : ExecIndexOnlyMarkPos((IndexOnlyScanState *) node);
336 : 62002 : break;
337 : :
3446 rhaas@postgresql.org 338 :UBC 0 : case T_CustomScanState:
339 : 0 : ExecCustomMarkPos((CustomScanState *) node);
340 : 0 : break;
341 : :
7801 tgl@sss.pgh.pa.us 342 :CBC 3318 : case T_MaterialState:
343 : 3318 : ExecMaterialMarkPos((MaterialState *) node);
8701 344 : 3318 : break;
345 : :
7801 346 : 289805 : case T_SortState:
347 : 289805 : ExecSortMarkPos((SortState *) node);
9715 bruce@momjian.us 348 : 289805 : break;
349 : :
6268 tgl@sss.pgh.pa.us 350 :UBC 0 : case T_ResultState:
351 : 0 : ExecResultMarkPos((ResultState *) node);
352 : 0 : break;
353 : :
9715 bruce@momjian.us 354 : 0 : default:
355 : : /* don't make hard error unless caller asks to restore... */
7573 tgl@sss.pgh.pa.us 356 [ # # ]: 0 : elog(DEBUG2, "unrecognized node type: %d", (int) nodeTag(node));
9715 bruce@momjian.us 357 : 0 : break;
358 : : }
10141 scrappy@hub.org 359 :CBC 358163 : }
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
7555 bruce@momjian.us 375 : 70141 : ExecRestrPos(PlanState *node)
376 : : {
9716 377 [ + - - + : 70141 : switch (nodeTag(node))
+ - - ]
378 : : {
7801 tgl@sss.pgh.pa.us 379 : 27015 : case T_IndexScanState:
380 : 27015 : ExecIndexRestrPos((IndexScanState *) node);
8664 381 : 27015 : break;
382 : :
4569 tgl@sss.pgh.pa.us 383 :LBC (3) : case T_IndexOnlyScanState:
384 : (3) : ExecIndexOnlyRestrPos((IndexOnlyScanState *) node);
385 : (3) : break;
386 : :
3446 rhaas@postgresql.org 387 :UBC 0 : case T_CustomScanState:
388 : 0 : ExecCustomRestrPos((CustomScanState *) node);
389 : 0 : break;
390 : :
7801 tgl@sss.pgh.pa.us 391 :CBC 27151 : case T_MaterialState:
392 : 27151 : ExecMaterialRestrPos((MaterialState *) node);
8664 393 : 27151 : break;
394 : :
7801 395 : 15975 : case T_SortState:
396 : 15975 : ExecSortRestrPos((SortState *) node);
8664 397 : 15975 : break;
398 : :
6268 tgl@sss.pgh.pa.us 399 :UBC 0 : case T_ResultState:
400 : 0 : ExecResultRestrPos((ResultState *) node);
401 : 0 : break;
402 : :
9715 bruce@momjian.us 403 : 0 : default:
7573 tgl@sss.pgh.pa.us 404 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
405 : : break;
406 : : }
10141 scrappy@hub.org 407 :CBC 70141 : }
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
3446 rhaas@postgresql.org 417 : 3064 : 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 [ + - - - : 3064 : switch (pathnode->pathtype)
+ + + ]
425 : : {
7806 tgl@sss.pgh.pa.us 426 : 2565 : case T_IndexScan:
427 : : case T_IndexOnlyScan:
428 : :
429 : : /*
430 : : * Not all index types support mark/restore.
431 : : */
1237 rhodiumtoad@postgres 432 : 2565 : return castNode(IndexPath, pathnode)->indexinfo->amcanmarkpos;
433 : :
7806 tgl@sss.pgh.pa.us 434 :UBC 0 : case T_Material:
435 : : case T_Sort:
436 : 0 : return true;
437 : :
3433 438 : 0 : case T_CustomScan:
1013 439 [ # # ]: 0 : if (castNode(CustomPath, pathnode)->flags & CUSTOMPATH_SUPPORT_MARK_RESTORE)
440 : 0 : return true;
441 : 0 : return false;
442 : :
6268 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 : : */
2960 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 */
1903 455 [ # # ]: 0 : else if (IsA(pathnode, GroupResultPath))
456 : 0 : return false; /* childless Result */
457 : : else
458 : : {
459 : : /* Simple RTE_RESULT base relation */
460 [ # # ]: 0 : Assert(IsA(pathnode, Path));
2960 461 : 0 : return false; /* childless Result */
462 : : }
463 : :
1847 tgl@sss.pgh.pa.us 464 :CBC 42 : case T_Append:
465 : : {
466 : 42 : 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 [ - + ]: 42 : if (list_length(appendPath->subpaths) == 1)
1847 tgl@sss.pgh.pa.us 474 :UBC 0 : return ExecSupportsMarkRestore((Path *) linitial(appendPath->subpaths));
475 : : /* Otherwise, Append can't handle it */
1847 tgl@sss.pgh.pa.us 476 :CBC 42 : return false;
477 : : }
478 : :
479 : 22 : case T_MergeAppend:
480 : : {
481 : 22 : 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 [ - + ]: 22 : if (list_length(mapath->subpaths) == 1)
1847 tgl@sss.pgh.pa.us 489 :UBC 0 : return ExecSupportsMarkRestore((Path *) linitial(mapath->subpaths));
490 : : /* Otherwise, MergeAppend can't handle it */
1847 tgl@sss.pgh.pa.us 491 :CBC 22 : return false;
492 : : }
493 : :
7806 494 : 435 : default:
495 : 435 : break;
496 : : }
497 : :
498 : 435 : 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
7706 510 : 1540 : ExecSupportsBackwardScan(Plan *node)
511 : : {
512 [ - + ]: 1540 : if (node == NULL)
7706 tgl@sss.pgh.pa.us 513 :UBC 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 : : */
3077 rhaas@postgresql.org 520 [ - + ]:CBC 1540 : if (node->parallel_aware)
3077 rhaas@postgresql.org 521 :UBC 0 : return false;
522 : :
7706 tgl@sss.pgh.pa.us 523 [ + + + - :CBC 1540 : switch (nodeTag(node))
+ + - - +
+ + + ]
524 : : {
525 : 34 : case T_Result:
526 [ - + ]: 34 : if (outerPlan(node) != NULL)
2642 andres@anarazel.de 527 :UBC 0 : return ExecSupportsBackwardScan(outerPlan(node));
528 : : else
7706 tgl@sss.pgh.pa.us 529 :CBC 34 : return false;
530 : :
531 : 20 : case T_Append:
532 : : {
533 : : ListCell *l;
534 : :
535 : : /* With async, tuples may be interleaved, so can't back up. */
1110 efujita@postgresql.o 536 [ - + ]: 20 : if (((Append *) node)->nasyncplans > 0)
1110 efujita@postgresql.o 537 :UBC 0 : return false;
538 : :
7559 bruce@momjian.us 539 [ + - + + :CBC 68 : foreach(l, ((Append *) node)->appendplans)
+ + ]
540 : : {
541 [ + + ]: 49 : if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
542 : 1 : return false;
543 : : }
544 : : /* need not check tlist because Append doesn't evaluate it */
545 : 19 : return true;
546 : : }
547 : :
3186 tgl@sss.pgh.pa.us 548 : 3 : case T_SampleScan:
549 : : /* Simplify life for tablesample methods by disallowing this */
550 : 3 : return false;
551 : :
3119 rhaas@postgresql.org 552 :UBC 0 : case T_Gather:
553 : 0 : return false;
554 : :
5658 tgl@sss.pgh.pa.us 555 :CBC 205 : case T_IndexScan:
2642 andres@anarazel.de 556 : 205 : return IndexSupportsBackwardScan(((IndexScan *) node)->indexid);
557 : :
4569 tgl@sss.pgh.pa.us 558 : 25 : case T_IndexOnlyScan:
2642 andres@anarazel.de 559 : 25 : return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid);
560 : :
7706 tgl@sss.pgh.pa.us 561 :UBC 0 : case T_SubqueryScan:
2642 andres@anarazel.de 562 : 0 : return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
563 : :
3446 rhaas@postgresql.org 564 : 0 : case T_CustomScan:
1013 tgl@sss.pgh.pa.us 565 [ # # ]: 0 : if (((CustomScan *) node)->flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
566 : 0 : return true;
3446 rhaas@postgresql.org 567 : 0 : return false;
568 : :
2642 andres@anarazel.de 569 :CBC 828 : 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 */
7706 tgl@sss.pgh.pa.us 578 : 828 : return true;
579 : :
1469 tomas.vondra@postgre 580 : 2 : 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 : 2 : return false;
587 : :
5298 tgl@sss.pgh.pa.us 588 : 72 : case T_LockRows:
589 : : case T_Limit:
7706 590 : 72 : return ExecSupportsBackwardScan(outerPlan(node));
591 : :
592 : 351 : default:
593 : 351 : 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
5658 602 : 230 : 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 */
5173 rhaas@postgresql.org 610 : 230 : ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid));
5658 tgl@sss.pgh.pa.us 611 [ - + ]: 230 : if (!HeapTupleIsValid(ht_idxrel))
5658 tgl@sss.pgh.pa.us 612 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for relation %u", indexid);
5658 tgl@sss.pgh.pa.us 613 :CBC 230 : idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
614 : :
615 : : /* Fetch the index AM's API struct */
2801 616 : 230 : amroutine = GetIndexAmRoutineByAmId(idxrelrec->relam, false);
617 : :
3010 618 : 230 : result = amroutine->amcanbackward;
619 : :
620 : 230 : pfree(amroutine);
5658 621 : 230 : ReleaseSysCache(ht_idxrel);
622 : :
623 : 230 : 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
5328 635 : 227971 : ExecMaterializesOutput(NodeTag plantype)
636 : : {
637 [ + + ]: 227971 : switch (plantype)
638 : : {
639 : 11529 : 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 : 11529 : return true;
647 : :
648 : 216442 : default:
649 : 216442 : break;
650 : : }
651 : :
652 : 216442 : return false;
653 : : }
|