]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeTidscan.c
pgindent run. Make it all clean.
[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-2001, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.15 2001/03/22 03:59:29 momjian 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  *
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 static int      TidListCreate(List *, ExprContext *, ItemPointer *);
33 static TupleTableSlot *TidNext(TidScan *node);
34
35 static int
36 TidListCreate(List *evalList, ExprContext *econtext, ItemPointer *tidList)
37 {
38         List       *lst;
39         ItemPointer itemptr;
40         bool            isNull;
41         int                     numTids = 0;
42
43         foreach(lst, evalList)
44         {
45                 itemptr = (ItemPointer)
46                         DatumGetPointer(ExecEvalExprSwitchContext(lfirst(lst),
47                                                                                                           econtext,
48                                                                                                           &isNull,
49                                                                                                           NULL));
50                 if (!isNull && itemptr && ItemPointerIsValid(itemptr))
51                 {
52                         tidList[numTids] = itemptr;
53                         numTids++;
54                 }
55         }
56         return numTids;
57 }
58
59 /* ----------------------------------------------------------------
60  *              TidNext
61  *
62  *              Retrieve a tuple from the TidScan node's currentRelation
63  *              using the tids in the TidScanState information.
64  *
65  * ----------------------------------------------------------------
66  */
67 static TupleTableSlot *
68 TidNext(TidScan *node)
69 {
70         EState     *estate;
71         CommonScanState *scanstate;
72         TidScanState *tidstate;
73         ScanDirection direction;
74         Snapshot        snapshot;
75         Relation        heapRelation;
76         HeapTuple       tuple;
77         TupleTableSlot *slot;
78         Buffer          buffer = InvalidBuffer;
79         int                     numTids;
80
81         bool            bBackward;
82         int                     tidNumber;
83         ItemPointer *tidList,
84                                 itemptr;
85
86         /* ----------------
87          *      extract necessary information from tid scan node
88          * ----------------
89          */
90         estate = node->scan.plan.state;
91         direction = estate->es_direction;
92         snapshot = estate->es_snapshot;
93         scanstate = node->scan.scanstate;
94         tidstate = node->tidstate;
95         heapRelation = scanstate->css_currentRelation;
96         numTids = tidstate->tss_NumTids;
97         tidList = tidstate->tss_TidList;
98         slot = scanstate->css_ScanTupleSlot;
99
100         /*
101          * Check if we are evaluating PlanQual for tuple of this relation.
102          * Additional checking is not good, but no other way for now. We could
103          * introduce new nodes for this case and handle TidScan --> NewNode
104          * switching in Init/ReScan plan...
105          */
106         if (estate->es_evTuple != NULL &&
107                 estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
108         {
109                 ExecClearTuple(slot);
110                 if (estate->es_evTupleNull[node->scan.scanrelid - 1])
111                         return slot;            /* return empty slot */
112
113                 ExecStoreTuple(estate->es_evTuple[node->scan.scanrelid - 1],
114                                            slot, InvalidBuffer, false);
115
116                 /* Flag for the next call that no more tuples */
117                 estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
118                 return (slot);
119         }
120
121         tuple = &(tidstate->tss_htup);
122
123         /* ----------------
124          *      ok, now that we have what we need, fetch an tid tuple.
125          *      if scanning this tid succeeded then return the
126          *      appropriate heap tuple.. else return NULL.
127          * ----------------
128          */
129         bBackward = ScanDirectionIsBackward(direction);
130         if (bBackward)
131         {
132                 tidNumber = numTids - tidstate->tss_TidPtr - 1;
133                 if (tidNumber < 0)
134                 {
135                         tidNumber = 0;
136                         tidstate->tss_TidPtr = numTids - 1;
137                 }
138         }
139         else
140         {
141                 if ((tidNumber = tidstate->tss_TidPtr) < 0)
142                 {
143                         tidNumber = 0;
144                         tidstate->tss_TidPtr = 0;
145                 }
146         }
147         while (tidNumber < numTids)
148         {
149                 bool            slot_is_valid = false;
150
151                 itemptr = tidList[tidstate->tss_TidPtr];
152                 tuple->t_datamcxt = NULL;
153                 tuple->t_data = NULL;
154                 if (itemptr)
155                 {
156                         tuple->t_self = *(itemptr);
157                         heap_fetch(heapRelation, snapshot, tuple, &buffer);
158                 }
159                 if (tuple->t_data != NULL)
160                 {
161                         bool            prev_matches = false;
162                         int                     prev_tid;
163
164                         /* ----------------
165                          *      store the scanned tuple in the scan tuple slot of
166                          *      the scan state.  Eventually we will only do this and not
167                          *      return a tuple.  Note: we pass 'false' because tuples
168                          *      returned by amgetnext are pointers onto disk pages and
169                          *      were not created with palloc() and so should not be pfree()'d.
170                          * ----------------
171                          */
172                         ExecStoreTuple(tuple,           /* tuple to store */
173                                                    slot,/* slot to store in */
174                                                    buffer,              /* buffer associated with tuple  */
175                                                    false);              /* don't pfree */
176
177                         /*
178                          * At this point we have an extra pin on the buffer, because
179                          * ExecStoreTuple incremented the pin count. Drop our local
180                          * pin.
181                          */
182                         ReleaseBuffer(buffer);
183
184                         /*
185                          * We must check to see if the current tuple would have been
186                          * matched by an earlier tid, so we don't double report it. We
187                          * do this by passing the tuple through ExecQual and look for
188                          * failure with all previous qualifications.
189                          */
190                         for (prev_tid = 0; prev_tid < tidstate->tss_TidPtr;
191                                  prev_tid++)
192                         {
193                                 if (ItemPointerEquals(tidList[prev_tid], &tuple->t_self))
194                                 {
195                                         prev_matches = true;
196                                         break;
197                                 }
198                         }
199                         if (!prev_matches)
200                                 slot_is_valid = true;
201                         else
202                                 ExecClearTuple(slot);
203                 }
204                 else if (BufferIsValid(buffer))
205                         ReleaseBuffer(buffer);
206                 tidNumber++;
207                 if (bBackward)
208                         tidstate->tss_TidPtr--;
209                 else
210                         tidstate->tss_TidPtr++;
211                 if (slot_is_valid)
212                         return slot;
213         }
214         /* ----------------
215          *      if we get here it means the tid scan failed so we
216          *      are at the end of the scan..
217          * ----------------
218          */
219         return ExecClearTuple(slot);
220 }
221
222 /* ----------------------------------------------------------------
223  *              ExecTidScan(node)
224  *
225  *              Scans the relation using tids and returns
226  *                 the next qualifying tuple in the direction specified.
227  *              It calls ExecScan() and passes it the access methods which returns
228  *              the next tuple using the tids.
229  *
230  *              Conditions:
231  *                -- the "cursor" maintained by the AMI is positioned at the tuple
232  *                       returned previously.
233  *
234  *              Initial States:
235  *                -- the relation indicated is opened for scanning so that the
236  *                       "cursor" is positioned before the first qualifying tuple.
237  *                -- tidPtr points to the first tid.
238  *                -- state variable ruleFlag = nil.
239  * ----------------------------------------------------------------
240  */
241 TupleTableSlot *
242 ExecTidScan(TidScan *node)
243 {
244         /* ----------------
245          *      use TidNext as access method
246          * ----------------
247          */
248         return ExecScan(&node->scan, (ExecScanAccessMtd) TidNext);
249 }
250
251 /* ----------------------------------------------------------------
252  *              ExecTidReScan(node)
253  * ----------------------------------------------------------------
254  */
255 void
256 ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
257 {
258         EState     *estate;
259         TidScanState *tidstate;
260         ItemPointer *tidList;
261
262         tidstate = node->tidstate;
263         estate = node->scan.plan.state;
264         tidstate->tss_TidPtr = -1;
265         tidList = tidstate->tss_TidList;
266
267         /* If we are being passed an outer tuple, save it for runtime key calc */
268         if (exprCtxt != NULL)
269                 node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple =
270                         exprCtxt->ecxt_outertuple;
271
272         /* If this is re-scanning of PlanQual ... */
273         if (estate->es_evTuple != NULL &&
274                 estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
275         {
276                 estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
277                 return;
278         }
279
280         tidstate->tss_NumTids = TidListCreate(node->tideval,
281                                                          node->scan.scanstate->cstate.cs_ExprContext,
282                                                                                   tidList);
283
284         /* ----------------
285          *      perhaps return something meaningful
286          * ----------------
287          */
288         return;
289 }
290
291 /* ----------------------------------------------------------------
292  *              ExecEndTidScan
293  *
294  *              Releases any storage allocated through C routines.
295  *              Returns nothing.
296  * ----------------------------------------------------------------
297  */
298 void
299 ExecEndTidScan(TidScan *node)
300 {
301         CommonScanState *scanstate;
302         TidScanState *tidstate;
303
304         scanstate = node->scan.scanstate;
305         tidstate = node->tidstate;
306         if (tidstate && tidstate->tss_TidList)
307                 pfree(tidstate->tss_TidList);
308
309         /* ----------------
310          *      extract information from the node
311          * ----------------
312          */
313
314         /* ----------------
315          *      Free the projection info and the scan attribute info
316          *
317          *      Note: we don't ExecFreeResultType(scanstate)
318          *                because the rule manager depends on the tupType
319          *                returned by ExecMain().  So for now, this
320          *                is freed at end-transaction time.  -cim 6/2/91
321          * ----------------
322          */
323         ExecFreeProjectionInfo(&scanstate->cstate);
324         ExecFreeExprContext(&scanstate->cstate);
325
326         /* ----------------
327          *      close the heap and tid relations
328          * ----------------
329          */
330         ExecCloseR((Plan *) node);
331
332         /* ----------------
333          *      clear out tuple table slots
334          * ----------------
335          */
336         ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
337         ExecClearTuple(scanstate->css_ScanTupleSlot);
338 }
339
340 /* ----------------------------------------------------------------
341  *              ExecTidMarkPos
342  *
343  *              Marks scan position by marking the current tid.
344  *              Returns nothing.
345  * ----------------------------------------------------------------
346  */
347 void
348 ExecTidMarkPos(TidScan *node)
349 {
350         TidScanState *tidstate;
351
352         tidstate = node->tidstate;
353         tidstate->tss_MarkTidPtr = tidstate->tss_TidPtr;
354 }
355
356 #ifdef NOT_USED
357 /* ----------------------------------------------------------------
358  *              ExecTidRestrPos
359  *
360  *              Restores scan position by restoring the current tid.
361  *              Returns nothing.
362  *
363  *              XXX Assumes previously marked scan position belongs to current tid
364  * ----------------------------------------------------------------
365  */
366 void
367 ExecTidRestrPos(TidScan *node)
368 {
369         TidScanState *tidstate;
370
371         tidstate = node->tidstate;
372         tidstate->tss_TidPtr = tidstate->tss_MarkTidPtr;
373 }
374
375 #endif
376
377 /* ----------------------------------------------------------------
378  *              ExecInitTidScan
379  *
380  *              Initializes the tid scan's state information, creates
381  *              scan keys, and opens the base and tid relations.
382  *
383  *              Parameters:
384  *                node: TidNode node produced by the planner.
385  *                estate: the execution state initialized in InitPlan.
386  * ----------------------------------------------------------------
387  */
388 bool
389 ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
390 {
391         TidScanState *tidstate;
392         CommonScanState *scanstate;
393         ItemPointer *tidList;
394         int                     numTids;
395         int                     tidPtr;
396         List       *rangeTable;
397         RangeTblEntry *rtentry;
398         Oid                     relid;
399         Oid                     reloid;
400         Relation        currentRelation;
401         List       *execParam = NIL;
402
403         /* ----------------
404          *      assign execution state to node
405          * ----------------
406          */
407         node->scan.plan.state = estate;
408
409         /* --------------------------------
410          *      Part 1)  initialize scan state
411          *
412          *      create new CommonScanState for node
413          * --------------------------------
414          */
415         scanstate = makeNode(CommonScanState);
416         node->scan.scanstate = scanstate;
417
418         /* ----------------
419          *      Miscellaneous initialization
420          *
421          *               +      create expression context for node
422          * ----------------
423          */
424         ExecAssignExprContext(estate, &scanstate->cstate);
425
426 #define TIDSCAN_NSLOTS 3
427         /* ----------------
428          *      tuple table initialization
429          * ----------------
430          */
431         ExecInitResultTupleSlot(estate, &scanstate->cstate);
432         ExecInitScanTupleSlot(estate, scanstate);
433
434         /* ----------------
435          *      initialize projection info.  result type comes from scan desc
436          *      below..
437          * ----------------
438          */
439         ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
440
441         /* --------------------------------
442           *  Part 2)  initialize tid scan state
443           *
444           *  create new TidScanState for node
445           * --------------------------------
446           */
447         tidstate = makeNode(TidScanState);
448         node->tidstate = tidstate;
449
450         /* ----------------
451          *      get the tid node information
452          * ----------------
453          */
454         tidList = (ItemPointer *) palloc(length(node->tideval) * sizeof(ItemPointer));
455         numTids = 0;
456         if (!node->needRescan)
457                 numTids = TidListCreate(node->tideval, scanstate->cstate.cs_ExprContext, tidList);
458         tidPtr = -1;
459
460         CXT1_printf("ExecInitTidScan: context is %d\n", CurrentMemoryContext);
461
462         tidstate->tss_NumTids = numTids;
463         tidstate->tss_TidPtr = tidPtr;
464         tidstate->tss_TidList = tidList;
465
466         /* ----------------
467          *      get the range table and direction information
468          *      from the execution state (these are needed to
469          *      open the relations).
470          * ----------------
471          */
472         rangeTable = estate->es_range_table;
473
474         /* ----------------
475          *      open the base relation
476          * ----------------
477          */
478         relid = node->scan.scanrelid;
479         rtentry = rt_fetch(relid, rangeTable);
480         reloid = rtentry->relid;
481
482         currentRelation = heap_open(reloid, AccessShareLock);
483         scanstate->css_currentRelation = currentRelation;
484         scanstate->css_currentScanDesc = 0;
485
486         /* ----------------
487          *      get the scan type from the relation descriptor.
488          * ----------------
489          */
490         ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
491         ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
492
493         /*
494          * if there are some PARAM_EXEC in skankeys then force tid rescan on
495          * first scan.
496          */
497         ((Plan *) node)->chgParam = execParam;
498
499         /* ----------------
500          *      all done.
501          * ----------------
502          */
503         return TRUE;
504 }
505
506 int
507 ExecCountSlotsTidScan(TidScan *node)
508 {
509         return ExecCountSlotsNode(outerPlan((Plan *) node)) +
510         ExecCountSlotsNode(innerPlan((Plan *) node)) + TIDSCAN_NSLOTS;
511 }