1 /*-------------------------------------------------------------------------
4 * miscellaneous executor access method routines
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * $Id: execAmi.c,v 1.60 2001/10/25 05:49:27 momjian Exp $
11 *-------------------------------------------------------------------------
16 * ExecOpenScanR \ / amopen
17 * ExecBeginScan \ / ambeginscan
18 * ExecCloseR \ / amclose
19 * ExecInsert \ executor interface / aminsert
20 * ExecReScanR / to access methods \ amrescan
21 * ExecMarkPos / \ ammarkpos
22 * ExecRestrPos / \ amrestpos
28 #include "access/genam.h"
29 #include "access/heapam.h"
30 #include "catalog/heap.h"
31 #include "executor/execdebug.h"
32 #include "executor/instrument.h"
33 #include "executor/nodeAgg.h"
34 #include "executor/nodeAppend.h"
35 #include "executor/nodeGroup.h"
36 #include "executor/nodeGroup.h"
37 #include "executor/nodeHash.h"
38 #include "executor/nodeHashjoin.h"
39 #include "executor/nodeIndexscan.h"
40 #include "executor/nodeTidscan.h"
41 #include "executor/nodeLimit.h"
42 #include "executor/nodeMaterial.h"
43 #include "executor/nodeMergejoin.h"
44 #include "executor/nodeNestloop.h"
45 #include "executor/nodeResult.h"
46 #include "executor/nodeSeqscan.h"
47 #include "executor/nodeSetOp.h"
48 #include "executor/nodeSort.h"
49 #include "executor/nodeSubplan.h"
50 #include "executor/nodeSubqueryscan.h"
51 #include "executor/nodeUnique.h"
53 static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys,
54 bool isindex, ScanDirection dir, Snapshot snapshot);
56 /* ----------------------------------------------------------------
61 * relation -- relation to be opened and scanned.
62 * nkeys -- number of keys
63 * skeys -- keys to restrict scanning
64 * isindex -- if this is true, the relation is the relid of
65 * an index relation, else it is a heap relation.
66 * Returns the relation as(relDesc scanDesc)
67 * ----------------------------------------------------------------
70 ExecOpenScanR(Oid relOid,
76 Relation *returnRelation, /* return */
77 Pointer *returnScanDesc) /* return */
83 * note: scanDesc returned by ExecBeginScan can be either a
84 * HeapScanDesc or an IndexScanDesc so for now we make it a Pointer.
85 * There should be a better scan abstraction someday -cim 9/9/89
89 * Open the relation with the correct call depending on whether this
90 * is a heap relation or an index relation.
92 * For a table, acquire AccessShareLock for the duration of the query
93 * execution. For indexes, acquire no lock here; the index machinery
94 * does its own locks and unlocks. (We rely on having some kind of
95 * lock on the parent table to ensure the index won't go away!)
98 relation = index_open(relOid);
100 relation = heap_open(relOid, AccessShareLock);
102 scanDesc = ExecBeginScan(relation,
109 if (returnRelation != NULL)
110 *returnRelation = relation;
111 if (scanDesc != NULL)
112 *returnScanDesc = scanDesc;
115 /* ----------------------------------------------------------------
118 * beginscans a relation in current direction.
120 * XXX fix parameters to AMbeginscan (and btbeginscan)
121 * currently we need to pass a flag stating whether
122 * or not the scan should begin at an endpoint of
123 * the relation.. Right now we always pass false
125 * ----------------------------------------------------------------
128 ExecBeginScan(Relation relation,
138 * open the appropriate type of scan.
140 * Note: ambeginscan()'s second arg is a boolean indicating that the scan
141 * should be done in reverse.. That is, if you pass it true, then the
146 scanDesc = (Pointer) index_beginscan(relation,
147 false, /* see above comment */
153 scanDesc = (Pointer) heap_beginscan(relation,
154 ScanDirectionIsBackward(dir),
160 if (scanDesc == NULL)
161 elog(DEBUG, "ExecBeginScan: scanDesc = NULL, heap_beginscan failed.");
166 /* ----------------------------------------------------------------
169 * closes the relation and scan descriptor for a scan node.
170 * Also closes index relations and scans for index scans.
171 * ----------------------------------------------------------------
174 ExecCloseR(Plan *node)
176 CommonScanState *state;
178 HeapScanDesc scanDesc;
181 * get state for node and shut down the heap scan, if any
183 switch (nodeTag(node))
186 state = ((SeqScan *) node)->scanstate;
190 state = ((IndexScan *) node)->scan.scanstate;
194 state = ((TidScan *) node)->scan.scanstate;
198 elog(DEBUG, "ExecCloseR: not a scan node!");
202 relation = state->css_currentRelation;
203 scanDesc = state->css_currentScanDesc;
205 if (scanDesc != NULL)
206 heap_endscan(scanDesc);
209 * if this is an index scan then we have to take care of the index
212 if (IsA(node, IndexScan))
214 IndexScan *iscan = (IndexScan *) node;
215 IndexScanState *indexstate = iscan->indxstate;
217 RelationPtr indexRelationDescs;
218 IndexScanDescPtr indexScanDescs;
221 numIndices = indexstate->iss_NumIndices;
222 indexRelationDescs = indexstate->iss_RelationDescs;
223 indexScanDescs = indexstate->iss_ScanDescs;
225 for (i = 0; i < numIndices; i++)
228 * shut down each of the index scans and close each of the
231 if (indexScanDescs[i] != NULL)
232 index_endscan(indexScanDescs[i]);
234 if (indexRelationDescs[i] != NULL)
235 index_close(indexRelationDescs[i]);
240 * Finally, close the heap relation.
242 * Currently, we do not release the AccessShareLock acquired by
243 * ExecOpenScanR. This lock should be held till end of transaction.
244 * (There is a faction that considers this too much locking, however.)
246 if (relation != NULL)
247 heap_close(relation, NoLock);
250 /* ----------------------------------------------------------------
253 * XXX this should be extended to cope with all the node types..
255 * takes the new expression context as an argument, so that
256 * index scans needn't have their scan keys updated separately
258 * ----------------------------------------------------------------
261 ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
263 if (node->instrument)
264 InstrEndLoop(node->instrument);
266 if (node->chgParam != NULL) /* Wow! */
270 foreach(lst, node->initPlan)
272 Plan *splan = ((SubPlan *) lfirst(lst))->plan;
274 if (splan->extParam != NULL) /* don't care about child
276 SetChangedParamList(splan, node->chgParam);
277 if (splan->chgParam != NULL)
278 ExecReScanSetParamPlan((SubPlan *) lfirst(lst), node);
280 foreach(lst, node->subPlan)
282 Plan *splan = ((SubPlan *) lfirst(lst))->plan;
284 if (splan->extParam != NULL)
285 SetChangedParamList(splan, node->chgParam);
287 /* Well. Now set chgParam for left/right trees. */
288 if (node->lefttree != NULL)
289 SetChangedParamList(node->lefttree, node->chgParam);
290 if (node->righttree != NULL)
291 SetChangedParamList(node->righttree, node->chgParam);
294 switch (nodeTag(node))
297 ExecSeqReScan((SeqScan *) node, exprCtxt, parent);
301 ExecIndexReScan((IndexScan *) node, exprCtxt, parent);
305 ExecTidReScan((TidScan *) node, exprCtxt, parent);
309 ExecSubqueryReScan((SubqueryScan *) node, exprCtxt, parent);
313 ExecMaterialReScan((Material *) node, exprCtxt, parent);
317 ExecReScanNestLoop((NestLoop *) node, exprCtxt, parent);
321 ExecReScanHashJoin((HashJoin *) node, exprCtxt, parent);
325 ExecReScanHash((Hash *) node, exprCtxt, parent);
329 ExecReScanAgg((Agg *) node, exprCtxt, parent);
333 ExecReScanGroup((Group *) node, exprCtxt, parent);
337 ExecReScanResult((Result *) node, exprCtxt, parent);
341 ExecReScanUnique((Unique *) node, exprCtxt, parent);
345 ExecReScanSetOp((SetOp *) node, exprCtxt, parent);
349 ExecReScanLimit((Limit *) node, exprCtxt, parent);
353 ExecReScanSort((Sort *) node, exprCtxt, parent);
357 ExecReScanMergeJoin((MergeJoin *) node, exprCtxt, parent);
361 ExecReScanAppend((Append *) node, exprCtxt, parent);
365 elog(ERROR, "ExecReScan: node type %d not supported",
370 if (node->chgParam != NULL)
372 freeList(node->chgParam);
373 node->chgParam = NULL;
377 /* ----------------------------------------------------------------
380 * XXX this does not do the right thing with indices yet.
381 * ----------------------------------------------------------------
384 ExecReScanR(Relation relDesc, /* LLL relDesc unused */
385 HeapScanDesc scanDesc,
386 ScanDirection direction,
387 int nkeys, /* LLL nkeys unused */
390 if (scanDesc != NULL)
391 heap_rescan(scanDesc, /* scan desc */
392 ScanDirectionIsBackward(direction), /* backward flag */
393 skeys); /* scan keys */
398 /* ----------------------------------------------------------------
401 * Marks the current scan position.
403 * XXX Needs to be extended to include all the node types,
404 * or at least all the ones that can be directly below a mergejoin.
405 * ----------------------------------------------------------------
408 ExecMarkPos(Plan *node)
410 switch (nodeTag(node))
413 ExecSeqMarkPos((SeqScan *) node);
417 ExecIndexMarkPos((IndexScan *) node);
421 ExecMaterialMarkPos((Material *) node);
425 ExecSortMarkPos((Sort *) node);
429 ExecTidMarkPos((TidScan *) node);
433 /* don't make hard error unless caller asks to restore... */
434 elog(DEBUG, "ExecMarkPos: node type %d not supported",
440 /* ----------------------------------------------------------------
443 * restores the scan position previously saved with ExecMarkPos()
445 * XXX Needs to be extended to include all the node types,
446 * or at least all the ones that can be directly below a mergejoin.
447 * ----------------------------------------------------------------
450 ExecRestrPos(Plan *node)
452 switch (nodeTag(node))
455 ExecSeqRestrPos((SeqScan *) node);
459 ExecIndexRestrPos((IndexScan *) node);
463 ExecMaterialRestrPos((Material *) node);
467 ExecSortRestrPos((Sort *) node);
471 elog(ERROR, "ExecRestrPos: node type %d not supported",