Add support for user-defined I/O conversion casts.
[PostgreSQL.git] / src / backend / executor / execAmi.c
blobb2c4e85e50994b76ed082f6c85ee5891ee7dc1c5
1 /*-------------------------------------------------------------------------
3 * execAmi.c
4 * miscellaneous executor access method routines
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * $PostgreSQL$
11 *-------------------------------------------------------------------------
13 #include "postgres.h"
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/nodeFunctionscan.h"
24 #include "executor/nodeGroup.h"
25 #include "executor/nodeGroup.h"
26 #include "executor/nodeHash.h"
27 #include "executor/nodeHashjoin.h"
28 #include "executor/nodeIndexscan.h"
29 #include "executor/nodeLimit.h"
30 #include "executor/nodeMaterial.h"
31 #include "executor/nodeMergejoin.h"
32 #include "executor/nodeNestloop.h"
33 #include "executor/nodeRecursiveunion.h"
34 #include "executor/nodeResult.h"
35 #include "executor/nodeSeqscan.h"
36 #include "executor/nodeSetOp.h"
37 #include "executor/nodeSort.h"
38 #include "executor/nodeSubplan.h"
39 #include "executor/nodeSubqueryscan.h"
40 #include "executor/nodeTidscan.h"
41 #include "executor/nodeUnique.h"
42 #include "executor/nodeValuesscan.h"
43 #include "executor/nodeCtescan.h"
44 #include "executor/nodeWorktablescan.h"
45 #include "nodes/nodeFuncs.h"
46 #include "utils/syscache.h"
49 static bool TargetListSupportsBackwardScan(List *targetlist);
50 static bool IndexSupportsBackwardScan(Oid indexid);
54 * ExecReScan
55 * Reset a plan node so that its output can be re-scanned.
57 * Note that if the plan node has parameters that have changed value,
58 * the output might be different from last time.
60 * The second parameter is currently only used to pass a NestLoop plan's
61 * econtext down to its inner child plan, in case that is an indexscan that
62 * needs access to variables of the current outer tuple. (The handling of
63 * this parameter is currently pretty inconsistent: some callers pass NULL
64 * and some pass down their parent's value; so don't rely on it in other
65 * situations. It'd probably be better to remove the whole thing and use
66 * the generalized parameter mechanism instead.)
68 void
69 ExecReScan(PlanState *node, ExprContext *exprCtxt)
71 /* If collecting timing stats, update them */
72 if (node->instrument)
73 InstrEndLoop(node->instrument);
76 * If we have changed parameters, propagate that info.
78 * Note: ExecReScanSetParamPlan() can add bits to node->chgParam,
79 * corresponding to the output param(s) that the InitPlan will update.
80 * Since we make only one pass over the list, that means that an InitPlan
81 * can depend on the output param(s) of a sibling InitPlan only if that
82 * sibling appears earlier in the list. This is workable for now given
83 * the limited ways in which one InitPlan could depend on another, but
84 * eventually we might need to work harder (or else make the planner
85 * enlarge the extParam/allParam sets to include the params of depended-on
86 * InitPlans).
88 if (node->chgParam != NULL)
90 ListCell *l;
92 foreach(l, node->initPlan)
94 SubPlanState *sstate = (SubPlanState *) lfirst(l);
95 PlanState *splan = sstate->planstate;
97 if (splan->plan->extParam != NULL) /* don't care about child
98 * local Params */
99 UpdateChangedParamSet(splan, node->chgParam);
100 if (splan->chgParam != NULL)
101 ExecReScanSetParamPlan(sstate, node);
103 foreach(l, node->subPlan)
105 SubPlanState *sstate = (SubPlanState *) lfirst(l);
106 PlanState *splan = sstate->planstate;
108 if (splan->plan->extParam != NULL)
109 UpdateChangedParamSet(splan, node->chgParam);
111 /* Well. Now set chgParam for left/right trees. */
112 if (node->lefttree != NULL)
113 UpdateChangedParamSet(node->lefttree, node->chgParam);
114 if (node->righttree != NULL)
115 UpdateChangedParamSet(node->righttree, node->chgParam);
118 /* Shut down any SRFs in the plan node's targetlist */
119 if (node->ps_ExprContext)
120 ReScanExprContext(node->ps_ExprContext);
122 /* And do node-type-specific processing */
123 switch (nodeTag(node))
125 case T_ResultState:
126 ExecReScanResult((ResultState *) node, exprCtxt);
127 break;
129 case T_AppendState:
130 ExecReScanAppend((AppendState *) node, exprCtxt);
131 break;
133 case T_RecursiveUnionState:
134 ExecRecursiveUnionReScan((RecursiveUnionState *) node, exprCtxt);
135 break;
137 case T_BitmapAndState:
138 ExecReScanBitmapAnd((BitmapAndState *) node, exprCtxt);
139 break;
141 case T_BitmapOrState:
142 ExecReScanBitmapOr((BitmapOrState *) node, exprCtxt);
143 break;
145 case T_SeqScanState:
146 ExecSeqReScan((SeqScanState *) node, exprCtxt);
147 break;
149 case T_IndexScanState:
150 ExecIndexReScan((IndexScanState *) node, exprCtxt);
151 break;
153 case T_BitmapIndexScanState:
154 ExecBitmapIndexReScan((BitmapIndexScanState *) node, exprCtxt);
155 break;
157 case T_BitmapHeapScanState:
158 ExecBitmapHeapReScan((BitmapHeapScanState *) node, exprCtxt);
159 break;
161 case T_TidScanState:
162 ExecTidReScan((TidScanState *) node, exprCtxt);
163 break;
165 case T_SubqueryScanState:
166 ExecSubqueryReScan((SubqueryScanState *) node, exprCtxt);
167 break;
169 case T_FunctionScanState:
170 ExecFunctionReScan((FunctionScanState *) node, exprCtxt);
171 break;
173 case T_ValuesScanState:
174 ExecValuesReScan((ValuesScanState *) node, exprCtxt);
175 break;
177 case T_CteScanState:
178 ExecCteScanReScan((CteScanState *) node, exprCtxt);
179 break;
181 case T_WorkTableScanState:
182 ExecWorkTableScanReScan((WorkTableScanState *) node, exprCtxt);
183 break;
185 case T_NestLoopState:
186 ExecReScanNestLoop((NestLoopState *) node, exprCtxt);
187 break;
189 case T_MergeJoinState:
190 ExecReScanMergeJoin((MergeJoinState *) node, exprCtxt);
191 break;
193 case T_HashJoinState:
194 ExecReScanHashJoin((HashJoinState *) node, exprCtxt);
195 break;
197 case T_MaterialState:
198 ExecMaterialReScan((MaterialState *) node, exprCtxt);
199 break;
201 case T_SortState:
202 ExecReScanSort((SortState *) node, exprCtxt);
203 break;
205 case T_GroupState:
206 ExecReScanGroup((GroupState *) node, exprCtxt);
207 break;
209 case T_AggState:
210 ExecReScanAgg((AggState *) node, exprCtxt);
211 break;
213 case T_UniqueState:
214 ExecReScanUnique((UniqueState *) node, exprCtxt);
215 break;
217 case T_HashState:
218 ExecReScanHash((HashState *) node, exprCtxt);
219 break;
221 case T_SetOpState:
222 ExecReScanSetOp((SetOpState *) node, exprCtxt);
223 break;
225 case T_LimitState:
226 ExecReScanLimit((LimitState *) node, exprCtxt);
227 break;
229 default:
230 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
231 break;
234 if (node->chgParam != NULL)
236 bms_free(node->chgParam);
237 node->chgParam = NULL;
242 * ExecMarkPos
244 * Marks the current scan position.
246 void
247 ExecMarkPos(PlanState *node)
249 switch (nodeTag(node))
251 case T_SeqScanState:
252 ExecSeqMarkPos((SeqScanState *) node);
253 break;
255 case T_IndexScanState:
256 ExecIndexMarkPos((IndexScanState *) node);
257 break;
259 case T_TidScanState:
260 ExecTidMarkPos((TidScanState *) node);
261 break;
263 case T_ValuesScanState:
264 ExecValuesMarkPos((ValuesScanState *) node);
265 break;
267 case T_MaterialState:
268 ExecMaterialMarkPos((MaterialState *) node);
269 break;
271 case T_SortState:
272 ExecSortMarkPos((SortState *) node);
273 break;
275 case T_ResultState:
276 ExecResultMarkPos((ResultState *) node);
277 break;
279 default:
280 /* don't make hard error unless caller asks to restore... */
281 elog(DEBUG2, "unrecognized node type: %d", (int) nodeTag(node));
282 break;
287 * ExecRestrPos
289 * restores the scan position previously saved with ExecMarkPos()
291 * NOTE: the semantics of this are that the first ExecProcNode following
292 * the restore operation will yield the same tuple as the first one following
293 * the mark operation. It is unspecified what happens to the plan node's
294 * result TupleTableSlot. (In most cases the result slot is unchanged by
295 * a restore, but the node may choose to clear it or to load it with the
296 * restored-to tuple.) Hence the caller should discard any previously
297 * returned TupleTableSlot after doing a restore.
299 void
300 ExecRestrPos(PlanState *node)
302 switch (nodeTag(node))
304 case T_SeqScanState:
305 ExecSeqRestrPos((SeqScanState *) node);
306 break;
308 case T_IndexScanState:
309 ExecIndexRestrPos((IndexScanState *) node);
310 break;
312 case T_TidScanState:
313 ExecTidRestrPos((TidScanState *) node);
314 break;
316 case T_ValuesScanState:
317 ExecValuesRestrPos((ValuesScanState *) node);
318 break;
320 case T_MaterialState:
321 ExecMaterialRestrPos((MaterialState *) node);
322 break;
324 case T_SortState:
325 ExecSortRestrPos((SortState *) node);
326 break;
328 case T_ResultState:
329 ExecResultRestrPos((ResultState *) node);
330 break;
332 default:
333 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
334 break;
339 * ExecSupportsMarkRestore - does a plan type support mark/restore?
341 * XXX Ideally, all plan node types would support mark/restore, and this
342 * wouldn't be needed. For now, this had better match the routines above.
343 * But note the test is on Plan nodetype, not PlanState nodetype.
345 * (However, since the only present use of mark/restore is in mergejoin,
346 * there is no need to support mark/restore in any plan type that is not
347 * capable of generating ordered output. So the seqscan, tidscan,
348 * and valuesscan support is actually useless code at present.)
350 bool
351 ExecSupportsMarkRestore(NodeTag plantype)
353 switch (plantype)
355 case T_SeqScan:
356 case T_IndexScan:
357 case T_TidScan:
358 case T_ValuesScan:
359 case T_Material:
360 case T_Sort:
361 return true;
363 case T_Result:
366 * T_Result only supports mark/restore if it has a child plan that
367 * does, so we do not have enough information to give a really
368 * correct answer. However, for current uses it's enough to
369 * always say "false", because this routine is not asked about
370 * gating Result plans, only base-case Results.
372 return false;
374 default:
375 break;
378 return false;
382 * ExecSupportsBackwardScan - does a plan type support backwards scanning?
384 * Ideally, all plan types would support backwards scan, but that seems
385 * unlikely to happen soon. In some cases, a plan node passes the backwards
386 * scan down to its children, and so supports backwards scan only if its
387 * children do. Therefore, this routine must be passed a complete plan tree.
389 bool
390 ExecSupportsBackwardScan(Plan *node)
392 if (node == NULL)
393 return false;
395 switch (nodeTag(node))
397 case T_Result:
398 if (outerPlan(node) != NULL)
399 return ExecSupportsBackwardScan(outerPlan(node)) &&
400 TargetListSupportsBackwardScan(node->targetlist);
401 else
402 return false;
404 case T_Append:
406 ListCell *l;
408 foreach(l, ((Append *) node)->appendplans)
410 if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
411 return false;
413 /* need not check tlist because Append doesn't evaluate it */
414 return true;
417 case T_SeqScan:
418 case T_TidScan:
419 case T_FunctionScan:
420 case T_ValuesScan:
421 case T_CteScan:
422 return TargetListSupportsBackwardScan(node->targetlist);
424 case T_IndexScan:
425 return IndexSupportsBackwardScan(((IndexScan *) node)->indexid) &&
426 TargetListSupportsBackwardScan(node->targetlist);
428 case T_SubqueryScan:
429 return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan) &&
430 TargetListSupportsBackwardScan(node->targetlist);
432 case T_Material:
433 case T_Sort:
434 /* these don't evaluate tlist */
435 return true;
437 case T_Limit:
438 /* doesn't evaluate tlist */
439 return ExecSupportsBackwardScan(outerPlan(node));
441 default:
442 return false;
447 * If the tlist contains set-returning functions, we can't support backward
448 * scan, because the TupFromTlist code is direction-ignorant.
450 static bool
451 TargetListSupportsBackwardScan(List *targetlist)
453 if (expression_returns_set((Node *) targetlist))
454 return false;
455 return true;
459 * An IndexScan node supports backward scan only if the index's AM does.
461 static bool
462 IndexSupportsBackwardScan(Oid indexid)
464 bool result;
465 HeapTuple ht_idxrel;
466 HeapTuple ht_am;
467 Form_pg_class idxrelrec;
468 Form_pg_am amrec;
470 /* Fetch the pg_class tuple of the index relation */
471 ht_idxrel = SearchSysCache(RELOID,
472 ObjectIdGetDatum(indexid),
473 0, 0, 0);
474 if (!HeapTupleIsValid(ht_idxrel))
475 elog(ERROR, "cache lookup failed for relation %u", indexid);
476 idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
478 /* Fetch the pg_am tuple of the index' access method */
479 ht_am = SearchSysCache(AMOID,
480 ObjectIdGetDatum(idxrelrec->relam),
481 0, 0, 0);
482 if (!HeapTupleIsValid(ht_am))
483 elog(ERROR, "cache lookup failed for access method %u",
484 idxrelrec->relam);
485 amrec = (Form_pg_am) GETSTRUCT(ht_am);
487 result = amrec->amcanbackward;
489 ReleaseSysCache(ht_idxrel);
490 ReleaseSysCache(ht_am);
492 return result;