@@ -228,7 +228,9 @@ gistindex_keytest(IndexScanDesc scan,
228
228
* tuples should be reported directly into the bitmap. If they are NULL,
229
229
* we're doing a plain or ordered indexscan. For a plain indexscan, heap
230
230
* 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.
232
234
*
233
235
* If we detect that the index page has split since we saw its downlink
234
236
* 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,
239
241
TIDBitmap * tbm , int64 * ntids )
240
242
{
241
243
GISTScanOpaque so = (GISTScanOpaque ) scan -> opaque ;
244
+ GISTSTATE * giststate = so -> giststate ;
245
+ Relation r = scan -> indexRelation ;
242
246
Buffer buffer ;
243
247
Page page ;
244
248
GISTPageOpaque opaque ;
@@ -288,6 +292,8 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
288
292
}
289
293
290
294
so -> nPageData = so -> curPageData = 0 ;
295
+ if (so -> pageDataCxt )
296
+ MemoryContextReset (so -> pageDataCxt );
291
297
292
298
/*
293
299
* check all tuples on page
@@ -326,10 +332,21 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
326
332
else if (scan -> numberOfOrderBys == 0 && GistPageIsLeaf (page ))
327
333
{
328
334
/*
329
- * Non-ordered scan, so report heap tuples in so->pageData[]
335
+ * Non-ordered scan, so report tuples in so->pageData[]
330
336
*/
331
337
so -> pageData [so -> nPageData ].heapPtr = it -> t_tid ;
332
338
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
+ }
333
350
so -> nPageData ++ ;
334
351
}
335
352
else
@@ -352,6 +369,12 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
352
369
item -> blkno = InvalidBlockNumber ;
353
370
item -> data .heap .heapPtr = it -> t_tid ;
354
371
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 );
355
378
}
356
379
else
357
380
{
@@ -412,6 +435,13 @@ getNextNearest(IndexScanDesc scan)
412
435
GISTScanOpaque so = (GISTScanOpaque ) scan -> opaque ;
413
436
bool res = false;
414
437
438
+ if (scan -> xs_itup )
439
+ {
440
+ /* free previously returned tuple */
441
+ pfree (scan -> xs_itup );
442
+ scan -> xs_itup = NULL ;
443
+ }
444
+
415
445
do
416
446
{
417
447
GISTSearchItem * item = getNextGISTSearchItem (so );
@@ -424,6 +454,10 @@ getNextNearest(IndexScanDesc scan)
424
454
/* found a heap item at currently minimal distance */
425
455
scan -> xs_ctup .t_self = item -> data .heap .heapPtr ;
426
456
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 ;
427
461
res = true;
428
462
}
429
463
else
@@ -465,6 +499,8 @@ gistgettuple(PG_FUNCTION_ARGS)
465
499
466
500
so -> firstCall = false;
467
501
so -> curPageData = so -> nPageData = 0 ;
502
+ if (so -> pageDataCxt )
503
+ MemoryContextReset (so -> pageDataCxt );
468
504
469
505
fakeItem .blkno = GIST_ROOT_BLKNO ;
470
506
memset (& fakeItem .data .parentlsn , 0 , sizeof (GistNSN ));
@@ -483,10 +519,17 @@ gistgettuple(PG_FUNCTION_ARGS)
483
519
{
484
520
if (so -> curPageData < so -> nPageData )
485
521
{
522
+
486
523
/* continuing to return tuples from a leaf page */
487
524
scan -> xs_ctup .t_self = so -> pageData [so -> curPageData ].heapPtr ;
488
525
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
+
489
531
so -> curPageData ++ ;
532
+
490
533
PG_RETURN_BOOL (true);
491
534
}
492
535
@@ -533,6 +576,8 @@ gistgetbitmap(PG_FUNCTION_ARGS)
533
576
534
577
/* Begin the scan by processing the root page */
535
578
so -> curPageData = so -> nPageData = 0 ;
579
+ if (so -> pageDataCxt )
580
+ MemoryContextReset (so -> pageDataCxt );
536
581
537
582
fakeItem .blkno = GIST_ROOT_BLKNO ;
538
583
memset (& fakeItem .data .parentlsn , 0 , sizeof (GistNSN ));
@@ -558,3 +603,20 @@ gistgetbitmap(PG_FUNCTION_ARGS)
558
603
559
604
PG_RETURN_INT64 (ntids );
560
605
}
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