8000 DEBUG: Show index values in pageinspect · petergeoghegan/postgres@c98b41f · GitHub
[go: up one dir, main page]

Skip to content

Commit c98b41f

Browse files
DEBUG: Show index values in pageinspect
This is not intended for commit. It is included as a convenience for reviewers.
1 parent c067eaa commit c98b41f

File tree

5 files changed

+82
-52
lines changed

5 files changed

+82
-52
lines changed

contrib/pageinspect/btreefuncs.c

Lines changed: 67 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ PG_FUNCTION_INFO_V1(bt_multi_page_stats);
5151
#define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
5252
#define IS_BTREE(r) ((r)->rd_rel->relam == BTREE_AM_OID)
5353

54+
#define BTreeTupleGetNKeyAtts(itup, rel) \
55+
Min(IndexRelationGetNumberOfKeyAttributes(rel), BTreeTupleGetNAtts(itup, rel))
56+
5457
/* ------------------------------------------------
5558
* structure for single btree page statistics
5659
* ------------------------------------------------
@@ -470,15 +473,30 @@ bt_multi_page_stats(PG_FUNCTION_ARGS)
470473
SRF_RETURN_DONE(fctx);
471474
}
472475

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+
473490
/*-------------------------------------------------------
474491
* bt_page_print_tuples()
475492
*
476493
* Form a tuple describing index tuple at a given offset
477494
* ------------------------------------------------------
478495
*/
479496
static Datum
480-
bt_page_print_tuples(ua_page_items *uargs)
497+
bt_page_print_tuples(struct user_args *uargs)
481498
{
499+
Relation rel = uargs->rel;
482500
Page page = uargs->page;
483501
OffsetNumber offset = uargs->offset;
484502
bool leafpage = uargs->leafpage;
@@ -513,48 +531,45 @@ bt_page_print_tuples(ua_page_items *uargs)
513531
values[j++] = BoolGetDatum(IndexTupleHasVarwidths(itup));
514532

515533
ptr = (char *) itup + IndexInfoFindDataOffset(itup->t_info);
516-
dlen = IndexTupleSize(itup) - IndexInfoFindDataOffset(itup->t_info);
517534

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)
552536
{
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);
557549
}
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+
558573
values[j++] = CStringGetTextDatum(datacstring);
559574
pfree(datacstring);
560575

@@ -627,7 +642,7 @@ bt_page_items_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
627642
Datum result;
628643
FuncCallContext *fctx;
629644
MemoryContext mctx;
630-
ua_page_items *uargs;
645+
struct user_args *uargs;
631646

632647
if (!superuser())
633648
ereport(ERROR,
@@ -659,13 +674,13 @@ bt_page_items_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
659674
*/
660675
mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
661676

662-
uargs = palloc(sizeof(ua_page_items));
677+
uargs = palloc(sizeof(struct user_args));
663678

679+
uargs->rel = rel;
664680
uargs->page = palloc(BLCKSZ);
665681
memcpy(uargs->page, BufferGetPage(buffer), BLCKSZ);
666682

667683
UnlockReleaseBuffer(buffer);
668-
relation_close(rel, AccessShareLock);
669684

670685
uargs->offset = FirstOffsetNumber;
671686

@@ -703,6 +718,12 @@ bt_page_items_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
703718
uargs->offset++;
704719
SRF_RETURN_NEXT(fctx, result);
705720
}
721+
else
722+
{
723+
relation_close(uargs->rel, AccessShareLock);
724+
pfree(uargs->page);
725+
pfree(uargs);
726+
}
706727

707728
SRF_RETURN_DONE(fctx);
708729
}
@@ -735,7 +756,7 @@ bt_page_items_bytea(PG_FUNCTION_ARGS)
735756
bytea *raw_page = PG_GETARG_BYTEA_P(0);
736757
Datum result;
737758
FuncCallContext *fctx;
738-
ua_page_items *uargs;
759+
struct user_args *uargs;
739760

740761
if (!superuser())
741762
ereport(ERROR,
@@ -751,8 +772,9 @@ bt_page_items_bytea(PG_FUNCTION_ARGS)
751772
fctx = SRF_FIRSTCALL_INIT();
752773
mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
753774

754-
uargs = palloc(sizeof(ua_page_items));
775+
uargs = palloc(sizeof(struct user_args));
755776

777+
uargs->rel = NULL;
756778
uargs->page = get_page_from_raw(raw_page);
757779

758780
if (PageIsNew(uargs->page))

contrib/pageinspect/expected/btree.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ ctid | (0,1)
158158
itemlen | 16
159159
nulls | f
160160
vars | f
161-
data | 01 00 00 00 00 00 00 01
161+
data | (a)=(72057594037927937)
162162
dead | f
163163
htid | (0,1)
164164
tids |

contrib/pageinspect/expected/oldextversions.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ SELECT * FROM bt_page_stats('test1_a_idx', 1);
3333
SELECT * FROM bt_page_items('test1_a_idx', 1);
3434
itemoffset | ctid | itemlen | nulls | vars | data | dead | htid | tids
3535
------------+-------+---------+-------+------+-------------------------+------+-------+------
36-
1 | (0,1) | 16 | f | f | 01 00 00 00 00 00 00 01 | f | (0,1) |
36+
1 | (0,1) | 16 | f | f | (a)=(72057594037927937) | f | (0,1) |
3737
(1 row)
3838

3939
-- page_header() uses int instead of smallint for lower, upper, special and

src/backend/access/index/genam.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,20 +175,26 @@ IndexScanEnd(IndexScanDesc scan)
175175
* change.
176176
*/
177177
char *
178-
BuildIndexValueDescription(Relation indexRelation,
179-
const Datum *values, const bool *isnull)
178+
BuildIndexValueDescription(Relation indexRelation, const Datum *values,
179+
const bool *isnull)
180+
{
181+
return BuildIndexValueDescriptionNatts(indexRelation,
182+
IndexRelationGetNumberOfKeyAttributes(indexRelation),
183+
values, isnull);
184+
}
185+
186+
char *
187+
BuildIndexValueDescriptionNatts(Relation indexRelation, int indnkeyatts,
188+
const Datum *values, const bool *isnull)
180189
{
181190
StringInfoData buf;
182191
Form_pg_index idxrec;
183-
int indnkeyatts;
184192
int i;
185193
int keyno;
186194
Oid indexrelid = RelationGetRelid(indexRelation);
187195
Oid indrelid;
188196
AclResult aclresult;
189197

190-
indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
191-
192198
/*
193199
* Check permissions- if the user does not have access to view all of the
194200
* key columns then return NULL to avoid leaking data.

src/include/access/genam.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ extern bytea *index_opclass_options(Relation indrel, AttrNumber attnum,
239239
extern IndexScanDesc RelationGetIndexScan(Relation indexRelation,
240240
int nkeys, int norderbys);
241241
extern void IndexScanEnd(IndexScanDesc scan);
242+
extern char *BuildIndexValueDescriptionNatts(Relation indexRelation, int indnkeyatts,
243+
const Datum *values, const bool *isnull);
242244
extern char *BuildIndexValueDescription(Relation indexRelation,
243245
const Datum *values, const bool *isnull);
244246
extern TransactionId index_compute_xid_horizon_for_tuples(Relation irel,

0 commit comments

Comments
 (0)
0