1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-19 04:21:08 +03:00

Add support for index-only scans in GiST.

This adds a new GiST opclass method, 'fetch', which is used to reconstruct
the original Datum from the value stored in the index. Also, the 'canreturn'
index AM interface function gains a new 'attno' argument. That makes it
possible to use index-only scans on a multi-column index where some of the
opclasses support index-only scans but some do not.

This patch adds support in the box and point opclasses. Other opclasses
can added later as follow-on patches (btree_gist would be particularly
interesting).

Anastasia Lubennikova, with additional fixes and modifications by me.
This commit is contained in:
Heikki Linnakangas
2015-03-26 19:12:00 +02:00
parent 8fa393a6d7
commit d04c8ed904
24 changed files with 575 additions and 73 deletions

View File

@ -228,7 +228,9 @@ gistindex_keytest(IndexScanDesc scan,
* tuples should be reported directly into the bitmap. If they are NULL,
* we're doing a plain or ordered indexscan. For a plain indexscan, heap
* tuple TIDs are returned into so->pageData[]. For an ordered indexscan,
* heap tuple TIDs are pushed into individual search queue items.
* heap tuple TIDs are pushed into individual search queue items. In an
* index-only scan, reconstructed index tuples are returned along with the
* TIDs.
*
* If we detect that the index page has split since we saw its downlink
* in the parent, we push its new right sibling onto the queue so the
@ -239,6 +241,8 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
TIDBitmap *tbm, int64 *ntids)
{
GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
GISTSTATE *giststate = so->giststate;
Relation r = scan->indexRelation;
Buffer buffer;
Page page;
GISTPageOpaque opaque;
@ -288,6 +292,8 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
}
so->nPageData = so->curPageData = 0;
if (so->pageDataCxt)
MemoryContextReset(so->pageDataCxt);
/*
* check all tuples on page
@ -326,10 +332,21 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
else if (scan->numberOfOrderBys == 0 && GistPageIsLeaf(page))
{
/*
* Non-ordered scan, so report heap tuples in so->pageData[]
* Non-ordered scan, so report tuples in so->pageData[]
*/
so->pageData[so->nPageData].heapPtr = it->t_tid;
so->pageData[so->nPageData].recheck = recheck;
/*
* In an index-only scan, also fetch the data from the tuple.
*/
if (scan->xs_want_itup)
{
oldcxt = MemoryContextSwitchTo(so->pageDataCxt);
so->pageData[so->nPageData].ftup =
gistFetchTuple(giststate, r, it);
MemoryContextSwitchTo(oldcxt);
}
so->nPageData++;
}
else
@ -352,6 +369,12 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
item->blkno = InvalidBlockNumber;
item->data.heap.heapPtr = it->t_tid;
item->data.heap.recheck = recheck;
/*
* In an index-only scan, also fetch the data from the tuple.
*/
if (scan->xs_want_itup)
item->data.heap.ftup = gistFetchTuple(giststate, r, it);
}
else
{
@ -412,6 +435,13 @@ getNextNearest(IndexScanDesc scan)
GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
bool res = false;
if (scan->xs_itup)
{
/* free previously returned tuple */
pfree(scan->xs_itup);
scan->xs_itup = NULL;
}
do
{
GISTSearchItem *item = getNextGISTSearchItem(so);
@ -424,6 +454,10 @@ getNextNearest(IndexScanDesc scan)
/* found a heap item at currently minimal distance */
scan->xs_ctup.t_self = item->data.heap.heapPtr;
scan->xs_recheck = item->data.heap.recheck;
/* in an index-only scan, also return the reconstructed tuple. */
if (scan->xs_want_itup)
scan->xs_itup = item->data.heap.ftup;
res = true;
}
else
@ -465,6 +499,8 @@ gistgettuple(PG_FUNCTION_ARGS)
so->firstCall = false;
so->curPageData = so->nPageData = 0;
if (so->pageDataCxt)
MemoryContextReset(so->pageDataCxt);
fakeItem.blkno = GIST_ROOT_BLKNO;
memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
@ -483,10 +519,17 @@ gistgettuple(PG_FUNCTION_ARGS)
{
if (so->curPageData < so->nPageData)
{
/* continuing to return tuples from a leaf page */
scan->xs_ctup.t_self = so->pageData[so->curPageData].heapPtr;
scan->xs_recheck = so->pageData[so->curPageData].recheck;
/* in an index-only scan, also return the reconstructed tuple */
if (scan->xs_want_itup)
scan->xs_itup = so->pageData[so->curPageData].ftup;
so->curPageData++;
PG_RETURN_BOOL(true);
}
@ -533,6 +576,8 @@ gistgetbitmap(PG_FUNCTION_ARGS)
/* Begin the scan by processing the root page */
so->curPageData = so->nPageData = 0;
if (so->pageDataCxt)
MemoryContextReset(so->pageDataCxt);
fakeItem.blkno = GIST_ROOT_BLKNO;
memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
@ -558,3 +603,20 @@ gistgetbitmap(PG_FUNCTION_ARGS)
PG_RETURN_INT64(ntids);
}
/*
* Can we do index-only scans on the given index column?
*
* Opclasses that implement a fetch function support index-only scans.
*/
Datum
gistcanreturn(PG_FUNCTION_ARGS)
{
Relation index = (Relation) PG_GETARG_POINTER(0);
int attno = PG_GETARG_INT32(1);
if (OidIsValid(index_getprocid(index, attno, GIST_FETCH_PROC)))
PG_RETURN_BOOL(true);
else
PG_RETURN_BOOL(false);
}