Add support for user-defined I/O conversion casts.
[PostgreSQL.git] / src / backend / executor / nodeBitmapHeapscan.c
blob64a598da2bf4897d9ac5f2f6a04a1f4fa9a11e4f
1 /*-------------------------------------------------------------------------
3 * nodeBitmapHeapscan.c
4 * Routines to support bitmapped scans of relations
6 * NOTE: it is critical that this plan type only be used with MVCC-compliant
7 * snapshots (ie, regular snapshots, not SnapshotNow or one of the other
8 * special snapshots). The reason is that since index and heap scans are
9 * decoupled, there can be no assurance that the index tuple prompting a
10 * visit to a particular heap TID still exists when the visit is made.
11 * Therefore the tuple might not exist anymore either (which is OK because
12 * heap_fetch will cope) --- but worse, the tuple slot could have been
13 * re-used for a newer tuple. With an MVCC snapshot the newer tuple is
14 * certain to fail the time qual and so it will not be mistakenly returned.
15 * With SnapshotNow we might return a tuple that doesn't meet the required
16 * index qual conditions.
19 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
20 * Portions Copyright (c) 1994, Regents of the University of California
23 * IDENTIFICATION
24 * $PostgreSQL$
26 *-------------------------------------------------------------------------
29 * INTERFACE ROUTINES
30 * ExecBitmapHeapScan scans a relation using bitmap info
31 * ExecBitmapHeapNext workhorse for above
32 * ExecInitBitmapHeapScan creates and initializes state info.
33 * ExecBitmapHeapReScan prepares to rescan the plan.
34 * ExecEndBitmapHeapScan releases all storage.
36 #include "postgres.h"
38 #include "access/heapam.h"
39 #include "access/relscan.h"
40 #include "access/transam.h"
41 #include "executor/execdebug.h"
42 #include "executor/nodeBitmapHeapscan.h"
43 #include "pgstat.h"
44 #include "storage/bufmgr.h"
45 #include "utils/memutils.h"
46 #include "utils/snapmgr.h"
47 #include "utils/tqual.h"
50 static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node);
51 static void bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres);
54 /* ----------------------------------------------------------------
55 * BitmapHeapNext
57 * Retrieve next tuple from the BitmapHeapScan node's currentRelation
58 * ----------------------------------------------------------------
60 static TupleTableSlot *
61 BitmapHeapNext(BitmapHeapScanState *node)
63 EState *estate;
64 ExprContext *econtext;
65 HeapScanDesc scan;
66 Index scanrelid;
67 TIDBitmap *tbm;
68 TBMIterateResult *tbmres;
69 OffsetNumber targoffset;
70 TupleTableSlot *slot;
73 * extract necessary information from index scan node
75 estate = node->ss.ps.state;
76 econtext = node->ss.ps.ps_ExprContext;
77 slot = node->ss.ss_ScanTupleSlot;
78 scan = node->ss.ss_currentScanDesc;
79 scanrelid = ((BitmapHeapScan *) node->ss.ps.plan)->scan.scanrelid;
80 tbm = node->tbm;
81 tbmres = node->tbmres;
84 * Check if we are evaluating PlanQual for tuple of this relation.
85 * Additional checking is not good, but no other way for now. We could
86 * introduce new nodes for this case and handle IndexScan --> NewNode
87 * switching in Init/ReScan plan...
89 if (estate->es_evTuple != NULL &&
90 estate->es_evTuple[scanrelid - 1] != NULL)
92 if (estate->es_evTupleNull[scanrelid - 1])
93 return ExecClearTuple(slot);
95 ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
96 slot, InvalidBuffer, false);
98 /* Does the tuple meet the original qual conditions? */
99 econtext->ecxt_scantuple = slot;
101 ResetExprContext(econtext);
103 if (!ExecQual(node->bitmapqualorig, econtext, false))
104 ExecClearTuple(slot); /* would not be returned by scan */
106 /* Flag for the next call that no more tuples */
107 estate->es_evTupleNull[scanrelid - 1] = true;
109 return slot;
113 * If we haven't yet performed the underlying index scan, do it, and
114 * prepare the bitmap to be iterated over.
116 if (tbm == NULL)
118 tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
120 if (!tbm || !IsA(tbm, TIDBitmap))
121 elog(ERROR, "unrecognized result from subplan");
123 node->tbm = tbm;
124 node->tbmres = tbmres = NULL;
126 tbm_begin_iterate(tbm);
129 for (;;)
131 Page dp;
132 ItemId lp;
135 * Get next page of results if needed
137 if (tbmres == NULL)
139 node->tbmres = tbmres = tbm_iterate(tbm);
140 if (tbmres == NULL)
142 /* no more entries in the bitmap */
143 break;
147 * Ignore any claimed entries past what we think is the end of the
148 * relation. (This is probably not necessary given that we got at
149 * least AccessShareLock on the table before performing any of the
150 * indexscans, but let's be safe.)
152 if (tbmres->blockno >= scan->rs_nblocks)
154 node->tbmres = tbmres = NULL;
155 continue;
159 * Fetch the current heap page and identify candidate tuples.
161 bitgetpage(scan, tbmres);
164 * Set rs_cindex to first slot to examine
166 scan->rs_cindex = 0;
168 else
171 * Continuing in previously obtained page; advance rs_cindex
173 scan->rs_cindex++;
177 * Out of range? If so, nothing more to look at on this page
179 if (scan->rs_cindex < 0 || scan->rs_cindex >= scan->rs_ntuples)
181 node->tbmres = tbmres = NULL;
182 continue;
186 * Okay to fetch the tuple
188 targoffset = scan->rs_vistuples[scan->rs_cindex];
189 dp = (Page) BufferGetPage(scan->rs_cbuf);
190 lp = PageGetItemId(dp, targoffset);
191 Assert(ItemIdIsNormal(lp));
193 scan->rs_ctup.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
194 scan->rs_ctup.t_len = ItemIdGetLength(lp);
195 ItemPointerSet(&scan->rs_ctup.t_self, tbmres->blockno, targoffset);
197 pgstat_count_heap_fetch(scan->rs_rd);
200 * Set up the result slot to point to this tuple. Note that the slot
201 * acquires a pin on the buffer.
203 ExecStoreTuple(&scan->rs_ctup,
204 slot,
205 scan->rs_cbuf,
206 false);
209 * If we are using lossy info, we have to recheck the qual conditions
210 * at every tuple.
212 if (tbmres->recheck)
214 econtext->ecxt_scantuple = slot;
215 ResetExprContext(econtext);
217 if (!ExecQual(node->bitmapqualorig, econtext, false))
219 /* Fails recheck, so drop it and loop back for another */
220 ExecClearTuple(slot);
221 continue;
225 /* OK to return this tuple */
226 return slot;
230 * if we get here it means we are at the end of the scan..
232 return ExecClearTuple(slot);
236 * bitgetpage - subroutine for BitmapHeapNext()
238 * This routine reads and pins the specified page of the relation, then
239 * builds an array indicating which tuples on the page are both potentially
240 * interesting according to the bitmap, and visible according to the snapshot.
242 static void
243 bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres)
245 BlockNumber page = tbmres->blockno;
246 Buffer buffer;
247 Snapshot snapshot;
248 int ntup;
251 * Acquire pin on the target heap page, trading in any pin we held before.
253 Assert(page < scan->rs_nblocks);
255 scan->rs_cbuf = ReleaseAndReadBuffer(scan->rs_cbuf,
256 scan->rs_rd,
257 page);
258 buffer = scan->rs_cbuf;
259 snapshot = scan->rs_snapshot;
261 ntup = 0;
264 * Prune and repair fragmentation for the whole page, if possible.
266 Assert(TransactionIdIsValid(RecentGlobalXmin));
267 heap_page_prune_opt(scan->rs_rd, buffer, RecentGlobalXmin);
270 * We must hold share lock on the buffer content while examining tuple
271 * visibility. Afterwards, however, the tuples we have found to be
272 * visible are guaranteed good as long as we hold the buffer pin.
274 LockBuffer(buffer, BUFFER_LOCK_SHARE);
277 * We need two separate strategies for lossy and non-lossy cases.
279 if (tbmres->ntuples >= 0)
282 * Bitmap is non-lossy, so we just look through the offsets listed in
283 * tbmres; but we have to follow any HOT chain starting at each such
284 * offset.
286 int curslot;
288 for (curslot = 0; curslot < tbmres->ntuples; curslot++)
290 OffsetNumber offnum = tbmres->offsets[curslot];
291 ItemPointerData tid;
293 ItemPointerSet(&tid, page, offnum);
294 if (heap_hot_search_buffer(&tid, buffer, snapshot, NULL))
295 scan->rs_vistuples[ntup++] = ItemPointerGetOffsetNumber(&tid);
298 else
301 * Bitmap is lossy, so we must examine each item pointer on the page.
302 * But we can ignore HOT chains, since we'll check each tuple anyway.
304 Page dp = (Page) BufferGetPage(buffer);
305 OffsetNumber maxoff = PageGetMaxOffsetNumber(dp);
306 OffsetNumber offnum;
308 for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum))
310 ItemId lp;
311 HeapTupleData loctup;
313 lp = PageGetItemId(dp, offnum);
314 if (!ItemIdIsNormal(lp))
315 continue;
316 loctup.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
317 loctup.t_len = ItemIdGetLength(lp);
318 if (HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer))
319 scan->rs_vistuples[ntup++] = offnum;
323 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
325 Assert(ntup <= MaxHeapTuplesPerPage);
326 scan->rs_ntuples = ntup;
329 /* ----------------------------------------------------------------
330 * ExecBitmapHeapScan(node)
331 * ----------------------------------------------------------------
333 TupleTableSlot *
334 ExecBitmapHeapScan(BitmapHeapScanState *node)
337 * use BitmapHeapNext as access method
339 return ExecScan(&node->ss, (ExecScanAccessMtd) BitmapHeapNext);
342 /* ----------------------------------------------------------------
343 * ExecBitmapHeapReScan(node)
344 * ----------------------------------------------------------------
346 void
347 ExecBitmapHeapReScan(BitmapHeapScanState *node, ExprContext *exprCtxt)
349 EState *estate;
350 Index scanrelid;
352 estate = node->ss.ps.state;
353 scanrelid = ((BitmapHeapScan *) node->ss.ps.plan)->scan.scanrelid;
355 node->ss.ps.ps_TupFromTlist = false;
358 * If we are being passed an outer tuple, link it into the "regular"
359 * per-tuple econtext for possible qual eval.
361 if (exprCtxt != NULL)
363 ExprContext *stdecontext;
365 stdecontext = node->ss.ps.ps_ExprContext;
366 stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
369 /* If this is re-scanning of PlanQual ... */
370 if (estate->es_evTuple != NULL &&
371 estate->es_evTuple[scanrelid - 1] != NULL)
373 estate->es_evTupleNull[scanrelid - 1] = false;
376 /* rescan to release any page pin */
377 heap_rescan(node->ss.ss_currentScanDesc, NULL);
379 if (node->tbm)
380 tbm_free(node->tbm);
381 node->tbm = NULL;
382 node->tbmres = NULL;
385 * Always rescan the input immediately, to ensure we can pass down any
386 * outer tuple that might be used in index quals.
388 ExecReScan(outerPlanState(node), exprCtxt);
391 /* ----------------------------------------------------------------
392 * ExecEndBitmapHeapScan
393 * ----------------------------------------------------------------
395 void
396 ExecEndBitmapHeapScan(BitmapHeapScanState *node)
398 Relation relation;
399 HeapScanDesc scanDesc;
402 * extract information from the node
404 relation = node->ss.ss_currentRelation;
405 scanDesc = node->ss.ss_currentScanDesc;
408 * Free the exprcontext
410 ExecFreeExprContext(&node->ss.ps);
413 * clear out tuple table slots
415 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
416 ExecClearTuple(node->ss.ss_ScanTupleSlot);
419 * close down subplans
421 ExecEndNode(outerPlanState(node));
424 * release bitmap if any
426 if (node->tbm)
427 tbm_free(node->tbm);
430 * close heap scan
432 heap_endscan(scanDesc);
435 * close the heap relation.
437 ExecCloseScanRelation(relation);
440 /* ----------------------------------------------------------------
441 * ExecInitBitmapHeapScan
443 * Initializes the scan's state information.
444 * ----------------------------------------------------------------
446 BitmapHeapScanState *
447 ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
449 BitmapHeapScanState *scanstate;
450 Relation currentRelation;
452 /* check for unsupported flags */
453 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
456 * Assert caller didn't ask for an unsafe snapshot --- see comments at
457 * head of file.
459 Assert(IsMVCCSnapshot(estate->es_snapshot));
462 * create state structure
464 scanstate = makeNode(BitmapHeapScanState);
465 scanstate->ss.ps.plan = (Plan *) node;
466 scanstate->ss.ps.state = estate;
468 scanstate->tbm = NULL;
469 scanstate->tbmres = NULL;
472 * Miscellaneous initialization
474 * create expression context for node
476 ExecAssignExprContext(estate, &scanstate->ss.ps);
478 scanstate->ss.ps.ps_TupFromTlist = false;
481 * initialize child expressions
483 scanstate->ss.ps.targetlist = (List *)
484 ExecInitExpr((Expr *) node->scan.plan.targetlist,
485 (PlanState *) scanstate);
486 scanstate->ss.ps.qual = (List *)
487 ExecInitExpr((Expr *) node->scan.plan.qual,
488 (PlanState *) scanstate);
489 scanstate->bitmapqualorig = (List *)
490 ExecInitExpr((Expr *) node->bitmapqualorig,
491 (PlanState *) scanstate);
493 #define BITMAPHEAPSCAN_NSLOTS 2
496 * tuple table initialization
498 ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
499 ExecInitScanTupleSlot(estate, &scanstate->ss);
502 * open the base relation and acquire appropriate lock on it.
504 currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid);
506 scanstate->ss.ss_currentRelation = currentRelation;
509 * Even though we aren't going to do a conventional seqscan, it is useful
510 * to create a HeapScanDesc --- most of the fields in it are usable.
512 scanstate->ss.ss_currentScanDesc = heap_beginscan_bm(currentRelation,
513 estate->es_snapshot,
515 NULL);
518 * get the scan type from the relation descriptor.
520 ExecAssignScanType(&scanstate->ss, RelationGetDescr(currentRelation));
523 * Initialize result tuple type and projection info.
525 ExecAssignResultTypeFromTL(&scanstate->ss.ps);
526 ExecAssignScanProjectionInfo(&scanstate->ss);
529 * initialize child nodes
531 * We do this last because the child nodes will open indexscans on our
532 * relation's indexes, and we want to be sure we have acquired a lock on
533 * the relation first.
535 outerPlanState(scanstate) = ExecInitNode(outerPlan(node), estate, eflags);
538 * all done.
540 return scanstate;
544 ExecCountSlotsBitmapHeapScan(BitmapHeapScan *node)
546 return ExecCountSlotsNode(outerPlan((Plan *) node)) +
547 ExecCountSlotsNode(innerPlan((Plan *) node)) + BITMAPHEAPSCAN_NSLOTS;