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