OSDN Git Service

01775ce4494c1781bb630dcaeefa722af49b6a1a
[pg-rex/syncrep.git] / src / backend / executor / execAmi.c
1 /*-------------------------------------------------------------------------
2  *
3  * execAmi.c
4  *        miscellaneous executor access method routines
5  *
6  * Portions Copyright (c) 1996-2011, 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 "executor/execdebug.h"
16 #include "executor/instrument.h"
17 #include "executor/nodeAgg.h"
18 #include "executor/nodeAppend.h"
19 #include "executor/nodeBitmapAnd.h"
20 #include "executor/nodeBitmapHeapscan.h"
21 #include "executor/nodeBitmapIndexscan.h"
22 #include "executor/nodeBitmapOr.h"
23 #include "executor/nodeCtescan.h"
24 #include "executor/nodeForeignscan.h"
25 #include "executor/nodeFunctionscan.h"
26 #include "executor/nodeGroup.h"
27 #include "executor/nodeGroup.h"
28 #include "executor/nodeHash.h"
29 #include "executor/nodeHashjoin.h"
30 #include "executor/nodeIndexscan.h"
31 #include "executor/nodeLimit.h"
32 #include "executor/nodeLockRows.h"
33 #include "executor/nodeMaterial.h"
34 #include "executor/nodeMergeAppend.h"
35 #include "executor/nodeMergejoin.h"
36 #include "executor/nodeModifyTable.h"
37 #include "executor/nodeNestloop.h"
38 #include "executor/nodeRecursiveunion.h"
39 #include "executor/nodeResult.h"
40 #include "executor/nodeSeqscan.h"
41 #include "executor/nodeSetOp.h"
42 #include "executor/nodeSort.h"
43 #include "executor/nodeSubplan.h"
44 #include "executor/nodeSubqueryscan.h"
45 #include "executor/nodeTidscan.h"
46 #include "executor/nodeUnique.h"
47 #include "executor/nodeValuesscan.h"
48 #include "executor/nodeWindowAgg.h"
49 #include "executor/nodeWorktablescan.h"
50 #include "nodes/nodeFuncs.h"
51 #include "utils/syscache.h"
52
53
54 static bool TargetListSupportsBackwardScan(List *targetlist);
55 static bool IndexSupportsBackwardScan(Oid indexid);
56
57
58 /*
59  * ExecReScan
60  *              Reset a plan node so that its output can be re-scanned.
61  *
62  * Note that if the plan node has parameters that have changed value,
63  * the output might be different from last time.
64  */
65 void
66 ExecReScan(PlanState *node)
67 {
68         /* If collecting timing stats, update them */
69         if (node->instrument)
70                 InstrEndLoop(node->instrument);
71
72         /*
73          * If we have changed parameters, propagate that info.
74          *
75          * Note: ExecReScanSetParamPlan() can add bits to node->chgParam,
76          * corresponding to the output param(s) that the InitPlan will update.
77          * Since we make only one pass over the list, that means that an InitPlan
78          * can depend on the output param(s) of a sibling InitPlan only if that
79          * sibling appears earlier in the list.  This is workable for now given
80          * the limited ways in which one InitPlan could depend on another, but
81          * eventually we might need to work harder (or else make the planner
82          * enlarge the extParam/allParam sets to include the params of depended-on
83          * InitPlans).
84          */
85         if (node->chgParam != NULL)
86         {
87                 ListCell   *l;
88
89                 foreach(l, node->initPlan)
90                 {
91                         SubPlanState *sstate = (SubPlanState *) lfirst(l);
92                         PlanState  *splan = sstate->planstate;
93
94                         if (splan->plan->extParam != NULL)      /* don't care about child
95                                                                                                  * local Params */
96                                 UpdateChangedParamSet(splan, node->chgParam);
97                         if (splan->chgParam != NULL)
98                                 ExecReScanSetParamPlan(sstate, node);
99                 }
100                 foreach(l, node->subPlan)
101                 {
102                         SubPlanState *sstate = (SubPlanState *) lfirst(l);
103                         PlanState  *splan = sstate->planstate;
104
105                         if (splan->plan->extParam != NULL)
106                                 UpdateChangedParamSet(splan, node->chgParam);
107                 }
108                 /* Well. Now set chgParam for left/right trees. */
109                 if (node->lefttree != NULL)
110                         UpdateChangedParamSet(node->lefttree, node->chgParam);
111                 if (node->righttree != NULL)
112                         UpdateChangedParamSet(node->righttree, node->chgParam);
113         }
114
115         /* Shut down any SRFs in the plan node's targetlist */
116         if (node->ps_ExprContext)
117                 ReScanExprContext(node->ps_ExprContext);
118
119         /* And do node-type-specific processing */
120         switch (nodeTag(node))
121         {
122                 case T_ResultState:
123                         ExecReScanResult((ResultState *) node);
124                         break;
125
126                 case T_ModifyTableState:
127                         ExecReScanModifyTable((ModifyTableState *) node);
128                         break;
129
130                 case T_AppendState:
131                         ExecReScanAppend((AppendState *) node);
132                         break;
133
134                 case T_MergeAppendState:
135                         ExecReScanMergeAppend((MergeAppendState *) node);
136                         break;
137
138                 case T_RecursiveUnionState:
139                         ExecReScanRecursiveUnion((RecursiveUnionState *) node);
140                         break;
141
142                 case T_BitmapAndState:
143                         ExecReScanBitmapAnd((BitmapAndState *) node);
144                         break;
145
146                 case T_BitmapOrState:
147                         ExecReScanBitmapOr((BitmapOrState *) node);
148                         break;
149
150                 case T_SeqScanState:
151                         ExecReScanSeqScan((SeqScanState *) node);
152                         break;
153
154                 case T_IndexScanState:
155                         ExecReScanIndexScan((IndexScanState *) node);
156                         break;
157
158                 case T_BitmapIndexScanState:
159                         ExecReScanBitmapIndexScan((BitmapIndexScanState *) node);
160                         break;
161
162                 case T_BitmapHeapScanState:
163                         ExecReScanBitmapHeapScan((BitmapHeapScanState *) node);
164                         break;
165
166                 case T_TidScanState:
167                         ExecReScanTidScan((TidScanState *) node);
168                         break;
169
170                 case T_SubqueryScanState:
171                         ExecReScanSubqueryScan((SubqueryScanState *) node);
172                         break;
173
174                 case T_FunctionScanState:
175                         ExecReScanFunctionScan((FunctionScanState *) node);
176                         break;
177
178                 case T_ValuesScanState:
179                         ExecReScanValuesScan((ValuesScanState *) node);
180                         break;
181
182                 case T_CteScanState:
183                         ExecReScanCteScan((CteScanState *) node);
184                         break;
185
186                 case T_WorkTableScanState:
187                         ExecReScanWorkTableScan((WorkTableScanState *) node);
188                         break;
189
190                 case T_ForeignScanState:
191                         ExecReScanForeignScan((ForeignScanState *) node);
192                         break;
193
194                 case T_NestLoopState:
195                         ExecReScanNestLoop((NestLoopState *) node);
196                         break;
197
198                 case T_MergeJoinState:
199                         ExecReScanMergeJoin((MergeJoinState *) node);
200                         break;
201
202                 case T_HashJoinState:
203                         ExecReScanHashJoin((HashJoinState *) node);
204                         break;
205
206                 case T_MaterialState:
207                         ExecReScanMaterial((MaterialState *) node);
208                         break;
209
210                 case T_SortState:
211                         ExecReScanSort((SortState *) node);
212                         break;
213
214                 case T_GroupState:
215                         ExecReScanGroup((GroupState *) node);
216                         break;
217
218                 case T_AggState:
219                         ExecReScanAgg((AggState *) node);
220                         break;
221
222                 case T_WindowAggState:
223                         ExecReScanWindowAgg((WindowAggState *) node);
224                         break;
225
226                 case T_UniqueState:
227                         ExecReScanUnique((UniqueState *) node);
228                         break;
229
230                 case T_HashState:
231                         ExecReScanHash((HashState *) node);
232                         break;
233
234                 case T_SetOpState:
235                         ExecReScanSetOp((SetOpState *) node);
236                         break;
237
238                 case T_LockRowsState:
239                         ExecReScanLockRows((LockRowsState *) node);
240                         break;
241
242                 case T_LimitState:
243                         ExecReScanLimit((LimitState *) node);
244                         break;
245
246                 default:
247                         elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
248                         break;
249         }
250
251         if (node->chgParam != NULL)
252         {
253                 bms_free(node->chgParam);
254                 node->chgParam = NULL;
255         }
256 }
257
258 /*
259  * ExecMarkPos
260  *
261  * Marks the current scan position.
262  */
263 void
264 ExecMarkPos(PlanState *node)
265 {
266         switch (nodeTag(node))
267         {
268                 case T_SeqScanState:
269                         ExecSeqMarkPos((SeqScanState *) node);
270                         break;
271
272                 case T_IndexScanState:
273                         ExecIndexMarkPos((IndexScanState *) node);
274                         break;
275
276                 case T_TidScanState:
277                         ExecTidMarkPos((TidScanState *) node);
278                         break;
279
280                 case T_ValuesScanState:
281                         ExecValuesMarkPos((ValuesScanState *) node);
282                         break;
283
284                 case T_MaterialState:
285                         ExecMaterialMarkPos((MaterialState *) node);
286                         break;
287
288                 case T_SortState:
289                         ExecSortMarkPos((SortState *) node);
290                         break;
291
292                 case T_ResultState:
293                         ExecResultMarkPos((ResultState *) node);
294                         break;
295
296                 default:
297                         /* don't make hard error unless caller asks to restore... */
298                         elog(DEBUG2, "unrecognized node type: %d", (int) nodeTag(node));
299                         break;
300         }
301 }
302
303 /*
304  * ExecRestrPos
305  *
306  * restores the scan position previously saved with ExecMarkPos()
307  *
308  * NOTE: the semantics of this are that the first ExecProcNode following
309  * the restore operation will yield the same tuple as the first one following
310  * the mark operation.  It is unspecified what happens to the plan node's
311  * result TupleTableSlot.  (In most cases the result slot is unchanged by
312  * a restore, but the node may choose to clear it or to load it with the
313  * restored-to tuple.)  Hence the caller should discard any previously
314  * returned TupleTableSlot after doing a restore.
315  */
316 void
317 ExecRestrPos(PlanState *node)
318 {
319         switch (nodeTag(node))
320         {
321                 case T_SeqScanState:
322                         ExecSeqRestrPos((SeqScanState *) node);
323                         break;
324
325                 case T_IndexScanState:
326                         ExecIndexRestrPos((IndexScanState *) node);
327                         break;
328
329                 case T_TidScanState:
330                         ExecTidRestrPos((TidScanState *) node);
331                         break;
332
333                 case T_ValuesScanState:
334                         ExecValuesRestrPos((ValuesScanState *) node);
335                         break;
336
337                 case T_MaterialState:
338                         ExecMaterialRestrPos((MaterialState *) node);
339                         break;
340
341                 case T_SortState:
342                         ExecSortRestrPos((SortState *) node);
343                         break;
344
345                 case T_ResultState:
346                         ExecResultRestrPos((ResultState *) node);
347                         break;
348
349                 default:
350                         elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
351                         break;
352         }
353 }
354
355 /*
356  * ExecSupportsMarkRestore - does a plan type support mark/restore?
357  *
358  * XXX Ideally, all plan node types would support mark/restore, and this
359  * wouldn't be needed.  For now, this had better match the routines above.
360  * But note the test is on Plan nodetype, not PlanState nodetype.
361  *
362  * (However, since the only present use of mark/restore is in mergejoin,
363  * there is no need to support mark/restore in any plan type that is not
364  * capable of generating ordered output.  So the seqscan, tidscan,
365  * and valuesscan support is actually useless code at present.)
366  */
367 bool
368 ExecSupportsMarkRestore(NodeTag plantype)
369 {
370         switch (plantype)
371         {
372                 case T_SeqScan:
373                 case T_IndexScan:
374                 case T_TidScan:
375                 case T_ValuesScan:
376                 case T_Material:
377                 case T_Sort:
378                         return true;
379
380                 case T_Result:
381
382                         /*
383                          * T_Result only supports mark/restore if it has a child plan that
384                          * does, so we do not have enough information to give a really
385                          * correct answer.      However, for current uses it's enough to
386                          * always say "false", because this routine is not asked about
387                          * gating Result plans, only base-case Results.
388                          */
389                         return false;
390
391                 default:
392                         break;
393         }
394
395         return false;
396 }
397
398 /*
399  * ExecSupportsBackwardScan - does a plan type support backwards scanning?
400  *
401  * Ideally, all plan types would support backwards scan, but that seems
402  * unlikely to happen soon.  In some cases, a plan node passes the backwards
403  * scan down to its children, and so supports backwards scan only if its
404  * children do.  Therefore, this routine must be passed a complete plan tree.
405  */
406 bool
407 ExecSupportsBackwardScan(Plan *node)
408 {
409         if (node == NULL)
410                 return false;
411
412         switch (nodeTag(node))
413         {
414                 case T_Result:
415                         if (outerPlan(node) != NULL)
416                                 return ExecSupportsBackwardScan(outerPlan(node)) &&
417                                         TargetListSupportsBackwardScan(node->targetlist);
418                         else
419                                 return false;
420
421                 case T_Append:
422                         {
423                                 ListCell   *l;
424
425                                 foreach(l, ((Append *) node)->appendplans)
426                                 {
427                                         if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
428                                                 return false;
429                                 }
430                                 /* need not check tlist because Append doesn't evaluate it */
431                                 return true;
432                         }
433
434                 case T_SeqScan:
435                 case T_TidScan:
436                 case T_FunctionScan:
437                 case T_ValuesScan:
438                 case T_CteScan:
439                         return TargetListSupportsBackwardScan(node->targetlist);
440
441                 case T_IndexScan:
442                         return IndexSupportsBackwardScan(((IndexScan *) node)->indexid) &&
443                                 TargetListSupportsBackwardScan(node->targetlist);
444
445                 case T_SubqueryScan:
446                         return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan) &&
447                                 TargetListSupportsBackwardScan(node->targetlist);
448
449                 case T_Material:
450                 case T_Sort:
451                         /* these don't evaluate tlist */
452                         return true;
453
454                 case T_LockRows:
455                 case T_Limit:
456                         /* these don't evaluate tlist */
457                         return ExecSupportsBackwardScan(outerPlan(node));
458
459                 default:
460                         return false;
461         }
462 }
463
464 /*
465  * If the tlist contains set-returning functions, we can't support backward
466  * scan, because the TupFromTlist code is direction-ignorant.
467  */
468 static bool
469 TargetListSupportsBackwardScan(List *targetlist)
470 {
471         if (expression_returns_set((Node *) targetlist))
472                 return false;
473         return true;
474 }
475
476 /*
477  * An IndexScan node supports backward scan only if the index's AM does.
478  */
479 static bool
480 IndexSupportsBackwardScan(Oid indexid)
481 {
482         bool            result;
483         HeapTuple       ht_idxrel;
484         HeapTuple       ht_am;
485         Form_pg_class idxrelrec;
486         Form_pg_am      amrec;
487
488         /* Fetch the pg_class tuple of the index relation */
489         ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid));
490         if (!HeapTupleIsValid(ht_idxrel))
491                 elog(ERROR, "cache lookup failed for relation %u", indexid);
492         idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
493
494         /* Fetch the pg_am tuple of the index' access method */
495         ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
496         if (!HeapTupleIsValid(ht_am))
497                 elog(ERROR, "cache lookup failed for access method %u",
498                          idxrelrec->relam);
499         amrec = (Form_pg_am) GETSTRUCT(ht_am);
500
501         result = amrec->amcanbackward;
502
503         ReleaseSysCache(ht_idxrel);
504         ReleaseSysCache(ht_am);
505
506         return result;
507 }
508
509 /*
510  * ExecMaterializesOutput - does a plan type materialize its output?
511  *
512  * Returns true if the plan node type is one that automatically materializes
513  * its output (typically by keeping it in a tuplestore).  For such plans,
514  * a rescan without any parameter change will have zero startup cost and
515  * very low per-tuple cost.
516  */
517 bool
518 ExecMaterializesOutput(NodeTag plantype)
519 {
520         switch (plantype)
521         {
522                 case T_Material:
523                 case T_FunctionScan:
524                 case T_CteScan:
525                 case T_WorkTableScan:
526                 case T_Sort:
527                         return true;
528
529                 default:
530                         break;
531         }
532
533         return false;
534 }