33 * formatting heap (data), index and control files.
44 *
55 * Copyright (c) 2002-2010 Red Hat, Inc.
6- * Copyright (c) 2011-2024 , PostgreSQL Global Development Group
6+ * Copyright (c) 2011-2025 , PostgreSQL Global Development Group
77 *
88 * This program is free software; you can redistribute it and/or modify
99 * it under the terms of the GNU General Public License as published by
3333#include "storage/checksum.h"
3434#include "storage/checksum_impl.h"
3535#include "decode.h"
36+ #include <inttypes.h>
3637
3738/*
3839 * Global variables for ease of use mostly
@@ -149,6 +150,13 @@ static void FormatBinary(char *buffer,
149150 unsigned int numBytes , unsigned int startIndex );
150151static void DumpBinaryBlock (char * buffer );
151152static int PrintRelMappings (void );
153+ static ItemPointer ginPostingListDecodeAllSegmentsItems (
154+ GinPostingList * segment ,
155+ int len ,
156+ int * ndecoded_out );
157+ static ItemPointer ginReadTupleItems (
158+ IndexTuple itup ,
159+ int * nitems );
152160
153161
154162/* Send properly formed usage information to the user. */
@@ -825,22 +833,6 @@ IsGinMetaPage(Page page)
825833 return false;
826834}
827835
828- /* Check whether page is a gin leaf page */
829- static bool
830- IsGinLeafPage (Page page )
831- {
832- if ((PageGetSpecialSize (page ) == (MAXALIGN (sizeof (GinPageOpaqueData ))))
833- && (bytesToFormat == blockSize ))
834- {
835- GinPageOpaque gpo = GinPageGetOpaque (page );
836-
837- if (gpo -> flags & GIN_LEAF )
838- return true;
839- }
840-
841- return false;
842- }
843-
844836/* Check whether page is a SpGist meta page */
845837static bool
846838IsSpGistMetaPage (Page page )
@@ -976,6 +968,24 @@ FormatHeader(char *buffer, Page page, BlockNumber blkno, bool isToast)
976968 }
977969 headerBytes += sizeof (BTMetaPageData );
978970 }
971+ else if (IsGinMetaPage (page ))
972+ {
973+ GinMetaPageData * gpMeta = GinPageGetMeta (buffer );
974+ if (!isToast || verbose )
975+ {
976+ printf ("%s GIN Meta Data: Version (%u)\n" ,
977+ indent , gpMeta -> ginVersion );
978+ printf ("%s Pending list: Head: (%u) Tail: (%u) Tail Free Size: (%u)\n" ,
979+ indent , gpMeta -> head , gpMeta -> tail , gpMeta -> tailFreeSize );
980+ printf ("%s Num of Pending Pages: (%u) Num of Pending Heap Tuples: (%" PRIu64 ")\n" ,
981+ indent , gpMeta -> nPendingPages , gpMeta -> nPendingHeapTuples );
982+ printf ("%s Statistic for planner: Num of Total Pages: (%u) Num of Entry Pages: (%u)\n" ,
983+ indent , gpMeta -> nTotalPages , gpMeta -> nEntryPages );
984+ printf ("%s Num of Data Pages: (%u) Num of Entries: (%" PRIu64 ")\n\n" ,
985+ indent , gpMeta -> nDataPages , gpMeta -> nEntries );
986+ }
987+ headerBytes += sizeof (GinMetaPageData );
988+ }
979989
980990 /* Eye the contents of the header and alert the user to possible
981991 * problems. */
@@ -1107,6 +1117,88 @@ decode_varbyte(unsigned char **ptr)
11071117 return val ;
11081118}
11091119
1120+ static ItemPointer
1121+ ginPostingListDecodeAllSegmentsItems (GinPostingList * segment , int len , int * ndecoded_out )
1122+ {
1123+ ItemPointer result ;
1124+ int nallocated ;
1125+ uint64 val ;
1126+ char * endseg = ((char * ) segment ) + len ;
1127+ int ndecoded ;
1128+ unsigned char * ptr ;
1129+ unsigned char * endptr ;
1130+
1131+ /*
1132+ * Guess an initial size of the array.
1133+ */
1134+ nallocated = segment -> nbytes * 2 + 1 ;
1135+ result = palloc (nallocated * sizeof (ItemPointerData ));
1136+
1137+ ndecoded = 0 ;
1138+ while ((char * ) segment < endseg )
1139+ {
1140+ /* enlarge output array if needed */
1141+ if (ndecoded >= nallocated )
1142+ {
1143+ nallocated *= 2 ;
1144+ result = repalloc (result , nallocated * sizeof (ItemPointerData ));
1145+ }
1146+
1147+ /* copy the first item */
1148+ result [ndecoded ] = segment -> first ;
1149+ ndecoded ++ ;
1150+
1151+ val = itemptr_to_uint64 (& segment -> first );
1152+ ptr = segment -> bytes ;
1153+ endptr = segment -> bytes + segment -> nbytes ;
1154+ while (ptr < endptr )
1155+ {
1156+ /* enlarge output array if needed */
1157+ if (ndecoded >= nallocated )
1158+ {
1159+ nallocated *= 2 ;
1160+ result = repalloc (result , nallocated * sizeof (ItemPointerData ));
1161+ }
1162+
1163+ val += decode_varbyte (& ptr );
1164+
1165+ uint64_to_itemptr (val , & result [ndecoded ]);
1166+ ndecoded ++ ;
1167+ }
1168+ segment = GinNextPostingListSegment (segment );
1169+ }
1170+
1171+ if (ndecoded_out )
1172+ * ndecoded_out = ndecoded ;
1173+ return result ;
1174+ }
1175+
1176+ static ItemPointer
1177+ ginReadTupleItems (IndexTuple itup , int * nitems )
1178+ {
1179+ Pointer ptr = GinGetPosting (itup );
1180+ int nipd = GinGetNPosting (itup );
1181+ ItemPointer ipd ;
1182+ if (GinItupIsCompressed (itup ))
1183+ {
1184+ if (nipd > 0 )
1185+ {
1186+ ipd = ginPostingListDecodeAllSegmentsItems ((GinPostingList * )ptr , SizeOfGinPostingList ((GinPostingList * )ptr ), nitems );
1187+ }
1188+ else
1189+ {
1190+ ipd = palloc (0 );
1191+ }
1192+ }
1193+ else
1194+ {
1195+ ipd = (ItemPointer ) palloc (sizeof (ItemPointerData ) * nipd );
1196+ memcpy (ipd , ptr , sizeof (ItemPointerData ) * nipd );
1197+ }
1198+ * nitems = nipd ;
1199+ return ipd ;
1200+ }
1201+
11101202/* Dump out gin-specific content of block */
11111203static void
11121204FormatGinBlock (char * buffer ,
@@ -1122,18 +1214,24 @@ FormatGinBlock(char *buffer,
11221214 if (isToast && !verbose )
11231215 return ;
11241216
1217+ if (GinPageIsDeleted (page ))
1218+ {
1219+ printf ("%s Deleted page.\n\n" , indent );
1220+ return ;
1221+ }
1222+
11251223 printf ("%s<Data> -----\n" , indent );
11261224
1127- if (IsGinLeafPage (page ))
1225+ if (GinPageIsData ( page ) && GinPageIsLeaf (page ))
11281226 {
1227+ printf ("\n%s Leaf Page of TID B-tree\n" ,indent );
11291228 if (GinPageIsCompressed (page ))
11301229 {
11311230 GinPostingList * seg = GinDataLeafPageGetPostingList (page );
11321231 int plist_idx = 1 ;
11331232 Size len = GinDataLeafPageGetPostingListSize (page );
11341233 Pointer endptr = ((Pointer ) seg ) + len ;
11351234 ItemPointer cur ;
1136-
11371235 while ((Pointer ) seg < endptr )
11381236 {
11391237 int item_idx = 1 ;
@@ -1186,24 +1284,98 @@ FormatGinBlock(char *buffer,
11861284 }
11871285 }
11881286 }
1189- else
1287+ else if (!GinPageIsData (page ) && GinPageIsLeaf (page ))
1288+ {
1289+ printf ("\n%s Leaf Page of Element B-tree" , indent );
1290+ for (int offset = FirstOffsetNumber ; offset <= PageGetMaxOffsetNumber (page ); offset ++ )
1291+ {
1292+ IndexTuple itup ;
1293+ itup = (IndexTuple ) PageGetItem (page , PageGetItemId (page , offset ));
1294+ if (!GinIsPostingTree (itup ))
1295+ {
1296+ int nitems ;
1297+ ItemPointer items = ginReadTupleItems (itup , & nitems );
1298+ printf ("\n%s Posting List %3d -- Length: %4u -- isCompressed: %d\n" ,
1299+ indent , offset , nitems , GinItupIsCompressed (itup ));
1300+ for (int i = 0 ; i < nitems ; i ++ )
1301+ {
1302+ printf ("%s ItemPointer %d -- Block Id: %u linp Index: %u\n" ,
1303+ indent , i + 1 ,
1304+ ((uint32 ) ((items [i ].ip_blkid .bi_hi << 16 ) |
1305+ (uint16 ) items [i ].ip_blkid .bi_lo )),
1306+ items [i ].ip_posid );
1307+ }
1308+ pfree (items );
1309+ } else
1310+ {
1311+ BlockNumber rootPostingTree = GinGetPostingTree (itup );
1312+ printf ("\n%s Root posting tree -- Block Id: %u\n" ,
1313+ indent , rootPostingTree );
1314+ }
1315+ }
1316+ }
1317+ else if (!GinPageIsLeaf (page ) && GinPageIsData (page ))
11901318 {
11911319 OffsetNumber cur ,
1192- high = GinPageGetOpaque (page )-> maxoff ;
1320+ high = GinPageGetOpaque (page )-> maxoff ; /* number of PostingItems on GIN_DATA & ~GIN_LEAF page.*/
11931321 PostingItem * pitem = NULL ;
11941322
1323+ ItemPointer rightBound = GinDataPageGetRightBound (page );
1324+
1325+ printf ("%s Internal Page of TID B-tree -- Block Id: %u linp Index: %u\n" ,
1326+ indent ,
1327+ ((uint32 ) ((rightBound -> ip_blkid .bi_hi << 16 ) |
1328+ (uint16 ) rightBound -> ip_blkid .bi_lo )),
1329+ rightBound -> ip_posid );
11951330 for (cur = FirstOffsetNumber ; cur <= high ; cur = OffsetNumberNext (cur ))
11961331 {
11971332 pitem = GinDataPageGetPostingItem (page , cur );
1198- printf ("%s PostingItem %d -- child Block Id: (%u) Block Id: %u linp Index: %u\n" ,
1333+ printf ("%s PostingItem %d -- child Block Id: (%u) Key Block Id: %u Key linp Index: %u\n" ,
11991334 indent , cur ,
1200- ((uint32 ) ((pitem -> child_blkno .bi_hi << 16 ) |
1201- (uint16 ) pitem -> child_blkno .bi_lo )),
1202- ((uint32 ) ((pitem -> key .ip_blkid .bi_hi << 16 ) |
1203- (uint16 ) pitem -> key .ip_blkid .bi_lo )),
1204- pitem -> key .ip_posid );
1335+ ((uint32 ) ((pitem -> child_blkno .bi_hi << 16 ) |
1336+ (uint16 ) pitem -> child_blkno .bi_lo )),
1337+ ((uint32 ) ((pitem -> key .ip_blkid .bi_hi << 16 ) |
1338+ (uint16 ) pitem -> key .ip_blkid .bi_lo )),
1339+ pitem -> key .ip_posid );
1340+ }
1341+ }
1342+ else if (GinPageIsList (page ))
1343+ {
1344+ printf ("\n%s Pending List Page -- Length: %4u\n" , indent , GinPageGetOpaque (page )-> maxoff );
1345+ //Fast list index page, not compressed
1346+ for (OffsetNumber offset = FirstOffsetNumber ; offset <= GinPageGetOpaque (page )-> maxoff ; offset = OffsetNumberNext (offset ))
1347+ {
1348+ IndexTuple itup ;
1349+ itup = (IndexTuple ) PageGetItem (page , PageGetItemId (page , offset ));
1350+ printf ("%s ItemPointer -- Block Id: %u linp Index: %u\n" ,
1351+ indent ,
1352+ ((uint32 ) ((itup -> t_tid .ip_blkid .bi_hi << 16 ) |
1353+ (uint16 ) itup -> t_tid .ip_blkid .bi_lo )),
1354+ itup -> t_tid .ip_posid );
1355+ }
1356+ }
1357+ else if (GinPageGetOpaque (page )-> flags == 0 )
1358+ {
1359+ /*details postgrespro/src/backend/access/gin/ginentrypage::GinFormInteriorTuple,
1360+ *the specified child block number is inserted into t_tid.
1361+ */
1362+ printf ("\n%s Internal Page of Element B-tree \n" , indent );
1363+ for (OffsetNumber offset = FirstOffsetNumber ; offset <= PageGetMaxOffsetNumber (page ); offset = OffsetNumberNext (offset ))
1364+ {
1365+ IndexTuple itup ;
1366+ itup = (IndexTuple ) PageGetItem (page , PageGetItemId (page , offset ));
1367+ printf ("%s ItemPointer -- Block Id: %u linp Index: %u\n" ,
1368+ indent ,
1369+ ((uint32 ) ((itup -> t_tid .ip_blkid .bi_hi << 16 ) |
1370+ (uint16 ) itup -> t_tid .ip_blkid .bi_lo )),
1371+ itup -> t_tid .ip_posid );
12051372 }
12061373 }
1374+ else
1375+ {
1376+ printf ("%s Error: Unknown page type.\n" , indent );
1377+ exitCode = 1 ;
1378+ }
12071379
12081380 printf ("\n" );
12091381}
0 commit comments