]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeTidscan.c
Remove 576 references of include files that were not needed.
[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-2006, 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.50 2006/07/14 14:52:19 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  *              ExecTidRestrPos         restores scan position.
24  */
25 #include "postgres.h"
26
27 #include "access/heapam.h"
28 #include "catalog/pg_type.h"
29 #include "executor/execdebug.h"
30 #include "executor/nodeTidscan.h"
31 #include "optimizer/clauses.h"
32 #include "utils/array.h"
33
34
35 #define IsCTIDVar(node)  \
36         ((node) != NULL && \
37          IsA((node), Var) && \
38          ((Var *) (node))->varattno == SelfItemPointerAttributeNumber && \
39          ((Var *) (node))->varlevelsup == 0)
40
41 static void TidListCreate(TidScanState *tidstate);
42 static int      itemptr_comparator(const void *a, const void *b);
43 static TupleTableSlot *TidNext(TidScanState *node);
44
45
46 /*
47  * Compute the list of TIDs to be visited, by evaluating the expressions
48  * for them.
49  *
50  * (The result is actually an array, not a list.)
51  */
52 static void
53 TidListCreate(TidScanState *tidstate)
54 {
55         List       *evalList = tidstate->tss_tidquals;
56         ExprContext *econtext = tidstate->ss.ps.ps_ExprContext;
57         ItemPointerData *tidList;
58         int                     numAllocTids;
59         int                     numTids;
60         ListCell   *l;
61
62         /*
63          * We initialize the array with enough slots for the case that all
64          * quals are simple OpExprs.  If there's any ScalarArrayOpExprs,
65          * we may have to enlarge the array.
66          */
67         numAllocTids = list_length(evalList);
68         tidList = (ItemPointerData *)
69                 palloc(numAllocTids * sizeof(ItemPointerData));
70         numTids = 0;
71
72         foreach(l, evalList)
73         {
74                 ExprState  *exstate = (ExprState *) lfirst(l);
75                 Expr       *expr = exstate->expr;
76                 ItemPointer itemptr;
77                 bool            isNull;
78
79                 if (is_opclause(expr))
80                 {
81                         FuncExprState  *fexstate = (FuncExprState *) exstate;
82                         Node *arg1;
83                         Node *arg2;
84
85                         arg1 = get_leftop(expr);
86                         arg2 = get_rightop(expr);
87                         if (IsCTIDVar(arg1))
88                                 exstate = (ExprState *) lsecond(fexstate->args);
89                         else if (IsCTIDVar(arg2))
90                                 exstate = (ExprState *) linitial(fexstate->args);
91                         else
92                                 elog(ERROR, "could not identify CTID variable");
93
94                         itemptr = (ItemPointer)
95                                 DatumGetPointer(ExecEvalExprSwitchContext(exstate,
96                                                                                                                   econtext,
97                                                                                                                   &isNull,
98                                                                                                                   NULL));
99                         if (!isNull && ItemPointerIsValid(itemptr))
100                         {
101                                 if (numTids >= numAllocTids)
102                                 {
103                                         numAllocTids *= 2;
104                                         tidList = (ItemPointerData *)
105                                                 repalloc(tidList,
106                                                                  numAllocTids * sizeof(ItemPointerData));
107                                 }
108                                 tidList[numTids++] = *itemptr;
109                         }
110                 }
111                 else if (expr && IsA(expr, ScalarArrayOpExpr))
112                 {
113                         ScalarArrayOpExprState *saexstate = (ScalarArrayOpExprState *) exstate;
114                         Datum           arraydatum;
115                         ArrayType  *itemarray;
116                         Datum      *ipdatums;
117                         bool       *ipnulls;
118                         int                     ndatums;
119                         int                     i;
120
121                         exstate = (ExprState *) lsecond(saexstate->fxprstate.args);
122                         arraydatum = ExecEvalExprSwitchContext(exstate,
123                                                                                                    econtext,
124                                                                                                    &isNull,
125                                                                                                    NULL);
126                         if (isNull)
127                                 continue;
128                         itemarray = DatumGetArrayTypeP(arraydatum);
129                         deconstruct_array(itemarray,
130                                                           TIDOID, SizeOfIptrData, false, 's',
131                                                           &ipdatums, &ipnulls, &ndatums);
132                         if (numTids + ndatums > numAllocTids)
133                         {
134                                 numAllocTids = numTids + ndatums;
135                                 tidList = (ItemPointerData *)
136                                         repalloc(tidList,
137                                                          numAllocTids * sizeof(ItemPointerData));
138                         }
139                         for (i = 0; i < ndatums; i++)
140                         {
141                                 if (!ipnulls[i])
142                                 {
143                                         itemptr = (ItemPointer) DatumGetPointer(ipdatums[i]);
144                                         if (ItemPointerIsValid(itemptr))
145                                                 tidList[numTids++] = *itemptr;
146                                 }
147                         }
148                         pfree(ipdatums);
149                         pfree(ipnulls);
150                 }
151                 else
152                         elog(ERROR, "could not identify CTID expression");
153         }
154
155         /*
156          * Sort the array of TIDs into order, and eliminate duplicates.
157          * Eliminating duplicates is necessary since we want OR semantics
158          * across the list.  Sorting makes it easier to detect duplicates,
159          * and as a bonus ensures that we will visit the heap in the most
160          * efficient way.
161          */
162         if (numTids > 1)
163         {
164                 int             lastTid;
165                 int             i;
166
167                 qsort((void *) tidList, numTids, sizeof(ItemPointerData),
168                           itemptr_comparator);
169                 lastTid = 0;
170                 for (i = 1; i < numTids; i++)
171                 {
172                         if (!ItemPointerEquals(&tidList[lastTid], &tidList[i]))
173                                 tidList[++lastTid] = tidList[i];
174                 }
175                 numTids = lastTid + 1;
176         }
177
178         tidstate->tss_TidList = tidList;
179         tidstate->tss_NumTids = numTids;
180         tidstate->tss_TidPtr = -1;
181 }
182
183 /*
184  * qsort comparator for ItemPointerData items
185  */
186 static int
187 itemptr_comparator(const void *a, const void *b)
188 {
189         const ItemPointerData *ipa = (const ItemPointerData *) a;
190         const ItemPointerData *ipb = (const ItemPointerData *) b;
191         BlockNumber     ba = ItemPointerGetBlockNumber(ipa);
192         BlockNumber     bb = ItemPointerGetBlockNumber(ipb);
193         OffsetNumber oa = ItemPointerGetOffsetNumber(ipa);
194         OffsetNumber ob = ItemPointerGetOffsetNumber(ipb);
195
196         if (ba < bb)
197                 return -1;
198         if (ba > bb)
199                 return 1;
200         if (oa < ob)
201                 return -1;
202         if (oa > ob)
203                 return 1;
204         return 0;
205 }
206
207 /* ----------------------------------------------------------------
208  *              TidNext
209  *
210  *              Retrieve a tuple from the TidScan node's currentRelation
211  *              using the tids in the TidScanState information.
212  *
213  * ----------------------------------------------------------------
214  */
215 static TupleTableSlot *
216 TidNext(TidScanState *node)
217 {
218         EState     *estate;
219         ScanDirection direction;
220         Snapshot        snapshot;
221         Relation        heapRelation;
222         HeapTuple       tuple;
223         TupleTableSlot *slot;
224         Index           scanrelid;
225         Buffer          buffer = InvalidBuffer;
226         ItemPointerData *tidList;
227         int                     numTids;
228         bool            bBackward;
229
230         /*
231          * extract necessary information from tid scan node
232          */
233         estate = node->ss.ps.state;
234         direction = estate->es_direction;
235         snapshot = estate->es_snapshot;
236         heapRelation = node->ss.ss_currentRelation;
237         slot = node->ss.ss_ScanTupleSlot;
238         scanrelid = ((TidScan *) node->ss.ps.plan)->scan.scanrelid;
239
240         /*
241          * Check if we are evaluating PlanQual for tuple of this relation.
242          * Additional checking is not good, but no other way for now. We could
243          * introduce new nodes for this case and handle TidScan --> NewNode
244          * switching in Init/ReScan plan...
245          */
246         if (estate->es_evTuple != NULL &&
247                 estate->es_evTuple[scanrelid - 1] != NULL)
248         {
249                 if (estate->es_evTupleNull[scanrelid - 1])
250                         return ExecClearTuple(slot);
251
252                 /*
253                  * XXX shouldn't we check here to make sure tuple matches TID list? In
254                  * runtime-key case this is not certain, is it?
255                  */
256
257                 ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
258                                            slot, InvalidBuffer, false);
259
260                 /* Flag for the next call that no more tuples */
261                 estate->es_evTupleNull[scanrelid - 1] = true;
262                 return slot;
263         }
264
265         /*
266          * First time through, compute the list of TIDs to be visited
267          */
268         if (node->tss_TidList == NULL)
269                 TidListCreate(node);
270
271         tidList = node->tss_TidList;
272         numTids = node->tss_NumTids;
273
274         tuple = &(node->tss_htup);
275
276         /*
277          * Initialize or advance scan position, depending on direction.
278          */
279         bBackward = ScanDirectionIsBackward(direction);
280         if (bBackward)
281         {
282                 if (node->tss_TidPtr < 0)
283                 {
284                         /* initialize for backward scan */
285                         node->tss_TidPtr = numTids - 1;
286                 }
287                 else
288                         node->tss_TidPtr--;
289         }
290         else
291         {
292                 if (node->tss_TidPtr < 0)
293                 {
294                         /* initialize for forward scan */
295                         node->tss_TidPtr = 0;
296                 }
297                 else
298                         node->tss_TidPtr++;
299         }
300
301         while (node->tss_TidPtr >= 0 && node->tss_TidPtr < numTids)
302         {
303                 tuple->t_self = tidList[node->tss_TidPtr];
304                 if (heap_fetch(heapRelation, snapshot, tuple, &buffer, false, NULL))
305                 {
306                         /*
307                          * store the scanned tuple in the scan tuple slot of the scan
308                          * state.  Eventually we will only do this and not return a tuple.
309                          * Note: we pass 'false' because tuples returned by amgetnext are
310                          * pointers onto disk pages and were not created with palloc() and
311                          * so should not be pfree()'d.
312                          */
313                         ExecStoreTuple(tuple,           /* tuple to store */
314                                                    slot,        /* slot to store in */
315                                                    buffer,              /* buffer associated with tuple  */
316                                                    false);              /* don't pfree */
317
318                         /*
319                          * At this point we have an extra pin on the buffer, because
320                          * ExecStoreTuple incremented the pin count. Drop our local pin.
321                          */
322                         ReleaseBuffer(buffer);
323
324                         return slot;
325                 }
326                 /* Bad TID or failed snapshot qual; try next */
327                 if (bBackward)
328                         node->tss_TidPtr--;
329                 else
330                         node->tss_TidPtr++;
331         }
332
333         /*
334          * if we get here it means the tid scan failed so we are at the end of the
335          * scan..
336          */
337         return ExecClearTuple(slot);
338 }
339
340 /* ----------------------------------------------------------------
341  *              ExecTidScan(node)
342  *
343  *              Scans the relation using tids and returns
344  *                 the next qualifying tuple in the direction specified.
345  *              It calls ExecScan() and passes it the access methods which returns
346  *              the next tuple using the tids.
347  *
348  *              Conditions:
349  *                -- the "cursor" maintained by the AMI is positioned at the tuple
350  *                       returned previously.
351  *
352  *              Initial States:
353  *                -- the relation indicated is opened for scanning so that the
354  *                       "cursor" is positioned before the first qualifying tuple.
355  *                -- tidPtr is -1.
356  * ----------------------------------------------------------------
357  */
358 TupleTableSlot *
359 ExecTidScan(TidScanState *node)
360 {
361         /*
362          * use TidNext as access method
363          */
364         return ExecScan(&node->ss, (ExecScanAccessMtd) TidNext);
365 }
366
367 /* ----------------------------------------------------------------
368  *              ExecTidReScan(node)
369  * ----------------------------------------------------------------
370  */
371 void
372 ExecTidReScan(TidScanState *node, ExprContext *exprCtxt)
373 {
374         EState     *estate;
375         Index           scanrelid;
376
377         estate = node->ss.ps.state;
378         scanrelid = ((TidScan *) node->ss.ps.plan)->scan.scanrelid;
379
380         /* If we are being passed an outer tuple, save it for runtime key calc */
381         if (exprCtxt != NULL)
382                 node->ss.ps.ps_ExprContext->ecxt_outertuple =
383                         exprCtxt->ecxt_outertuple;
384
385         /* If this is re-scanning of PlanQual ... */
386         if (estate->es_evTuple != NULL &&
387                 estate->es_evTuple[scanrelid - 1] != NULL)
388         {
389                 estate->es_evTupleNull[scanrelid - 1] = false;
390                 return;
391         }
392
393         if (node->tss_TidList)
394                 pfree(node->tss_TidList);
395         node->tss_TidList = NULL;
396         node->tss_NumTids = 0;
397         node->tss_TidPtr = -1;
398 }
399
400 /* ----------------------------------------------------------------
401  *              ExecEndTidScan
402  *
403  *              Releases any storage allocated through C routines.
404  *              Returns nothing.
405  * ----------------------------------------------------------------
406  */
407 void
408 ExecEndTidScan(TidScanState *node)
409 {
410         /*
411          * Free the exprcontext
412          */
413         ExecFreeExprContext(&node->ss.ps);
414
415         /*
416          * clear out tuple table slots
417          */
418         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
419         ExecClearTuple(node->ss.ss_ScanTupleSlot);
420
421         /*
422          * close the heap relation.
423          */
424         ExecCloseScanRelation(node->ss.ss_currentRelation);
425 }
426
427 /* ----------------------------------------------------------------
428  *              ExecTidMarkPos
429  *
430  *              Marks scan position by marking the current tid.
431  *              Returns nothing.
432  * ----------------------------------------------------------------
433  */
434 void
435 ExecTidMarkPos(TidScanState *node)
436 {
437         node->tss_MarkTidPtr = node->tss_TidPtr;
438 }
439
440 /* ----------------------------------------------------------------
441  *              ExecTidRestrPos
442  *
443  *              Restores scan position by restoring the current tid.
444  *              Returns nothing.
445  *
446  *              XXX Assumes previously marked scan position belongs to current tid
447  * ----------------------------------------------------------------
448  */
449 void
450 ExecTidRestrPos(TidScanState *node)
451 {
452         node->tss_TidPtr = node->tss_MarkTidPtr;
453 }
454
455 /* ----------------------------------------------------------------
456  *              ExecInitTidScan
457  *
458  *              Initializes the tid scan's state information, creates
459  *              scan keys, and opens the base and tid relations.
460  *
461  *              Parameters:
462  *                node: TidNode node produced by the planner.
463  *                estate: the execution state initialized in InitPlan.
464  * ----------------------------------------------------------------
465  */
466 TidScanState *
467 ExecInitTidScan(TidScan *node, EState *estate, int eflags)
468 {
469         TidScanState *tidstate;
470         Relation        currentRelation;
471
472         /*
473          * create state structure
474          */
475         tidstate = makeNode(TidScanState);
476         tidstate->ss.ps.plan = (Plan *) node;
477         tidstate->ss.ps.state = estate;
478
479         /*
480          * Miscellaneous initialization
481          *
482          * create expression context for node
483          */
484         ExecAssignExprContext(estate, &tidstate->ss.ps);
485
486         /*
487          * initialize child expressions
488          */
489         tidstate->ss.ps.targetlist = (List *)
490                 ExecInitExpr((Expr *) node->scan.plan.targetlist,
491                                          (PlanState *) tidstate);
492         tidstate->ss.ps.qual = (List *)
493                 ExecInitExpr((Expr *) node->scan.plan.qual,
494                                          (PlanState *) tidstate);
495
496         tidstate->tss_tidquals = (List *)
497                 ExecInitExpr((Expr *) node->tidquals,
498                                          (PlanState *) tidstate);
499
500 #define TIDSCAN_NSLOTS 2
501
502         /*
503          * tuple table initialization
504          */
505         ExecInitResultTupleSlot(estate, &tidstate->ss.ps);
506         ExecInitScanTupleSlot(estate, &tidstate->ss);
507
508         /*
509          * mark tid list as not computed yet
510          */
511         tidstate->tss_TidList = NULL;
512         tidstate->tss_NumTids = 0;
513         tidstate->tss_TidPtr = -1;
514
515         /*
516          * open the base relation and acquire appropriate lock on it.
517          */
518         currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid);
519
520         tidstate->ss.ss_currentRelation = currentRelation;
521         tidstate->ss.ss_currentScanDesc = NULL;         /* no heap scan here */
522
523         /*
524          * get the scan type from the relation descriptor.
525          */
526         ExecAssignScanType(&tidstate->ss, RelationGetDescr(currentRelation));
527
528         /*
529          * Initialize result tuple type and projection info.
530          */
531         ExecAssignResultTypeFromTL(&tidstate->ss.ps);
532         ExecAssignScanProjectionInfo(&tidstate->ss);
533
534         /*
535          * all done.
536          */
537         return tidstate;
538 }
539
540 int
541 ExecCountSlotsTidScan(TidScan *node)
542 {
543         return ExecCountSlotsNode(outerPlan((Plan *) node)) +
544                 ExecCountSlotsNode(innerPlan((Plan *) node)) + TIDSCAN_NSLOTS;
545 }