1 /*-------------------------------------------------------------------------
2 *
3 * execAmi.c
4 * miscellaneous executor access method routines
5 *
6 * Portions Copyright (c) 1996-2018, 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/nodeGroup.h"
32 #include "executor/nodeHash.h"
33 #include "executor/nodeHashjoin.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/nodeMergeAppend.h"
40 #include "executor/nodeMergejoin.h"
41 #include "executor/nodeModifyTable.h"
42 #include "executor/nodeNamedtuplestorescan.h"
43 #include "executor/nodeNestloop.h"
44 #include "executor/nodeProjectSet.h"
45 #include "executor/nodeRecursiveunion.h"
46 #include "executor/nodeResult.h"
47 #include "executor/nodeSamplescan.h"
48 #include "executor/nodeSeqscan.h"
49 #include "executor/nodeSetOp.h"
50 #include "executor/nodeSort.h"
51 #include "executor/nodeSubplan.h"
52 #include "executor/nodeSubqueryscan.h"
53 #include "executor/nodeTableFuncscan.h"
54 #include "executor/nodeTidscan.h"
55 #include "executor/nodeUnique.h"
56 #include "executor/nodeValuesscan.h"
57 #include "executor/nodeWindowAgg.h"
58 #include "executor/nodeWorktablescan.h"
59 #include "nodes/nodeFuncs.h"
60 #include "nodes/relation.h"
61 #include "utils/rel.h"
62 #include "utils/syscache.h"
63
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
ExecReScan(PlanState * node)76 ExecReScan(PlanState *node)
77 {
78 /* If collecting timing stats, update them */
79 if (node->instrument)
80 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 if (node->chgParam != NULL)
96 {
97 ListCell *l;
98
99 foreach(l, node->initPlan)
100 {
101 SubPlanState *sstate = (SubPlanState *) lfirst(l);
102 PlanState *splan = sstate->planstate;
103
104 if (splan->plan->extParam != NULL) /* don't care about child
105 * local Params */
106 UpdateChangedParamSet(splan, node->chgParam);
107 if (splan->chgParam != NULL)
108 ExecReScanSetParamPlan(sstate, node);
109 }
110 foreach(l, node->subPlan)
111 {
112 SubPlanState *sstate = (SubPlanState *) lfirst(l);
113 PlanState *splan = sstate->planstate;
114
115 if (splan->plan->extParam != NULL)
116 UpdateChangedParamSet(splan, node->chgParam);
117 }
118 /* Well. Now set chgParam for left/right trees. */
119 if (node->lefttree != NULL)
120 UpdateChangedParamSet(node->lefttree, node->chgParam);
121 if (node->righttree != NULL)
122 UpdateChangedParamSet(node->righttree, node->chgParam);
123 }
124
125 /* Call expression callbacks */
126 if (node->ps_ExprContext)
127 ReScanExprContext(node->ps_ExprContext);
128
129 /* And do node-type-specific processing */
130 switch (nodeTag(node))
131 {
132 case T_ResultState:
133 ExecReScanResult((ResultState *) node);
134 break;
135
136 case T_ProjectSetState:
137 ExecReScanProjectSet((ProjectSetState *) node);
138 break;
139
140 case T_ModifyTableState:
141 ExecReScanModifyTable((ModifyTableState *) node);
142 break;
143
144 case T_AppendState:
145 ExecReScanAppend((AppendState *) node);
146 break;
147
148 case T_MergeAppendState:
149 ExecReScanMergeAppend((MergeAppendState *) node);
150 break;
151
152 case T_RecursiveUnionState:
153 ExecReScanRecursiveUnion((RecursiveUnionState *) node);
154 break;
155
156 case T_BitmapAndState:
157 ExecReScanBitmapAnd((BitmapAndState *) node);
158 break;
159
160 case T_BitmapOrState:
161 ExecReScanBitmapOr((BitmapOrState *) node);
162 break;
163
164 case T_SeqScanState:
165 ExecReScanSeqScan((SeqScanState *) node);
166 break;
167
168 case T_SampleScanState:
169 ExecReScanSampleScan((SampleScanState *) node);
170 break;
171
172 case T_GatherState:
173 ExecReScanGather((GatherState *) node);
174 break;
175
176 case T_GatherMergeState:
177 ExecReScanGatherMerge((GatherMergeState *) node);
178 break;
179
180 case T_IndexScanState:
181 ExecReScanIndexScan((IndexScanState *) node);
182 break;
183
184 case T_IndexOnlyScanState:
185 ExecReScanIndexOnlyScan((IndexOnlyScanState *) node);
186 break;
187
188 case T_BitmapIndexScanState:
189 ExecReScanBitmapIndexScan((BitmapIndexScanState *) node);
190 break;
191
192 case T_BitmapHeapScanState:
193 ExecReScanBitmapHeapScan((BitmapHeapScanState *) node);
194 break;
195
196 case T_TidScanState:
197 ExecReScanTidScan((TidScanState *) node);
198 break;
199
200 case T_SubqueryScanState:
201 ExecReScanSubqueryScan((SubqueryScanState *) node);
202 break;
203
204 case T_FunctionScanState:
205 ExecReScanFunctionScan((FunctionScanState *) node);
206 break;
207
208 case T_TableFuncScanState:
209 ExecReScanTableFuncScan((TableFuncScanState *) node);
210 break;
211
212 case T_ValuesScanState:
213 ExecReScanValuesScan((ValuesScanState *) node);
214 break;
215
216 case T_CteScanState:
217 ExecReScanCteScan((CteScanState *) node);
218 break;
219
220 case T_NamedTuplestoreScanState:
221 ExecReScanNamedTuplestoreScan((NamedTuplestoreScanState *) node);
222 break;
223
224 case T_WorkTableScanState:
225 ExecReScanWorkTableScan((WorkTableScanState *) node);
226 break;
227
228 case T_ForeignScanState:
229 ExecReScanForeignScan((ForeignScanState *) node);
230 break;
231
232 case T_CustomScanState:
233 ExecReScanCustomScan((CustomScanState *) node);
234 break;
235
236 case T_NestLoopState:
237 ExecReScanNestLoop((NestLoopState *) node);
238 break;
239
240 case T_MergeJoinState:
241 ExecReScanMergeJoin((MergeJoinState *) node);
242 break;
243
244 case T_HashJoinState:
245 ExecReScanHashJoin((HashJoinState *) node);
246 break;
247
248 case T_MaterialState:
249 ExecReScanMaterial((MaterialState *) node);
250 break;
251
252 case T_SortState:
253 ExecReScanSort((SortState *) node);
254 break;
255
256 case T_GroupState:
257 ExecReScanGroup((GroupState *) node);
258 break;
259
260 case T_AggState:
261 ExecReScanAgg((AggState *) node);
262 break;
263
264 case T_WindowAggState:
265 ExecReScanWindowAgg((WindowAggState *) node);
266 break;
267
268 case T_UniqueState:
269 ExecReScanUnique((UniqueState *) node);
270 break;
271
272 case T_HashState:
273 ExecReScanHash((HashState *) node);
274 break;
275
276 case T_SetOpState:
277 ExecReScanSetOp((SetOpState *) node);
278 break;
279
280 case T_LockRowsState:
281 ExecReScanLockRows((LockRowsState *) node);
282 break;
283
284 case T_LimitState:
285 ExecReScanLimit((LimitState *) node);
286 break;
287
288 default:
289 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
290 break;
291 }
292
293 if (node->chgParam != NULL)
294 {
295 bms_free(node->chgParam);
296 node->chgParam = NULL;
297 }
298 }
299
300 /*
301 * ExecMarkPos
302 *
303 * Marks the current scan position.
304 *
305 * NOTE: mark/restore capability is currently needed only for plan nodes
306 * that are the immediate inner child of a MergeJoin node. Since MergeJoin
307 * requires sorted input, there is never any need to support mark/restore in
308 * node types that cannot produce sorted output. There are some cases in
309 * which a node can pass through sorted data from its child; if we don't
310 * implement mark/restore for such a node type, the planner compensates by
311 * inserting a Material node above that node.
312 */
313 void
ExecMarkPos(PlanState * node)314 ExecMarkPos(PlanState *node)
315 {
316 switch (nodeTag(node))
317 {
318 case T_IndexScanState:
319 ExecIndexMarkPos((IndexScanState *) node);
320 break;
321
322 case T_IndexOnlyScanState:
323 ExecIndexOnlyMarkPos((IndexOnlyScanState *) node);
324 break;
325
326 case T_CustomScanState:
327 ExecCustomMarkPos((CustomScanState *) node);
328 break;
329
330 case T_MaterialState:
331 ExecMaterialMarkPos((MaterialState *) node);
332 break;
333
334 case T_SortState:
335 ExecSortMarkPos((SortState *) node);
336 break;
337
338 case T_ResultState:
339 ExecResultMarkPos((ResultState *) node);
340 break;
341
342 default:
343 /* don't make hard error unless caller asks to restore... */
344 elog(DEBUG2, "unrecognized node type: %d", (int) nodeTag(node));
345 break;
346 }
347 }
348
349 /*
350 * ExecRestrPos
351 *
352 * restores the scan position previously saved with ExecMarkPos()
353 *
354 * NOTE: the semantics of this are that the first ExecProcNode following
355 * the restore operation will yield the same tuple as the first one following
356 * the mark operation. It is unspecified what happens to the plan node's
357 * result TupleTableSlot. (In most cases the result slot is unchanged by
358 * a restore, but the node may choose to clear it or to load it with the
359 * restored-to tuple.) Hence the caller should discard any previously
360 * returned TupleTableSlot after doing a restore.
361 */
362 void
ExecRestrPos(PlanState * node)363 ExecRestrPos(PlanState *node)
364 {
365 switch (nodeTag(node))
366 {
367 case T_IndexScanState:
368 ExecIndexRestrPos((IndexScanState *) node);
369 break;
370
371 case T_IndexOnlyScanState:
372 ExecIndexOnlyRestrPos((IndexOnlyScanState *) node);
373 break;
374
375 case T_CustomScanState:
376 ExecCustomRestrPos((CustomScanState *) node);
377 break;
378
379 case T_MaterialState:
380 ExecMaterialRestrPos((MaterialState *) node);
381 break;
382
383 case T_SortState:
384 ExecSortRestrPos((SortState *) node);
385 break;
386
387 case T_ResultState:
388 ExecResultRestrPos((ResultState *) node);
389 break;
390
391 default:
392 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
393 break;
394 }
395 }
396
397 /*
398 * ExecSupportsMarkRestore - does a Path support mark/restore?
399 *
400 * This is used during planning and so must accept a Path, not a Plan.
401 * We keep it here to be adjacent to the routines above, which also must
402 * know which plan types support mark/restore.
403 */
404 bool
ExecSupportsMarkRestore(Path * pathnode)405 ExecSupportsMarkRestore(Path *pathnode)
406 {
407 /*
408 * For consistency with the routines above, we do not examine the nodeTag
409 * but rather the pathtype, which is the Plan node type the Path would
410 * produce.
411 */
412 switch (pathnode->pathtype)
413 {
414 case T_IndexScan:
415 case T_IndexOnlyScan:
416 /*
417 * Not all index types support mark/restore.
418 */
419 return castNode(IndexPath, pathnode)->indexinfo->amcanmarkpos;
420
421 case T_Material:
422 case T_Sort:
423 return true;
424
425 case T_CustomScan:
426 {
427 CustomPath *customPath = castNode(CustomPath, pathnode);
428
429 if (customPath->flags & CUSTOMPATH_SUPPORT_MARK_RESTORE)
430 return true;
431 return false;
432 }
433 case T_Result:
434
435 /*
436 * Result supports mark/restore iff it has a child plan that does.
437 *
438 * We have to be careful here because there is more than one Path
439 * type that can produce a Result plan node.
440 */
441 if (IsA(pathnode, ProjectionPath))
442 return ExecSupportsMarkRestore(((ProjectionPath *) pathnode)->subpath);
443 else if (IsA(pathnode, MinMaxAggPath))
444 return false; /* childless Result */
445 else
446 {
447 Assert(IsA(pathnode, ResultPath));
448 return false; /* childless Result */
449 }
450
451 default:
452 break;
453 }
454
455 return false;
456 }
457
458 /*
459 * ExecSupportsBackwardScan - does a plan type support backwards scanning?
460 *
461 * Ideally, all plan types would support backwards scan, but that seems
462 * unlikely to happen soon. In some cases, a plan node passes the backwards
463 * scan down to its children, and so supports backwards scan only if its
464 * children do. Therefore, this routine must be passed a complete plan tree.
465 */
466 bool
ExecSupportsBackwardScan(Plan * node)467 ExecSupportsBackwardScan(Plan *node)
468 {
469 if (node == NULL)
470 return false;
471
472 /*
473 * Parallel-aware nodes return a subset of the tuples in each worker, and
474 * in general we can't expect to have enough bookkeeping state to know
475 * which ones we returned in this worker as opposed to some other worker.
476 */
477 if (node->parallel_aware)
478 return false;
479
480 switch (nodeTag(node))
481 {
482 case T_Result:
483 if (outerPlan(node) != NULL)
484 return ExecSupportsBackwardScan(outerPlan(node));
485 else
486 return false;
487
488 case T_Append:
489 {
490 ListCell *l;
491
492 foreach(l, ((Append *) node)->appendplans)
493 {
494 if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
495 return false;
496 }
497 /* need not check tlist because Append doesn't evaluate it */
498 return true;
499 }
500
501 case T_SampleScan:
502 /* Simplify life for tablesample methods by disallowing this */
503 return false;
504
505 case T_Gather:
506 return false;
507
508 case T_IndexScan:
509 return IndexSupportsBackwardScan(((IndexScan *) node)->indexid);
510
511 case T_IndexOnlyScan:
512 return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid);
513
514 case T_SubqueryScan:
515 return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
516
517 case T_CustomScan:
518 {
519 uint32 flags = ((CustomScan *) node)->flags;
520
521 if (flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
522 return true;
523 }
524 return false;
525
526 case T_SeqScan:
527 case T_TidScan:
528 case T_FunctionScan:
529 case T_ValuesScan:
530 case T_CteScan:
531 case T_Material:
532 case T_Sort:
533 return true;
534
535 case T_LockRows:
536 case T_Limit:
537 return ExecSupportsBackwardScan(outerPlan(node));
538
539 default:
540 return false;
541 }
542 }
543
544 /*
545 * An IndexScan or IndexOnlyScan node supports backward scan only if the
546 * index's AM does.
547 */
548 static bool
IndexSupportsBackwardScan(Oid indexid)549 IndexSupportsBackwardScan(Oid indexid)
550 {
551 bool result;
552 HeapTuple ht_idxrel;
553 Form_pg_class idxrelrec;
554 IndexAmRoutine *amroutine;
555
556 /* Fetch the pg_class tuple of the index relation */
557 ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid));
558 if (!HeapTupleIsValid(ht_idxrel))
559 elog(ERROR, "cache lookup failed for relation %u", indexid);
560 idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
561
562 /* Fetch the index AM's API struct */
563 amroutine = GetIndexAmRoutineByAmId(idxrelrec->relam, false);
564
565 result = amroutine->amcanbackward;
566
567 pfree(amroutine);
568 ReleaseSysCache(ht_idxrel);
569
570 return result;
571 }
572
573 /*
574 * ExecMaterializesOutput - does a plan type materialize its output?
575 *
576 * Returns true if the plan node type is one that automatically materializes
577 * its output (typically by keeping it in a tuplestore). For such plans,
578 * a rescan without any parameter change will have zero startup cost and
579 * very low per-tuple cost.
580 */
581 bool
ExecMaterializesOutput(NodeTag plantype)582 ExecMaterializesOutput(NodeTag plantype)
583 {
584 switch (plantype)
585 {
586 case T_Material:
587 case T_FunctionScan:
588 case T_TableFuncScan:
589 case T_CteScan:
590 case T_NamedTuplestoreScan:
591 case T_WorkTableScan:
592 case T_Sort:
593 return true;
594
595 default:
596 break;
597 }
598
599 return false;
600 }
601