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