1 /*-------------------------------------------------------------------------
4 * Routines to support direct tid scans of relations
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.15 2001/03/22 03:59:29 momjian Exp $
13 *-------------------------------------------------------------------------
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.
27 #include "executor/execdebug.h"
28 #include "executor/nodeTidscan.h"
29 #include "access/heapam.h"
30 #include "parser/parsetree.h"
32 static int TidListCreate(List *, ExprContext *, ItemPointer *);
33 static TupleTableSlot *TidNext(TidScan *node);
36 TidListCreate(List *evalList, ExprContext *econtext, ItemPointer *tidList)
43 foreach(lst, evalList)
45 itemptr = (ItemPointer)
46 DatumGetPointer(ExecEvalExprSwitchContext(lfirst(lst),
50 if (!isNull && itemptr && ItemPointerIsValid(itemptr))
52 tidList[numTids] = itemptr;
59 /* ----------------------------------------------------------------
62 * Retrieve a tuple from the TidScan node's currentRelation
63 * using the tids in the TidScanState information.
65 * ----------------------------------------------------------------
67 static TupleTableSlot *
68 TidNext(TidScan *node)
71 CommonScanState *scanstate;
72 TidScanState *tidstate;
73 ScanDirection direction;
75 Relation heapRelation;
78 Buffer buffer = InvalidBuffer;
87 * extract necessary information from tid scan node
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;
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...
106 if (estate->es_evTuple != NULL &&
107 estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
109 ExecClearTuple(slot);
110 if (estate->es_evTupleNull[node->scan.scanrelid - 1])
111 return slot; /* return empty slot */
113 ExecStoreTuple(estate->es_evTuple[node->scan.scanrelid - 1],
114 slot, InvalidBuffer, false);
116 /* Flag for the next call that no more tuples */
117 estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
121 tuple = &(tidstate->tss_htup);
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.
129 bBackward = ScanDirectionIsBackward(direction);
132 tidNumber = numTids - tidstate->tss_TidPtr - 1;
136 tidstate->tss_TidPtr = numTids - 1;
141 if ((tidNumber = tidstate->tss_TidPtr) < 0)
144 tidstate->tss_TidPtr = 0;
147 while (tidNumber < numTids)
149 bool slot_is_valid = false;
151 itemptr = tidList[tidstate->tss_TidPtr];
152 tuple->t_datamcxt = NULL;
153 tuple->t_data = NULL;
156 tuple->t_self = *(itemptr);
157 heap_fetch(heapRelation, snapshot, tuple, &buffer);
159 if (tuple->t_data != NULL)
161 bool prev_matches = false;
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.
172 ExecStoreTuple(tuple, /* tuple to store */
173 slot,/* slot to store in */
174 buffer, /* buffer associated with tuple */
175 false); /* don't pfree */
178 * At this point we have an extra pin on the buffer, because
179 * ExecStoreTuple incremented the pin count. Drop our local
182 ReleaseBuffer(buffer);
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.
190 for (prev_tid = 0; prev_tid < tidstate->tss_TidPtr;
193 if (ItemPointerEquals(tidList[prev_tid], &tuple->t_self))
200 slot_is_valid = true;
202 ExecClearTuple(slot);
204 else if (BufferIsValid(buffer))
205 ReleaseBuffer(buffer);
208 tidstate->tss_TidPtr--;
210 tidstate->tss_TidPtr++;
215 * if we get here it means the tid scan failed so we
216 * are at the end of the scan..
219 return ExecClearTuple(slot);
222 /* ----------------------------------------------------------------
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.
231 * -- the "cursor" maintained by the AMI is positioned at the tuple
232 * returned previously.
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 * ----------------------------------------------------------------
242 ExecTidScan(TidScan *node)
245 * use TidNext as access method
248 return ExecScan(&node->scan, (ExecScanAccessMtd) TidNext);
251 /* ----------------------------------------------------------------
252 * ExecTidReScan(node)
253 * ----------------------------------------------------------------
256 ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
259 TidScanState *tidstate;
260 ItemPointer *tidList;
262 tidstate = node->tidstate;
263 estate = node->scan.plan.state;
264 tidstate->tss_TidPtr = -1;
265 tidList = tidstate->tss_TidList;
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;
272 /* If this is re-scanning of PlanQual ... */
273 if (estate->es_evTuple != NULL &&
274 estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
276 estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
280 tidstate->tss_NumTids = TidListCreate(node->tideval,
281 node->scan.scanstate->cstate.cs_ExprContext,
285 * perhaps return something meaningful
291 /* ----------------------------------------------------------------
294 * Releases any storage allocated through C routines.
296 * ----------------------------------------------------------------
299 ExecEndTidScan(TidScan *node)
301 CommonScanState *scanstate;
302 TidScanState *tidstate;
304 scanstate = node->scan.scanstate;
305 tidstate = node->tidstate;
306 if (tidstate && tidstate->tss_TidList)
307 pfree(tidstate->tss_TidList);
310 * extract information from the node
315 * Free the projection info and the scan attribute info
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
323 ExecFreeProjectionInfo(&scanstate->cstate);
324 ExecFreeExprContext(&scanstate->cstate);
327 * close the heap and tid relations
330 ExecCloseR((Plan *) node);
333 * clear out tuple table slots
336 ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
337 ExecClearTuple(scanstate->css_ScanTupleSlot);
340 /* ----------------------------------------------------------------
343 * Marks scan position by marking the current tid.
345 * ----------------------------------------------------------------
348 ExecTidMarkPos(TidScan *node)
350 TidScanState *tidstate;
352 tidstate = node->tidstate;
353 tidstate->tss_MarkTidPtr = tidstate->tss_TidPtr;
357 /* ----------------------------------------------------------------
360 * Restores scan position by restoring the current tid.
363 * XXX Assumes previously marked scan position belongs to current tid
364 * ----------------------------------------------------------------
367 ExecTidRestrPos(TidScan *node)
369 TidScanState *tidstate;
371 tidstate = node->tidstate;
372 tidstate->tss_TidPtr = tidstate->tss_MarkTidPtr;
377 /* ----------------------------------------------------------------
380 * Initializes the tid scan's state information, creates
381 * scan keys, and opens the base and tid relations.
384 * node: TidNode node produced by the planner.
385 * estate: the execution state initialized in InitPlan.
386 * ----------------------------------------------------------------
389 ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
391 TidScanState *tidstate;
392 CommonScanState *scanstate;
393 ItemPointer *tidList;
397 RangeTblEntry *rtentry;
400 Relation currentRelation;
401 List *execParam = NIL;
404 * assign execution state to node
407 node->scan.plan.state = estate;
409 /* --------------------------------
410 * Part 1) initialize scan state
412 * create new CommonScanState for node
413 * --------------------------------
415 scanstate = makeNode(CommonScanState);
416 node->scan.scanstate = scanstate;
419 * Miscellaneous initialization
421 * + create expression context for node
424 ExecAssignExprContext(estate, &scanstate->cstate);
426 #define TIDSCAN_NSLOTS 3
428 * tuple table initialization
431 ExecInitResultTupleSlot(estate, &scanstate->cstate);
432 ExecInitScanTupleSlot(estate, scanstate);
435 * initialize projection info. result type comes from scan desc
439 ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
441 /* --------------------------------
442 * Part 2) initialize tid scan state
444 * create new TidScanState for node
445 * --------------------------------
447 tidstate = makeNode(TidScanState);
448 node->tidstate = tidstate;
451 * get the tid node information
454 tidList = (ItemPointer *) palloc(length(node->tideval) * sizeof(ItemPointer));
456 if (!node->needRescan)
457 numTids = TidListCreate(node->tideval, scanstate->cstate.cs_ExprContext, tidList);
460 CXT1_printf("ExecInitTidScan: context is %d\n", CurrentMemoryContext);
462 tidstate->tss_NumTids = numTids;
463 tidstate->tss_TidPtr = tidPtr;
464 tidstate->tss_TidList = tidList;
467 * get the range table and direction information
468 * from the execution state (these are needed to
469 * open the relations).
472 rangeTable = estate->es_range_table;
475 * open the base relation
478 relid = node->scan.scanrelid;
479 rtentry = rt_fetch(relid, rangeTable);
480 reloid = rtentry->relid;
482 currentRelation = heap_open(reloid, AccessShareLock);
483 scanstate->css_currentRelation = currentRelation;
484 scanstate->css_currentScanDesc = 0;
487 * get the scan type from the relation descriptor.
490 ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
491 ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
494 * if there are some PARAM_EXEC in skankeys then force tid rescan on
497 ((Plan *) node)->chgParam = execParam;
507 ExecCountSlotsTidScan(TidScan *node)
509 return ExecCountSlotsNode(outerPlan((Plan *) node)) +
510 ExecCountSlotsNode(innerPlan((Plan *) node)) + TIDSCAN_NSLOTS;