@@ -228,7 +228,9 @@ gistindex_keytest(IndexScanDesc scan,
228228 * tuples should be reported directly into the bitmap. If they are NULL,
229229 * we're doing a plain or ordered indexscan. For a plain indexscan, heap
230230 * tuple TIDs are returned into so->pageData[]. For an ordered indexscan,
231- * heap tuple TIDs are pushed into individual search queue items.
231+ * heap tuple TIDs are pushed into individual search queue items. In an
232+ * index-only scan, reconstructed index tuples are returned along with the
233+ * TIDs.
232234 *
233235 * If we detect that the index page has split since we saw its downlink
234236 * 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,
239241 TIDBitmap * tbm , int64 * ntids )
240242{
241243 GISTScanOpaque so = (GISTScanOpaque ) scan -> opaque ;
244+ GISTSTATE * giststate = so -> giststate ;
245+ Relation r = scan -> indexRelation ;
242246 Buffer buffer ;
243247 Page page ;
244248 GISTPageOpaque opaque ;
@@ -288,6 +292,8 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
288292 }
289293
290294 so -> nPageData = so -> curPageData = 0 ;
295+ if (so -> pageDataCxt )
296+ MemoryContextReset (so -> pageDataCxt );
291297
292298 /*
293299 * check all tuples on page
@@ -326,10 +332,21 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
326332 else if (scan -> numberOfOrderBys == 0 && GistPageIsLeaf (page ))
327333 {
328334 /*
329- * Non-ordered scan, so report heap tuples in so->pageData[]
335+ * Non-ordered scan, so report tuples in so->pageData[]
330336 */
331337 so -> pageData [so -> nPageData ].heapPtr = it -> t_tid ;
332338 so -> pageData [so -> nPageData ].recheck = recheck ;
339+
340+ /*
341+ * In an index-only scan, also fetch the data from the tuple.
342+ */
343+ if (scan -> xs_want_itup )
344+ {
345+ oldcxt = MemoryContextSwitchTo (so -> pageDataCxt );
346+ so -> pageData [so -> nPageData ].ftup =
347+ gistFetchTuple (giststate , r , it );
348+ MemoryContextSwitchTo (oldcxt );
349+ }
333350 so -> nPageData ++ ;
334351 }
335352 else
@@ -352,6 +369,12 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
352369 item -> blkno = InvalidBlockNumber ;
353370 item -> data .heap .heapPtr = it -> t_tid ;
354371 item -> data .heap .recheck = recheck ;
372+
373+ /*
374+ * In an index-only scan, also fetch the data from the tuple.
375+ */
376+ if (scan -> xs_want_itup )
377+ item -> data .heap .ftup = gistFetchTuple (giststate , r , it );
355378 }
356379 else
357380 {
@@ -412,6 +435,13 @@ getNextNearest(IndexScanDesc scan)
412435 GISTScanOpaque so = (GISTScanOpaque ) scan -> opaque ;
413436 bool res = false;
414437
438+ if (scan -> xs_itup )
439+ {
440+ /* free previously returned tuple */
441+ pfree (scan -> xs_itup );
442+ scan -> xs_itup = NULL ;
443+ }
444+
415445 do
416446 {
417447 GISTSearchItem * item = getNextGISTSearchItem (so );
@@ -424,6 +454,10 @@ getNextNearest(IndexScanDesc scan)
424454 /* found a heap item at currently minimal distance */
425455 scan -> xs_ctup .t_self = item -> data .heap .heapPtr ;
426456 scan -> xs_recheck = item -> data .heap .recheck ;
457+
458+ /* in an index-only scan, also return the reconstructed tuple. */
459+ if (scan -> xs_want_itup )
460+ scan -> xs_itup = item -> data .heap .ftup ;
427461 res = true;
428462 }
429463 else
@@ -465,6 +499,8 @@ gistgettuple(PG_FUNCTION_ARGS)
465499
466500 so -> firstCall = false;
467501 so -> curPageData = so -> nPageData = 0 ;
502+ if (so -> pageDataCxt )
503+ MemoryContextReset (so -> pageDataCxt );
468504
469505 fakeItem .blkno = GIST_ROOT_BLKNO ;
470506 memset (& fakeItem .data .parentlsn , 0 , sizeof (GistNSN ));
@@ -483,10 +519,17 @@ gistgettuple(PG_FUNCTION_ARGS)
483519 {
484520 if (so -> curPageData < so -> nPageData )
485521 {
522+
486523 /* continuing to return tuples from a leaf page */
487524 scan -> xs_ctup .t_self = so -> pageData [so -> curPageData ].heapPtr ;
488525 scan -> xs_recheck = so -> pageData [so -> curPageData ].recheck ;
526+
527+ /* in an index-only scan, also return the reconstructed tuple */
528+ if (scan -> xs_want_itup )
529+ scan -> xs_itup = so -> pageData [so -> curPageData ].ftup ;
530+
489531 so -> curPageData ++ ;
532+
490533 PG_RETURN_BOOL (true);
491534 }
492535
@@ -533,6 +576,8 @@ gistgetbitmap(PG_FUNCTION_ARGS)
533576
534577 /* Begin the scan by processing the root page */
535578 so -> curPageData = so -> nPageData = 0 ;
579+ if (so -> pageDataCxt )
580+ MemoryContextReset (so -> pageDataCxt );
536581
537582 fakeItem .blkno = GIST_ROOT_BLKNO ;
538583 memset (& fakeItem .data .parentlsn , 0 , sizeof (GistNSN ));
@@ -558,3 +603,20 @@ gistgetbitmap(PG_FUNCTION_ARGS)
558603
559604 PG_RETURN_INT64 (ntids );
560605}
606+
607+ /*
608+ * Can we do index-only scans on the given index column?
609+ *
610+ * Opclasses that implement a fetch function support index-only scans.
611+ */
612+ Datum
613+ gistcanreturn (PG_FUNCTION_ARGS )
614+ {
615+ Relation index = (Relation ) PG_GETARG_POINTER (0 );
616+ int attno = PG_GETARG_INT32 (1 );
617+
618+ if (OidIsValid (index_getprocid (index , attno , GIST_FETCH_PROC )))
619+ PG_RETURN_BOOL (true);
620+ else
621+ PG_RETURN_BOOL (false);
622+ }
0 commit comments