@@ -51,6 +51,9 @@ PG_FUNCTION_INFO_V1(bt_multi_page_stats);
51
51
#define IS_INDEX (r ) ((r)->rd_rel->relkind == RELKIND_INDEX)
52
52
#define IS_BTREE (r ) ((r)->rd_rel->relam == BTREE_AM_OID)
53
53
54
+ #define BTreeTupleGetNKeyAtts (itup , rel ) \
55
+ Min(IndexRelationGetNumberOfKeyAttributes(rel), BTreeTupleGetNAtts(itup, rel))
56
+
54
57
/* ------------------------------------------------
55
58
* structure for single btree page statistics
56
59
* ------------------------------------------------
@@ -470,15 +473,30 @@ bt_multi_page_stats(PG_FUNCTION_ARGS)
470
473
SRF_RETURN_DONE (fctx );
471
474
}
472
475
476
+
477
+ /*
478
+ * cross-call data structure for SRF
479
+ */
480
+ struct user_args
481
+ {
482
+ Relation rel ;
483
+ Page page ;
484
+ OffsetNumber offset ;
485
+ bool leafpage ;
486
+ bool rightmost ;
487
+ TupleDesc tupd ;
488
+ };
489
+
473
490
/*-------------------------------------------------------
474
491
* bt_page_print_tuples()
475
492
*
476
493
* Form a tuple describing index tuple at a given offset
477
494
* ------------------------------------------------------
478
495
*/
479
496
static Datum
480
- bt_page_print_tuples (ua_page_items * uargs )
497
+ bt_page_print_tuples (struct user_args * uargs )
481
498
{
499
+ Relation rel = uargs -> rel ;
482
500
Page page = uargs -> page ;
483
501
OffsetNumber offset = uargs -> offset ;
484
502
bool leafpage = uargs -> leafpage ;
@@ -513,48 +531,45 @@ bt_page_print_tuples(ua_page_items *uargs)
513
531
values [j ++ ] = BoolGetDatum (IndexTupleHasVarwidths (itup ));
514
532
515
533
ptr = (char * ) itup + IndexInfoFindDataOffset (itup -> t_info );
516
- dlen = IndexTupleSize (itup ) - IndexInfoFindDataOffset (itup -> t_info );
517
534
518
- /*
519
- * Make sure that "data" column does not include posting list or pivot
520
- * tuple representation of heap TID(s).
521
- *
522
- * Note: BTreeTupleIsPivot() won't work reliably on !heapkeyspace indexes
523
- * (those built before BTREE_VERSION 4), but we have no way of determining
524
- * if this page came from a !heapkeyspace index. We may only have a bytea
525
- * nbtree page image to go on, so in general there is no metapage that we
526
- * can check.
527
- *
528
- * That's okay here because BTreeTupleIsPivot() can only return false for
529
- * a !heapkeyspace pivot, never true for a !heapkeyspace non-pivot. Since
530
- * heap TID isn't part of the keyspace in a !heapkeyspace index anyway,
531
- * there cannot possibly be a pivot tuple heap TID representation that we
532
- * fail to make an adjustment for. A !heapkeyspace index can have
533
- * BTreeTupleIsPivot() return true (due to things like suffix truncation
534
- * for INCLUDE indexes in Postgres v11), but when that happens
535
- * BTreeTupleGetHeapTID() can be trusted to work reliably (i.e. return
536
- * NULL).
537
- *
538
- * Note: BTreeTupleIsPosting() always works reliably, even with
539
- * !heapkeyspace indexes.
540
- */
541
- if (BTreeTupleIsPosting (itup ))
542
- dlen -= IndexTupleSize (itup ) - BTreeTupleGetPostingOffset (itup );
543
- else if (BTreeTupleIsPivot (itup ) && BTreeTupleGetHeapTID (itup ) != NULL )
544
- dlen -= MAXALIGN (sizeof (ItemPointerData ));
545
-
546
- if (dlen < 0 || dlen > INDEX_SIZE_MASK )
547
- elog (ERROR , "invalid tuple length %d for tuple at offset number %u" ,
548
- dlen , offset );
549
- dump = palloc0 (dlen * 3 + 1 );
550
- datacstring = dump ;
551
- for (off = 0 ; off < dlen ; off ++ )
535
+ if (rel )
552
536
{
553
- if (off > 0 )
554
- * dump ++ = ' ' ;
555
- sprintf (dump , "%02x" , * (ptr + off ) & 0xff );
556
- dump += 2 ;
537
+ TupleDesc itupdesc ;
538
+ Datum datvalues [INDEX_MAX_KEYS ];
539
+ bool isnull [INDEX_MAX_KEYS ];
540
+ int natts = BTreeTupleGetNKeyAtts (itup , rel );
541
+
542
+ itupdesc = CreateTupleDescTruncatedCopy (RelationGetDescr (rel ), natts );
543
+
544
+ memset (& isnull , 0x00 , sizeof (isnull ));
545
+ index_deform_tuple (itup , itupdesc , datvalues , isnull );
546
+ datacstring = BuildIndexValueDescriptionNatts (rel , natts , datvalues , isnull );
547
+
548
+ pfree (itupdesc );
557
549
}
550
+ else
551
+ {
552
+ dlen = IndexTupleSize (itup ) - IndexInfoFindDataOffset (itup -> t_info );
553
+
554
+ if (BTreeTupleIsPosting (itup ))
555
+ dlen -= IndexTupleSize (itup ) - BTreeTupleGetPostingOffset (itup );
556
+ else if (BTreeTupleIsPivot (itup ) && BTreeTupleGetHeapTID (itup ) != NULL )
557
+ dlen -= MAXALIGN (sizeof (ItemPointerData ));
558
+
559
+ if (dlen < 0 || dlen > INDEX_SIZE_MASK )
560
+ elog (ERROR , "invalid tuple length %d for tuple at offset number %u" ,
561
+ dlen , offset );
562
+ dump = palloc0 (dlen * 3 + 1 );
563
+ datacstring = dump ;
564
+ for (off = 0 ; off < dlen ; off ++ )
565
+ {
566
+ if (off > 0 )
567
+ * dump ++ = ' ' ;
568
+ sprintf (dump , "%02x" , * (ptr + off ) & 0xff );
569
+ dump += 2 ;
570
+ }
571
+ }
572
+
558
573
values [j ++ ] = CStringGetTextDatum (datacstring );
559
574
pfree (datacstring );
560
575
@@ -627,7 +642,7 @@ bt_page_items_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
627
642
Datum result ;
628
643
FuncCallContext * fctx ;
629
644
MemoryContext mctx ;
630
- ua_page_items * uargs ;
645
+ struct user_args * uargs ;
631
646
632
647
if (!superuser ())
633
648
ereport (ERROR ,
@@ -659,13 +674,13 @@ bt_page_items_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
659
674
*/
660
675
mctx = MemoryContextSwitchTo (fctx -> multi_call_memory_ctx );
661
676
662
- uargs = palloc (sizeof (ua_page_items ));
677
+ uargs = palloc (sizeof (struct user_args ));
663
678
679
+ uargs -> rel = rel ;
664
680
uargs -> page = palloc (BLCKSZ );
665
681
memcpy (uargs -> page , BufferGetPage (buffer ), BLCKSZ );
666
682
667
683
UnlockReleaseBuffer (buffer );
668
- relation_close (rel , AccessShareLock );
669
684
670
685
uargs -> offset = FirstOffsetNumber ;
671
686
@@ -703,6 +718,12 @@ bt_page_items_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
703
718
uargs -> offset ++ ;
704
719
SRF_RETURN_NEXT (fctx , result );
705
720
}
721
+ else
722
+ {
723
+ relation_close (uargs -> rel , AccessShareLock );
724
+ pfree (uargs -> page );
725
+ pfree (uargs );
726
+ }
706
727
707
728
SRF_RETURN_DONE (fctx );
708
729
}
@@ -735,7 +756,7 @@ bt_page_items_bytea(PG_FUNCTION_ARGS)
735
756
bytea * raw_page = PG_GETARG_BYTEA_P (0 );
736
757
Datum result ;
737
758
FuncCallContext * fctx ;
738
- ua_page_items * uargs ;
759
+ struct user_args * uargs ;
739
760
740
761
if (!superuser ())
741
762
ereport (ERROR ,
@@ -751,8 +772,9 @@ bt_page_items_bytea(PG_FUNCTION_ARGS)
751
772
fctx = SRF_FIRSTCALL_INIT ();
752
773
mctx = MemoryContextSwitchTo (fctx -> multi_call_memory_ctx );
753
774
754
- uargs = palloc (sizeof (ua_page_items ));
775
+ uargs = palloc (sizeof (struct user_args ));
755
776
777
+ uargs -> rel = NULL ;
756
778
uargs -> page = get_page_from_raw (raw_page );
757
779
758
780
if (PageIsNew (uargs -> page ))
0 commit comments