LCOV - code coverage report
Current view: top level - contrib/pageinspect - hashfuncs.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 266 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 12 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * hashfuncs.c
       3              :  *              Functions to investigate the content of HASH indexes
       4              :  *
       5              :  * Copyright (c) 2017-2026, PostgreSQL Global Development Group
       6              :  *
       7              :  * IDENTIFICATION
       8              :  *              contrib/pageinspect/hashfuncs.c
       9              :  */
      10              : 
      11              : #include "postgres.h"
      12              : 
      13              : #include "access/hash.h"
      14              : #include "access/htup_details.h"
      15              : #include "access/relation.h"
      16              : #include "catalog/pg_am.h"
      17              : #include "catalog/pg_type.h"
      18              : #include "funcapi.h"
      19              : #include "miscadmin.h"
      20              : #include "pageinspect.h"
      21              : #include "utils/array.h"
      22              : #include "utils/builtins.h"
      23              : #include "utils/rel.h"
      24              : 
      25            0 : PG_FUNCTION_INFO_V1(hash_page_type);
      26            0 : PG_FUNCTION_INFO_V1(hash_page_stats);
      27            0 : PG_FUNCTION_INFO_V1(hash_page_items);
      28            0 : PG_FUNCTION_INFO_V1(hash_bitmap_info);
      29            0 : PG_FUNCTION_INFO_V1(hash_metapage_info);
      30              : 
      31              : #define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
      32              : #define IS_HASH(r) ((r)->rd_rel->relam == HASH_AM_OID)
      33              : 
      34              : /* ------------------------------------------------
      35              :  * structure for single hash page statistics
      36              :  * ------------------------------------------------
      37              :  */
      38              : typedef struct HashPageStat
      39              : {
      40              :         int                     live_items;
      41              :         int                     dead_items;
      42              :         int                     page_size;
      43              :         int                     free_size;
      44              : 
      45              :         /* opaque data */
      46              :         BlockNumber hasho_prevblkno;
      47              :         BlockNumber hasho_nextblkno;
      48              :         Bucket          hasho_bucket;
      49              :         uint16          hasho_flag;
      50              :         uint16          hasho_page_id;
      51              : } HashPageStat;
      52              : 
      53              : 
      54              : /*
      55              :  * Verify that the given bytea contains a HASH page, or die in the attempt.
      56              :  * A pointer to a palloc'd, properly aligned copy of the page is returned.
      57              :  */
      58              : static Page
      59            0 : verify_hash_page(bytea *raw_page, int flags)
      60              : {
      61            0 :         Page            page = get_page_from_raw(raw_page);
      62            0 :         int                     pagetype = LH_UNUSED_PAGE;
      63              : 
      64              :         /* Treat new pages as unused. */
      65            0 :         if (!PageIsNew(page))
      66              :         {
      67            0 :                 HashPageOpaque pageopaque;
      68              : 
      69            0 :                 if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData)))
      70            0 :                         ereport(ERROR,
      71              :                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      72              :                                          errmsg("input page is not a valid %s page", "hash"),
      73              :                                          errdetail("Expected special size %d, got %d.",
      74              :                                                            (int) MAXALIGN(sizeof(HashPageOpaqueData)),
      75              :                                                            (int) PageGetSpecialSize(page))));
      76              : 
      77            0 :                 pageopaque = HashPageGetOpaque(page);
      78            0 :                 if (pageopaque->hasho_page_id != HASHO_PAGE_ID)
      79            0 :                         ereport(ERROR,
      80              :                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      81              :                                          errmsg("input page is not a valid %s page", "hash"),
      82              :                                          errdetail("Expected %08x, got %08x.",
      83              :                                                            HASHO_PAGE_ID, pageopaque->hasho_page_id)));
      84              : 
      85            0 :                 pagetype = pageopaque->hasho_flag & LH_PAGE_TYPE;
      86            0 :         }
      87              : 
      88              :         /* Check that page type is sane. */
      89            0 :         if (pagetype != LH_OVERFLOW_PAGE && pagetype != LH_BUCKET_PAGE &&
      90            0 :                 pagetype != LH_BITMAP_PAGE && pagetype != LH_META_PAGE &&
      91            0 :                 pagetype != LH_UNUSED_PAGE)
      92            0 :                 ereport(ERROR,
      93              :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      94              :                                  errmsg("invalid hash page type %08x", pagetype)));
      95              : 
      96              :         /* If requested, verify page type. */
      97            0 :         if (flags != 0 && (pagetype & flags) == 0)
      98              :         {
      99            0 :                 switch (flags)
     100              :                 {
     101              :                         case LH_META_PAGE:
     102            0 :                                 ereport(ERROR,
     103              :                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     104              :                                                  errmsg("page is not a hash meta page")));
     105            0 :                                 break;
     106              :                         case LH_BUCKET_PAGE | LH_OVERFLOW_PAGE:
     107            0 :                                 ereport(ERROR,
     108              :                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     109              :                                                  errmsg("page is not a hash bucket or overflow page")));
     110            0 :                                 break;
     111              :                         case LH_OVERFLOW_PAGE:
     112            0 :                                 ereport(ERROR,
     113              :                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     114              :                                                  errmsg("page is not a hash overflow page")));
     115            0 :                                 break;
     116              :                         default:
     117            0 :                                 elog(ERROR,
     118              :                                          "hash page of type %08x not in mask %08x",
     119              :                                          pagetype, flags);
     120            0 :                                 break;
     121              :                 }
     122            0 :         }
     123              : 
     124              :         /*
     125              :          * If it is the metapage, also verify magic number and version.
     126              :          */
     127            0 :         if (pagetype == LH_META_PAGE)
     128              :         {
     129            0 :                 HashMetaPage metap = HashPageGetMeta(page);
     130              : 
     131            0 :                 if (metap->hashm_magic != HASH_MAGIC)
     132            0 :                         ereport(ERROR,
     133              :                                         (errcode(ERRCODE_INDEX_CORRUPTED),
     134              :                                          errmsg("invalid magic number for metadata"),
     135              :                                          errdetail("Expected 0x%08x, got 0x%08x.",
     136              :                                                            HASH_MAGIC, metap->hashm_magic)));
     137              : 
     138            0 :                 if (metap->hashm_version != HASH_VERSION)
     139            0 :                         ereport(ERROR,
     140              :                                         (errcode(ERRCODE_INDEX_CORRUPTED),
     141              :                                          errmsg("invalid version for metadata"),
     142              :                                          errdetail("Expected %d, got %d.",
     143              :                                                            HASH_VERSION, metap->hashm_version)));
     144            0 :         }
     145              : 
     146            0 :         return page;
     147            0 : }
     148              : 
     149              : /* -------------------------------------------------
     150              :  * GetHashPageStatistics()
     151              :  *
     152              :  * Collect statistics of single hash page
     153              :  * -------------------------------------------------
     154              :  */
     155              : static void
     156            0 : GetHashPageStatistics(Page page, HashPageStat *stat)
     157              : {
     158            0 :         OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
     159            0 :         HashPageOpaque opaque = HashPageGetOpaque(page);
     160            0 :         int                     off;
     161              : 
     162            0 :         stat->dead_items = stat->live_items = 0;
     163            0 :         stat->page_size = PageGetPageSize(page);
     164              : 
     165              :         /* hash page opaque data */
     166            0 :         stat->hasho_prevblkno = opaque->hasho_prevblkno;
     167            0 :         stat->hasho_nextblkno = opaque->hasho_nextblkno;
     168            0 :         stat->hasho_bucket = opaque->hasho_bucket;
     169            0 :         stat->hasho_flag = opaque->hasho_flag;
     170            0 :         stat->hasho_page_id = opaque->hasho_page_id;
     171              : 
     172              :         /* count live and dead tuples, and free space */
     173            0 :         for (off = FirstOffsetNumber; off <= maxoff; off++)
     174              :         {
     175            0 :                 ItemId          id = PageGetItemId(page, off);
     176              : 
     177            0 :                 if (!ItemIdIsDead(id))
     178            0 :                         stat->live_items++;
     179              :                 else
     180            0 :                         stat->dead_items++;
     181            0 :         }
     182            0 :         stat->free_size = PageGetFreeSpace(page);
     183            0 : }
     184              : 
     185              : /* ---------------------------------------------------
     186              :  * hash_page_type()
     187              :  *
     188              :  * Usage: SELECT hash_page_type(get_raw_page('con_hash_index', 1));
     189              :  * ---------------------------------------------------
     190              :  */
     191              : Datum
     192            0 : hash_page_type(PG_FUNCTION_ARGS)
     193              : {
     194            0 :         bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     195            0 :         Page            page;
     196            0 :         HashPageOpaque opaque;
     197            0 :         int                     pagetype;
     198            0 :         const char *type;
     199              : 
     200            0 :         if (!superuser())
     201            0 :                 ereport(ERROR,
     202              :                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     203              :                                  errmsg("must be superuser to use raw page functions")));
     204              : 
     205            0 :         page = verify_hash_page(raw_page, 0);
     206              : 
     207            0 :         if (PageIsNew(page))
     208            0 :                 type = "unused";
     209              :         else
     210              :         {
     211            0 :                 opaque = HashPageGetOpaque(page);
     212              : 
     213              :                 /* page type (flags) */
     214            0 :                 pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
     215            0 :                 if (pagetype == LH_META_PAGE)
     216            0 :                         type = "metapage";
     217            0 :                 else if (pagetype == LH_OVERFLOW_PAGE)
     218            0 :                         type = "overflow";
     219            0 :                 else if (pagetype == LH_BUCKET_PAGE)
     220            0 :                         type = "bucket";
     221            0 :                 else if (pagetype == LH_BITMAP_PAGE)
     222            0 :                         type = "bitmap";
     223              :                 else
     224            0 :                         type = "unused";
     225              :         }
     226              : 
     227            0 :         PG_RETURN_TEXT_P(cstring_to_text(type));
     228            0 : }
     229              : 
     230              : /* ---------------------------------------------------
     231              :  * hash_page_stats()
     232              :  *
     233              :  * Usage: SELECT * FROM hash_page_stats(get_raw_page('con_hash_index', 1));
     234              :  * ---------------------------------------------------
     235              :  */
     236              : Datum
     237            0 : hash_page_stats(PG_FUNCTION_ARGS)
     238              : {
     239            0 :         bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     240            0 :         Page            page;
     241            0 :         int                     j;
     242            0 :         Datum           values[9];
     243            0 :         bool            nulls[9] = {0};
     244            0 :         HashPageStat stat;
     245            0 :         HeapTuple       tuple;
     246            0 :         TupleDesc       tupleDesc;
     247              : 
     248            0 :         if (!superuser())
     249            0 :                 ereport(ERROR,
     250              :                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     251              :                                  errmsg("must be superuser to use raw page functions")));
     252              : 
     253            0 :         page = verify_hash_page(raw_page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
     254              : 
     255              :         /* keep compiler quiet */
     256            0 :         stat.hasho_prevblkno = stat.hasho_nextblkno = InvalidBlockNumber;
     257            0 :         stat.hasho_flag = stat.hasho_page_id = stat.free_size = 0;
     258              : 
     259            0 :         GetHashPageStatistics(page, &stat);
     260              : 
     261              :         /* Build a tuple descriptor for our result type */
     262            0 :         if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
     263            0 :                 elog(ERROR, "return type must be a row type");
     264            0 :         tupleDesc = BlessTupleDesc(tupleDesc);
     265              : 
     266            0 :         j = 0;
     267            0 :         values[j++] = Int32GetDatum(stat.live_items);
     268            0 :         values[j++] = Int32GetDatum(stat.dead_items);
     269            0 :         values[j++] = Int32GetDatum(stat.page_size);
     270            0 :         values[j++] = Int32GetDatum(stat.free_size);
     271            0 :         values[j++] = Int64GetDatum((int64) stat.hasho_prevblkno);
     272            0 :         values[j++] = Int64GetDatum((int64) stat.hasho_nextblkno);
     273            0 :         values[j++] = Int64GetDatum((int64) stat.hasho_bucket);
     274            0 :         values[j++] = Int32GetDatum((int32) stat.hasho_flag);
     275            0 :         values[j++] = Int32GetDatum((int32) stat.hasho_page_id);
     276              : 
     277            0 :         tuple = heap_form_tuple(tupleDesc, values, nulls);
     278              : 
     279            0 :         PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
     280            0 : }
     281              : 
     282              : /*
     283              :  * cross-call data structure for SRF
     284              :  */
     285              : struct user_args
     286              : {
     287              :         Page            page;
     288              :         OffsetNumber offset;
     289              : };
     290              : 
     291              : /*-------------------------------------------------------
     292              :  * hash_page_items()
     293              :  *
     294              :  * Get IndexTupleData set in a hash page
     295              :  *
     296              :  * Usage: SELECT * FROM hash_page_items(get_raw_page('con_hash_index', 1));
     297              :  *-------------------------------------------------------
     298              :  */
     299              : Datum
     300            0 : hash_page_items(PG_FUNCTION_ARGS)
     301              : {
     302            0 :         bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     303            0 :         Page            page;
     304            0 :         Datum           result;
     305            0 :         Datum           values[3];
     306            0 :         bool            nulls[3] = {0};
     307            0 :         uint32          hashkey;
     308            0 :         HeapTuple       tuple;
     309            0 :         FuncCallContext *fctx;
     310            0 :         MemoryContext mctx;
     311            0 :         struct user_args *uargs;
     312              : 
     313            0 :         if (!superuser())
     314            0 :                 ereport(ERROR,
     315              :                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     316              :                                  errmsg("must be superuser to use raw page functions")));
     317              : 
     318            0 :         if (SRF_IS_FIRSTCALL())
     319              :         {
     320            0 :                 TupleDesc       tupleDesc;
     321              : 
     322            0 :                 fctx = SRF_FIRSTCALL_INIT();
     323              : 
     324            0 :                 mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
     325              : 
     326            0 :                 page = verify_hash_page(raw_page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
     327              : 
     328            0 :                 uargs = palloc_object(struct user_args);
     329              : 
     330            0 :                 uargs->page = page;
     331              : 
     332            0 :                 uargs->offset = FirstOffsetNumber;
     333              : 
     334            0 :                 fctx->max_calls = PageGetMaxOffsetNumber(uargs->page);
     335              : 
     336              :                 /* Build a tuple descriptor for our result type */
     337            0 :                 if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
     338            0 :                         elog(ERROR, "return type must be a row type");
     339            0 :                 tupleDesc = BlessTupleDesc(tupleDesc);
     340              : 
     341            0 :                 fctx->attinmeta = TupleDescGetAttInMetadata(tupleDesc);
     342              : 
     343            0 :                 fctx->user_fctx = uargs;
     344              : 
     345            0 :                 MemoryContextSwitchTo(mctx);
     346            0 :         }
     347              : 
     348            0 :         fctx = SRF_PERCALL_SETUP();
     349            0 :         uargs = fctx->user_fctx;
     350              : 
     351            0 :         if (fctx->call_cntr < fctx->max_calls)
     352              :         {
     353            0 :                 ItemId          id;
     354            0 :                 IndexTuple      itup;
     355            0 :                 int                     j;
     356              : 
     357            0 :                 id = PageGetItemId(uargs->page, uargs->offset);
     358              : 
     359            0 :                 if (!ItemIdIsValid(id))
     360            0 :                         elog(ERROR, "invalid ItemId");
     361              : 
     362            0 :                 itup = (IndexTuple) PageGetItem(uargs->page, id);
     363              : 
     364            0 :                 j = 0;
     365            0 :                 values[j++] = Int32GetDatum((int32) uargs->offset);
     366            0 :                 values[j++] = PointerGetDatum(&itup->t_tid);
     367              : 
     368            0 :                 hashkey = _hash_get_indextuple_hashkey(itup);
     369            0 :                 values[j] = Int64GetDatum((int64) hashkey);
     370              : 
     371            0 :                 tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
     372            0 :                 result = HeapTupleGetDatum(tuple);
     373              : 
     374            0 :                 uargs->offset = uargs->offset + 1;
     375              : 
     376            0 :                 SRF_RETURN_NEXT(fctx, result);
     377            0 :         }
     378              : 
     379            0 :         SRF_RETURN_DONE(fctx);
     380            0 : }
     381              : 
     382              : /* ------------------------------------------------
     383              :  * hash_bitmap_info()
     384              :  *
     385              :  * Get bitmap information for a particular overflow page
     386              :  *
     387              :  * Usage: SELECT * FROM hash_bitmap_info('con_hash_index'::regclass, 5);
     388              :  * ------------------------------------------------
     389              :  */
     390              : Datum
     391            0 : hash_bitmap_info(PG_FUNCTION_ARGS)
     392              : {
     393            0 :         Oid                     indexRelid = PG_GETARG_OID(0);
     394            0 :         int64           ovflblkno = PG_GETARG_INT64(1);
     395            0 :         HashMetaPage metap;
     396            0 :         Buffer          metabuf,
     397              :                                 mapbuf;
     398            0 :         BlockNumber bitmapblkno;
     399            0 :         Page            mappage;
     400            0 :         bool            bit = false;
     401            0 :         TupleDesc       tupleDesc;
     402            0 :         Relation        indexRel;
     403            0 :         uint32          ovflbitno;
     404            0 :         int32           bitmappage,
     405              :                                 bitmapbit;
     406            0 :         HeapTuple       tuple;
     407            0 :         int                     i,
     408              :                                 j;
     409            0 :         Datum           values[3];
     410            0 :         bool            nulls[3] = {0};
     411            0 :         uint32     *freep;
     412              : 
     413            0 :         if (!superuser())
     414            0 :                 ereport(ERROR,
     415              :                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     416              :                                  errmsg("must be superuser to use raw page functions")));
     417              : 
     418              :         /*
     419              :          * This uses relation_open() and not index_open().  The latter allows
     420              :          * partitioned indexes, and these are forbidden here.
     421              :          */
     422            0 :         indexRel = relation_open(indexRelid, AccessShareLock);
     423              : 
     424            0 :         if (!IS_INDEX(indexRel) || !IS_HASH(indexRel))
     425            0 :                 ereport(ERROR,
     426              :                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     427              :                                  errmsg("\"%s\" is not a %s index",
     428              :                                                 RelationGetRelationName(indexRel), "hash")));
     429              : 
     430            0 :         if (RELATION_IS_OTHER_TEMP(indexRel))
     431            0 :                 ereport(ERROR,
     432              :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     433              :                                  errmsg("cannot access temporary tables of other sessions")));
     434              : 
     435            0 :         if (ovflblkno < 0 || ovflblkno > MaxBlockNumber)
     436            0 :                 ereport(ERROR,
     437              :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     438              :                                  errmsg("invalid block number")));
     439              : 
     440            0 :         if (ovflblkno >= RelationGetNumberOfBlocks(indexRel))
     441            0 :                 ereport(ERROR,
     442              :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     443              :                                  errmsg("block number %" PRId64 " is out of range for relation \"%s\"",
     444              :                                                 ovflblkno, RelationGetRelationName(indexRel))));
     445              : 
     446              :         /* Read the metapage so we can determine which bitmap page to use */
     447            0 :         metabuf = _hash_getbuf(indexRel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
     448            0 :         metap = HashPageGetMeta(BufferGetPage(metabuf));
     449              : 
     450              :         /*
     451              :          * Reject attempt to read the bit for a metapage or bitmap page; this is
     452              :          * only meaningful for overflow pages.
     453              :          */
     454            0 :         if (ovflblkno == 0)
     455            0 :                 ereport(ERROR,
     456              :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     457              :                                  errmsg("invalid overflow block number %u",
     458              :                                                 (BlockNumber) ovflblkno)));
     459            0 :         for (i = 0; i < metap->hashm_nmaps; i++)
     460            0 :                 if (metap->hashm_mapp[i] == ovflblkno)
     461            0 :                         ereport(ERROR,
     462              :                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     463              :                                          errmsg("invalid overflow block number %u",
     464              :                                                         (BlockNumber) ovflblkno)));
     465              : 
     466              :         /*
     467              :          * Identify overflow bit number.  This will error out for primary bucket
     468              :          * pages, and we've already rejected the metapage and bitmap pages above.
     469              :          */
     470            0 :         ovflbitno = _hash_ovflblkno_to_bitno(metap, (BlockNumber) ovflblkno);
     471              : 
     472            0 :         bitmappage = ovflbitno >> BMPG_SHIFT(metap);
     473            0 :         bitmapbit = ovflbitno & BMPG_MASK(metap);
     474              : 
     475            0 :         if (bitmappage >= metap->hashm_nmaps)
     476            0 :                 ereport(ERROR,
     477              :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     478              :                                  errmsg("invalid overflow block number %u",
     479              :                                                 (BlockNumber) ovflblkno)));
     480              : 
     481            0 :         bitmapblkno = metap->hashm_mapp[bitmappage];
     482              : 
     483            0 :         _hash_relbuf(indexRel, metabuf);
     484              : 
     485              :         /* Check the status of bitmap bit for overflow page */
     486            0 :         mapbuf = _hash_getbuf(indexRel, bitmapblkno, HASH_READ, LH_BITMAP_PAGE);
     487            0 :         mappage = BufferGetPage(mapbuf);
     488            0 :         freep = HashPageGetBitmap(mappage);
     489              : 
     490            0 :         bit = ISSET(freep, bitmapbit) != 0;
     491              : 
     492            0 :         _hash_relbuf(indexRel, mapbuf);
     493            0 :         relation_close(indexRel, AccessShareLock);
     494              : 
     495              :         /* Build a tuple descriptor for our result type */
     496            0 :         if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
     497            0 :                 elog(ERROR, "return type must be a row type");
     498            0 :         tupleDesc = BlessTupleDesc(tupleDesc);
     499              : 
     500            0 :         j = 0;
     501            0 :         values[j++] = Int64GetDatum((int64) bitmapblkno);
     502            0 :         values[j++] = Int32GetDatum(bitmapbit);
     503            0 :         values[j++] = BoolGetDatum(bit);
     504              : 
     505            0 :         tuple = heap_form_tuple(tupleDesc, values, nulls);
     506              : 
     507            0 :         PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
     508            0 : }
     509              : 
     510              : /* ------------------------------------------------
     511              :  * hash_metapage_info()
     512              :  *
     513              :  * Get the meta-page information for a hash index
     514              :  *
     515              :  * Usage: SELECT * FROM hash_metapage_info(get_raw_page('con_hash_index', 0))
     516              :  * ------------------------------------------------
     517              :  */
     518              : Datum
     519            0 : hash_metapage_info(PG_FUNCTION_ARGS)
     520              : {
     521            0 :         bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     522            0 :         Page            page;
     523            0 :         HashMetaPageData *metad;
     524            0 :         TupleDesc       tupleDesc;
     525            0 :         HeapTuple       tuple;
     526            0 :         int                     i,
     527              :                                 j;
     528            0 :         Datum           values[16];
     529            0 :         bool            nulls[16] = {0};
     530            0 :         Datum           spares[HASH_MAX_SPLITPOINTS];
     531            0 :         Datum           mapp[HASH_MAX_BITMAPS];
     532              : 
     533            0 :         if (!superuser())
     534            0 :                 ereport(ERROR,
     535              :                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     536              :                                  errmsg("must be superuser to use raw page functions")));
     537              : 
     538            0 :         page = verify_hash_page(raw_page, LH_META_PAGE);
     539              : 
     540              :         /* Build a tuple descriptor for our result type */
     541            0 :         if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
     542            0 :                 elog(ERROR, "return type must be a row type");
     543            0 :         tupleDesc = BlessTupleDesc(tupleDesc);
     544              : 
     545            0 :         metad = HashPageGetMeta(page);
     546              : 
     547            0 :         j = 0;
     548            0 :         values[j++] = Int64GetDatum((int64) metad->hashm_magic);
     549            0 :         values[j++] = Int64GetDatum((int64) metad->hashm_version);
     550            0 :         values[j++] = Float8GetDatum(metad->hashm_ntuples);
     551            0 :         values[j++] = Int32GetDatum((int32) metad->hashm_ffactor);
     552            0 :         values[j++] = Int32GetDatum((int32) metad->hashm_bsize);
     553            0 :         values[j++] = Int32GetDatum((int32) metad->hashm_bmsize);
     554            0 :         values[j++] = Int32GetDatum((int32) metad->hashm_bmshift);
     555            0 :         values[j++] = Int64GetDatum((int64) metad->hashm_maxbucket);
     556            0 :         values[j++] = Int64GetDatum((int64) metad->hashm_highmask);
     557            0 :         values[j++] = Int64GetDatum((int64) metad->hashm_lowmask);
     558            0 :         values[j++] = Int64GetDatum((int64) metad->hashm_ovflpoint);
     559            0 :         values[j++] = Int64GetDatum((int64) metad->hashm_firstfree);
     560            0 :         values[j++] = Int64GetDatum((int64) metad->hashm_nmaps);
     561            0 :         values[j++] = ObjectIdGetDatum((Oid) metad->hashm_procid);
     562              : 
     563            0 :         for (i = 0; i < HASH_MAX_SPLITPOINTS; i++)
     564            0 :                 spares[i] = Int64GetDatum((int64) metad->hashm_spares[i]);
     565            0 :         values[j++] = PointerGetDatum(construct_array_builtin(spares, HASH_MAX_SPLITPOINTS, INT8OID));
     566              : 
     567            0 :         for (i = 0; i < HASH_MAX_BITMAPS; i++)
     568            0 :                 mapp[i] = Int64GetDatum((int64) metad->hashm_mapp[i]);
     569            0 :         values[j++] = PointerGetDatum(construct_array_builtin(mapp, HASH_MAX_BITMAPS, INT8OID));
     570              : 
     571            0 :         tuple = heap_form_tuple(tupleDesc, values, nulls);
     572              : 
     573            0 :         PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
     574            0 : }
        

Generated by: LCOV version 2.3.2-1