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