1 /*-------------------------------------------------------------------------
4 * Support routines for sequential scans of relations.
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
17 * ExecSeqScan sequentially scans a relation.
18 * ExecSeqNext retrieve next tuple in sequential order.
19 * ExecInitSeqScan creates and initializes a seqscan node.
20 * ExecEndSeqScan releases any storage allocated.
21 * ExecSeqReScan rescans the relation
22 * ExecSeqMarkPos marks scan position
23 * ExecSeqRestrPos restores scan position
27 #include "access/heapam.h"
28 #include "access/relscan.h"
29 #include "executor/execdebug.h"
30 #include "executor/nodeSeqscan.h"
32 static void InitScanRelation(SeqScanState
*node
, EState
*estate
);
33 static TupleTableSlot
*SeqNext(SeqScanState
*node
);
35 /* ----------------------------------------------------------------
37 * ----------------------------------------------------------------
39 /* ----------------------------------------------------------------
42 * This is a workhorse for ExecSeqScan
43 * ----------------------------------------------------------------
45 static TupleTableSlot
*
46 SeqNext(SeqScanState
*node
)
49 HeapScanDesc scandesc
;
52 ScanDirection direction
;
56 * get information from the estate and scan state
58 estate
= node
->ps
.state
;
59 scandesc
= node
->ss_currentScanDesc
;
60 scanrelid
= ((SeqScan
*) node
->ps
.plan
)->scanrelid
;
61 direction
= estate
->es_direction
;
62 slot
= node
->ss_ScanTupleSlot
;
65 * Check if we are evaluating PlanQual for tuple of this relation.
66 * Additional checking is not good, but no other way for now. We could
67 * introduce new nodes for this case and handle SeqScan --> NewNode
68 * switching in Init/ReScan plan...
70 if (estate
->es_evTuple
!= NULL
&&
71 estate
->es_evTuple
[scanrelid
- 1] != NULL
)
73 if (estate
->es_evTupleNull
[scanrelid
- 1])
74 return ExecClearTuple(slot
);
76 ExecStoreTuple(estate
->es_evTuple
[scanrelid
- 1],
77 slot
, InvalidBuffer
, false);
80 * Note that unlike IndexScan, SeqScan never use keys in
81 * heap_beginscan (and this is very bad) - so, here we do not check
85 /* Flag for the next call that no more tuples */
86 estate
->es_evTupleNull
[scanrelid
- 1] = true;
91 * get the next tuple from the access methods
93 tuple
= heap_getnext(scandesc
, direction
);
96 * save the tuple and the buffer returned to us by the access methods in
97 * our scan tuple slot and return the slot. Note: we pass 'false' because
98 * tuples returned by heap_getnext() are pointers onto disk pages and were
99 * not created with palloc() and so should not be pfree()'d. Note also
100 * that ExecStoreTuple will increment the refcount of the buffer; the
101 * refcount will not be dropped until the tuple table slot is cleared.
104 ExecStoreTuple(tuple
, /* tuple to store */
105 slot
, /* slot to store in */
106 scandesc
->rs_cbuf
, /* buffer associated with this
108 false); /* don't pfree this pointer */
110 ExecClearTuple(slot
);
115 /* ----------------------------------------------------------------
118 * Scans the relation sequentially and returns the next qualifying
120 * It calls the ExecScan() routine and passes it the access method
121 * which retrieve tuples sequentially.
126 ExecSeqScan(SeqScanState
*node
)
129 * use SeqNext as access method
131 return ExecScan((ScanState
*) node
, (ExecScanAccessMtd
) SeqNext
);
134 /* ----------------------------------------------------------------
137 * This does the initialization for scan relations and
139 * ----------------------------------------------------------------
142 InitScanRelation(SeqScanState
*node
, EState
*estate
)
144 Relation currentRelation
;
145 HeapScanDesc currentScanDesc
;
148 * get the relation object id from the relid'th entry in the range table,
149 * open that relation and acquire appropriate lock on it.
151 currentRelation
= ExecOpenScanRelation(estate
,
152 ((SeqScan
*) node
->ps
.plan
)->scanrelid
);
154 currentScanDesc
= heap_beginscan(currentRelation
,
159 node
->ss_currentRelation
= currentRelation
;
160 node
->ss_currentScanDesc
= currentScanDesc
;
162 ExecAssignScanType(node
, RelationGetDescr(currentRelation
));
166 /* ----------------------------------------------------------------
168 * ----------------------------------------------------------------
171 ExecInitSeqScan(SeqScan
*node
, EState
*estate
, int eflags
)
173 SeqScanState
*scanstate
;
176 * Once upon a time it was possible to have an outerPlan of a SeqScan, but
179 Assert(outerPlan(node
) == NULL
);
180 Assert(innerPlan(node
) == NULL
);
183 * create state structure
185 scanstate
= makeNode(SeqScanState
);
186 scanstate
->ps
.plan
= (Plan
*) node
;
187 scanstate
->ps
.state
= estate
;
190 * Miscellaneous initialization
192 * create expression context for node
194 ExecAssignExprContext(estate
, &scanstate
->ps
);
197 * initialize child expressions
199 scanstate
->ps
.targetlist
= (List
*)
200 ExecInitExpr((Expr
*) node
->plan
.targetlist
,
201 (PlanState
*) scanstate
);
202 scanstate
->ps
.qual
= (List
*)
203 ExecInitExpr((Expr
*) node
->plan
.qual
,
204 (PlanState
*) scanstate
);
206 #define SEQSCAN_NSLOTS 2
209 * tuple table initialization
211 ExecInitResultTupleSlot(estate
, &scanstate
->ps
);
212 ExecInitScanTupleSlot(estate
, scanstate
);
215 * initialize scan relation
217 InitScanRelation(scanstate
, estate
);
219 scanstate
->ps
.ps_TupFromTlist
= false;
222 * Initialize result tuple type and projection info.
224 ExecAssignResultTypeFromTL(&scanstate
->ps
);
225 ExecAssignScanProjectionInfo(scanstate
);
231 ExecCountSlotsSeqScan(SeqScan
*node
)
233 return ExecCountSlotsNode(outerPlan(node
)) +
234 ExecCountSlotsNode(innerPlan(node
)) +
238 /* ----------------------------------------------------------------
241 * frees any storage allocated through C routines.
242 * ----------------------------------------------------------------
245 ExecEndSeqScan(SeqScanState
*node
)
248 HeapScanDesc scanDesc
;
251 * get information from node
253 relation
= node
->ss_currentRelation
;
254 scanDesc
= node
->ss_currentScanDesc
;
257 * Free the exprcontext
259 ExecFreeExprContext(&node
->ps
);
262 * clean out the tuple table
264 ExecClearTuple(node
->ps
.ps_ResultTupleSlot
);
265 ExecClearTuple(node
->ss_ScanTupleSlot
);
270 heap_endscan(scanDesc
);
273 * close the heap relation.
275 ExecCloseScanRelation(relation
);
278 /* ----------------------------------------------------------------
280 * ----------------------------------------------------------------
283 /* ----------------------------------------------------------------
286 * Rescans the relation.
287 * ----------------------------------------------------------------
290 ExecSeqReScan(SeqScanState
*node
, ExprContext
*exprCtxt
)
296 estate
= node
->ps
.state
;
297 scanrelid
= ((SeqScan
*) node
->ps
.plan
)->scanrelid
;
299 node
->ps
.ps_TupFromTlist
= false;
301 /* If this is re-scanning of PlanQual ... */
302 if (estate
->es_evTuple
!= NULL
&&
303 estate
->es_evTuple
[scanrelid
- 1] != NULL
)
305 estate
->es_evTupleNull
[scanrelid
- 1] = false;
309 scan
= node
->ss_currentScanDesc
;
311 heap_rescan(scan
, /* scan desc */
312 NULL
); /* new scan keys */
315 /* ----------------------------------------------------------------
316 * ExecSeqMarkPos(node)
318 * Marks scan position.
319 * ----------------------------------------------------------------
322 ExecSeqMarkPos(SeqScanState
*node
)
324 HeapScanDesc scan
= node
->ss_currentScanDesc
;
329 /* ----------------------------------------------------------------
332 * Restores scan position.
333 * ----------------------------------------------------------------
336 ExecSeqRestrPos(SeqScanState
*node
)
338 HeapScanDesc scan
= node
->ss_currentScanDesc
;
341 * Clear any reference to the previously returned tuple. This is needed
342 * because the slot is simply pointing at scan->rs_cbuf, which
343 * heap_restrpos will change; we'd have an internally inconsistent slot if
346 ExecClearTuple(node
->ss_ScanTupleSlot
);