]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeTidscan.c
Use the new List API function names throughout the backend, and disable the
[postgresql] / src / backend / executor / nodeTidscan.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeTidscan.c
4  *        Routines to support direct tid scans of relations
5  *
6  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/executor/nodeTidscan.c,v 1.39 2004/05/30 23:40:26 neilc Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  *
18  *              ExecTidScan                     scans a relation using tids
19  *              ExecInitTidScan         creates and initializes state info.
20  *              ExecTidReScan           rescans the tid relation.
21  *              ExecEndTidScan          releases all storage.
22  *              ExecTidMarkPos          marks scan position.
23  *              ExecTidRestrPos         restores scan position.
24  */
25 #include "postgres.h"
26
27 #include "executor/execdebug.h"
28 #include "executor/nodeTidscan.h"
29 #include "access/heapam.h"
30 #include "parser/parsetree.h"
31
32
33 static void TidListCreate(TidScanState *tidstate);
34 static TupleTableSlot *TidNext(TidScanState *node);
35
36
37 /*
38  * Compute the list of TIDs to be visited, by evaluating the expressions
39  * for them.
40  */
41 static void
42 TidListCreate(TidScanState *tidstate)
43 {
44         List       *evalList = tidstate->tss_tideval;
45         ExprContext *econtext = tidstate->ss.ps.ps_ExprContext;
46         ItemPointerData *tidList;
47         int                     numTids = 0;
48         ListCell   *l;
49
50         tidList = (ItemPointerData *)
51                 palloc(list_length(tidstate->tss_tideval) * sizeof(ItemPointerData));
52
53         foreach(l, evalList)
54         {
55                 ItemPointer itemptr;
56                 bool            isNull;
57
58                 itemptr = (ItemPointer)
59                         DatumGetPointer(ExecEvalExprSwitchContext(lfirst(l),
60                                                                                                           econtext,
61                                                                                                           &isNull,
62                                                                                                           NULL));
63                 if (!isNull && itemptr && ItemPointerIsValid(itemptr))
64                 {
65                         tidList[numTids] = *itemptr;
66                         numTids++;
67                 }
68         }
69
70         tidstate->tss_TidList = tidList;
71         tidstate->tss_NumTids = numTids;
72         tidstate->tss_TidPtr = -1;
73 }
74
75 /* ----------------------------------------------------------------
76  *              TidNext
77  *
78  *              Retrieve a tuple from the TidScan node's currentRelation
79  *              using the tids in the TidScanState information.
80  *
81  * ----------------------------------------------------------------
82  */
83 static TupleTableSlot *
84 TidNext(TidScanState *node)
85 {
86         EState     *estate;
87         ScanDirection direction;
88         Snapshot        snapshot;
89         Relation        heapRelation;
90         HeapTuple       tuple;
91         TupleTableSlot *slot;
92         Index           scanrelid;
93         Buffer          buffer = InvalidBuffer;
94         ItemPointerData *tidList;
95         int                     numTids;
96         bool            bBackward;
97         int                     tidNumber;
98
99         /*
100          * extract necessary information from tid scan node
101          */
102         estate = node->ss.ps.state;
103         direction = estate->es_direction;
104         snapshot = estate->es_snapshot;
105         heapRelation = node->ss.ss_currentRelation;
106         slot = node->ss.ss_ScanTupleSlot;
107         scanrelid = ((TidScan *) node->ss.ps.plan)->scan.scanrelid;
108
109         /*
110          * Clear any reference to the previously returned tuple.  This doesn't
111          * offer any great performance benefit, but it keeps this code in sync
112          * with SeqNext and IndexNext.
113          */
114         ExecClearTuple(slot);
115
116         /*
117          * Check if we are evaluating PlanQual for tuple of this relation.
118          * Additional checking is not good, but no other way for now. We could
119          * introduce new nodes for this case and handle TidScan --> NewNode
120          * switching in Init/ReScan plan...
121          */
122         if (estate->es_evTuple != NULL &&
123                 estate->es_evTuple[scanrelid - 1] != NULL)
124         {
125                 if (estate->es_evTupleNull[scanrelid - 1])
126                         return slot;            /* return empty slot */
127
128                 /*
129                  * XXX shouldn't we check here to make sure tuple matches TID
130                  * list? In runtime-key case this is not certain, is it?
131                  */
132
133                 ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
134                                            slot, InvalidBuffer, false);
135
136                 /* Flag for the next call that no more tuples */
137                 estate->es_evTupleNull[scanrelid - 1] = true;
138                 return (slot);
139         }
140
141         /*
142          * First time through, compute the list of TIDs to be visited
143          */
144         if (node->tss_TidList == NULL)
145                 TidListCreate(node);
146
147         tidList = node->tss_TidList;
148         numTids = node->tss_NumTids;
149
150         tuple = &(node->tss_htup);
151
152         /*
153          * ok, now that we have what we need, fetch an tid tuple. if scanning
154          * this tid succeeded then return the appropriate heap tuple.. else
155          * return NULL.
156          */
157         bBackward = ScanDirectionIsBackward(direction);
158         if (bBackward)
159         {
160                 tidNumber = numTids - node->tss_TidPtr - 1;
161                 if (tidNumber < 0)
162                 {
163                         tidNumber = 0;
164                         node->tss_TidPtr = numTids - 1;
165                 }
166         }
167         else
168         {
169                 if ((tidNumber = node->tss_TidPtr) < 0)
170                 {
171                         tidNumber = 0;
172                         node->tss_TidPtr = 0;
173                 }
174         }
175         while (tidNumber < numTids)
176         {
177                 bool            slot_is_valid = false;
178
179                 tuple->t_self = tidList[node->tss_TidPtr];
180                 if (heap_fetch(heapRelation, snapshot, tuple, &buffer, false, NULL))
181                 {
182                         bool            prev_matches = false;
183                         int                     prev_tid;
184
185                         /*
186                          * store the scanned tuple in the scan tuple slot of the scan
187                          * state.  Eventually we will only do this and not return a
188                          * tuple.  Note: we pass 'false' because tuples returned by
189                          * amgetnext are pointers onto disk pages and were not created
190                          * with palloc() and so should not be pfree()'d.
191                          */
192                         ExecStoreTuple(tuple,           /* tuple to store */
193                                                    slot,        /* slot to store in */
194                                                    buffer,              /* buffer associated with tuple  */
195                                                    false);              /* don't pfree */
196
197                         /*
198                          * At this point we have an extra pin on the buffer, because
199                          * ExecStoreTuple incremented the pin count. Drop our local
200                          * pin.
201                          */
202                         ReleaseBuffer(buffer);
203
204                         /*
205                          * We must check to see if the current tuple would have been
206                          * matched by an earlier tid, so we don't double report it.
207                          */
208                         for (prev_tid = 0; prev_tid < node->tss_TidPtr;
209                                  prev_tid++)
210                         {
211                                 if (ItemPointerEquals(&tidList[prev_tid], &tuple->t_self))
212                                 {
213                                         prev_matches = true;
214                                         break;
215                                 }
216                         }
217                         if (!prev_matches)
218                                 slot_is_valid = true;
219                         else
220                                 ExecClearTuple(slot);
221                 }
222                 tidNumber++;
223                 if (bBackward)
224                         node->tss_TidPtr--;
225                 else
226                         node->tss_TidPtr++;
227                 if (slot_is_valid)
228                         return slot;
229         }
230
231         /*
232          * if we get here it means the tid scan failed so we are at the end of
233          * the scan..
234          */
235         return ExecClearTuple(slot);
236 }
237
238 /* ----------------------------------------------------------------
239  *              ExecTidScan(node)
240  *
241  *              Scans the relation using tids and returns
242  *                 the next qualifying tuple in the direction specified.
243  *              It calls ExecScan() and passes it the access methods which returns
244  *              the next tuple using the tids.
245  *
246  *              Conditions:
247  *                -- the "cursor" maintained by the AMI is positioned at the tuple
248  *                       returned previously.
249  *
250  *              Initial States:
251  *                -- the relation indicated is opened for scanning so that the
252  *                       "cursor" is positioned before the first qualifying tuple.
253  *                -- tidPtr points to the first tid.
254  *                -- state variable ruleFlag = nil.
255  * ----------------------------------------------------------------
256  */
257 TupleTableSlot *
258 ExecTidScan(TidScanState *node)
259 {
260         /*
261          * use TidNext as access method
262          */
263         return ExecScan(&node->ss, (ExecScanAccessMtd) TidNext);
264 }
265
266 /* ----------------------------------------------------------------
267  *              ExecTidReScan(node)
268  * ----------------------------------------------------------------
269  */
270 void
271 ExecTidReScan(TidScanState *node, ExprContext *exprCtxt)
272 {
273         EState     *estate;
274         Index           scanrelid;
275
276         estate = node->ss.ps.state;
277         scanrelid = ((TidScan *) node->ss.ps.plan)->scan.scanrelid;
278
279         /* If we are being passed an outer tuple, save it for runtime key calc */
280         if (exprCtxt != NULL)
281                 node->ss.ps.ps_ExprContext->ecxt_outertuple =
282                         exprCtxt->ecxt_outertuple;
283
284         /* If this is re-scanning of PlanQual ... */
285         if (estate->es_evTuple != NULL &&
286                 estate->es_evTuple[scanrelid - 1] != NULL)
287         {
288                 estate->es_evTupleNull[scanrelid - 1] = false;
289                 return;
290         }
291
292         if (node->tss_TidList)
293                 pfree(node->tss_TidList);
294         node->tss_TidList = NULL;
295         node->tss_NumTids = 0;
296         node->tss_TidPtr = -1;
297 }
298
299 /* ----------------------------------------------------------------
300  *              ExecEndTidScan
301  *
302  *              Releases any storage allocated through C routines.
303  *              Returns nothing.
304  * ----------------------------------------------------------------
305  */
306 void
307 ExecEndTidScan(TidScanState *node)
308 {
309         /*
310          * Free the exprcontext
311          */
312         ExecFreeExprContext(&node->ss.ps);
313
314         /*
315          * clear out tuple table slots
316          */
317         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
318         ExecClearTuple(node->ss.ss_ScanTupleSlot);
319
320         /*
321          * close the heap relation.
322          *
323          * Currently, we do not release the AccessShareLock acquired by
324          * ExecInitTidScan.  This lock should be held till end of transaction.
325          * (There is a faction that considers this too much locking, however.)
326          */
327         heap_close(node->ss.ss_currentRelation, NoLock);
328 }
329
330 /* ----------------------------------------------------------------
331  *              ExecTidMarkPos
332  *
333  *              Marks scan position by marking the current tid.
334  *              Returns nothing.
335  * ----------------------------------------------------------------
336  */
337 void
338 ExecTidMarkPos(TidScanState *node)
339 {
340         node->tss_MarkTidPtr = node->tss_TidPtr;
341 }
342
343 /* ----------------------------------------------------------------
344  *              ExecTidRestrPos
345  *
346  *              Restores scan position by restoring the current tid.
347  *              Returns nothing.
348  *
349  *              XXX Assumes previously marked scan position belongs to current tid
350  * ----------------------------------------------------------------
351  */
352 void
353 ExecTidRestrPos(TidScanState *node)
354 {
355         node->tss_TidPtr = node->tss_MarkTidPtr;
356 }
357
358 /* ----------------------------------------------------------------
359  *              ExecInitTidScan
360  *
361  *              Initializes the tid scan's state information, creates
362  *              scan keys, and opens the base and tid relations.
363  *
364  *              Parameters:
365  *                node: TidNode node produced by the planner.
366  *                estate: the execution state initialized in InitPlan.
367  * ----------------------------------------------------------------
368  */
369 TidScanState *
370 ExecInitTidScan(TidScan *node, EState *estate)
371 {
372         TidScanState *tidstate;
373         List       *rangeTable;
374         RangeTblEntry *rtentry;
375         Oid                     relid;
376         Oid                     reloid;
377         Relation        currentRelation;
378         Bitmapset  *execParam = NULL;
379
380         /*
381          * create state structure
382          */
383         tidstate = makeNode(TidScanState);
384         tidstate->ss.ps.plan = (Plan *) node;
385         tidstate->ss.ps.state = estate;
386
387         /*
388          * Miscellaneous initialization
389          *
390          * create expression context for node
391          */
392         ExecAssignExprContext(estate, &tidstate->ss.ps);
393
394         /*
395          * initialize child expressions
396          */
397         tidstate->ss.ps.targetlist = (List *)
398                 ExecInitExpr((Expr *) node->scan.plan.targetlist,
399                                          (PlanState *) tidstate);
400         tidstate->ss.ps.qual = (List *)
401                 ExecInitExpr((Expr *) node->scan.plan.qual,
402                                          (PlanState *) tidstate);
403
404         tidstate->tss_tideval = (List *)
405                 ExecInitExpr((Expr *) node->tideval,
406                                          (PlanState *) tidstate);
407
408 #define TIDSCAN_NSLOTS 2
409
410         /*
411          * tuple table initialization
412          */
413         ExecInitResultTupleSlot(estate, &tidstate->ss.ps);
414         ExecInitScanTupleSlot(estate, &tidstate->ss);
415
416         /*
417          * mark tid list as not computed yet
418          */
419         tidstate->tss_TidList = NULL;
420         tidstate->tss_NumTids = 0;
421         tidstate->tss_TidPtr = -1;
422
423         /*
424          * get the range table and direction information from the execution
425          * state (these are needed to open the relations).
426          */
427         rangeTable = estate->es_range_table;
428
429         /*
430          * open the base relation
431          *
432          * We acquire AccessShareLock for the duration of the scan.
433          */
434         relid = node->scan.scanrelid;
435         rtentry = rt_fetch(relid, rangeTable);
436         reloid = rtentry->relid;
437
438         currentRelation = heap_open(reloid, AccessShareLock);
439
440         tidstate->ss.ss_currentRelation = currentRelation;
441         tidstate->ss.ss_currentScanDesc = NULL;         /* no heap scan here */
442
443         /*
444          * get the scan type from the relation descriptor.
445          */
446         ExecAssignScanType(&tidstate->ss, RelationGetDescr(currentRelation), false);
447
448         /*
449          * if there are some PARAM_EXEC in skankeys then force tid rescan on
450          * first scan.
451          */
452         tidstate->ss.ps.chgParam = execParam;
453
454         /*
455          * Initialize result tuple type and projection info.
456          */
457         ExecAssignResultTypeFromTL(&tidstate->ss.ps);
458         ExecAssignScanProjectionInfo(&tidstate->ss);
459
460         /*
461          * all done.
462          */
463         return tidstate;
464 }
465
466 int
467 ExecCountSlotsTidScan(TidScan *node)
468 {
469         return ExecCountSlotsNode(outerPlan((Plan *) node)) +
470                 ExecCountSlotsNode(innerPlan((Plan *) node)) + TIDSCAN_NSLOTS;
471 }