aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/nbtree/nbtree.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/nbtree/nbtree.c')
-rw-r--r--src/backend/access/nbtree/nbtree.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 996611516fe..11b57659ee8 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -73,6 +73,7 @@ static void btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
BTCycleId cycleid);
static void btvacuumpage(BTVacState *vstate, BlockNumber blkno,
BlockNumber orig_blkno);
+static IndexTuple bt_getindextuple(IndexScanDesc scan);
/*
@@ -310,10 +311,95 @@ btgettuple(PG_FUNCTION_ARGS)
else
res = _bt_first(scan, dir);
+ /* Return the whole index tuple if requested */
+ if (scan->xs_want_itup)
+ {
+ /* First, free the last one ... */
+ if (scan->xs_itup != NULL)
+ {
+ pfree(scan->xs_itup);
+ scan->xs_itup = NULL;
+ }
+
+ if (res)
+ scan->xs_itup = bt_getindextuple(scan);
+ }
+
PG_RETURN_BOOL(res);
}
/*
+ * bt_getindextuple - fetch index tuple at current position.
+ *
+ * This can fail to find the tuple if new tuples have been inserted on the
+ * index page since we stepped onto the page. NULL is returned in that case.
+ * (We could try a bit harder by searching for the TID; but if insertions
+ * are happening, it's reasonably likely that an index-only scan will fail
+ * anyway because of visibility. So probably not worth the trouble.)
+ *
+ * The tuple returned is a palloc'd copy, so that we don't need to keep a
+ * lock on the index page.
+ *
+ * The caller must have pin on so->currPos.buf.
+ */
+static IndexTuple
+bt_getindextuple(IndexScanDesc scan)
+{
+ BTScanOpaque so = (BTScanOpaque) scan->opaque;
+ Page page;
+ BTPageOpaque opaque;
+ OffsetNumber minoff;
+ OffsetNumber maxoff;
+ int itemIndex;
+ OffsetNumber offnum;
+ IndexTuple ituple,
+ result;
+
+ Assert(BufferIsValid(so->currPos.buf));
+
+ LockBuffer(so->currPos.buf, BT_READ);
+
+ /* Locate the tuple, being paranoid about possibility the page changed */
+ page = BufferGetPage(so->currPos.buf);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ minoff = P_FIRSTDATAKEY(opaque);
+ maxoff = PageGetMaxOffsetNumber(page);
+
+ itemIndex = so->currPos.itemIndex;
+ /* pure paranoia */
+ Assert(itemIndex >= so->currPos.firstItem &&
+ itemIndex <= so->currPos.lastItem);
+
+ offnum = so->currPos.items[itemIndex].indexOffset;
+ if (offnum < minoff || offnum > maxoff)
+ {
+ /* should never happen, since we have pin on page, but be careful */
+ LockBuffer(so->currPos.buf, BUFFER_LOCK_UNLOCK);
+ return NULL;
+ }
+
+ ituple = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
+
+ if (ItemPointerEquals(&ituple->t_tid, &scan->xs_ctup.t_self))
+ {
+ /* yup, it's the desired tuple, so make a copy */
+ Size itupsz = IndexTupleSize(ituple);
+
+ result = palloc(itupsz);
+ memcpy(result, ituple, itupsz);
+ }
+ else
+ {
+ /* oops, it got moved */
+ result = NULL;
+ }
+
+ LockBuffer(so->currPos.buf, BUFFER_LOCK_UNLOCK);
+
+ return result;
+}
+
+/*
* btgetbitmap() -- gets all matching tuples, and adds them to a bitmap
*/
Datum
@@ -464,6 +550,12 @@ btendscan(PG_FUNCTION_ARGS)
pfree(so->keyData);
pfree(so);
+ if (scan->xs_itup != NULL)
+ {
+ pfree(scan->xs_itup);
+ scan->xs_itup = NULL;
+ }
+
PG_RETURN_VOID();
}