LCOV - code coverage report
Current view: top level - contrib/pageinspect - hashfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 168 210 80.0 %
Date: 2024-07-18 17:11:54 Functions: 12 12 100.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-2024, 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          14 : PG_FUNCTION_INFO_V1(hash_page_type);
      26          14 : PG_FUNCTION_INFO_V1(hash_page_stats);
      27          14 : PG_FUNCTION_INFO_V1(hash_page_items);
      28          14 : PG_FUNCTION_INFO_V1(hash_bitmap_info);
      29          14 : 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          72 : verify_hash_page(bytea *raw_page, int flags)
      60             : {
      61          72 :     Page        page = get_page_from_raw(raw_page);
      62          64 :     int         pagetype = LH_UNUSED_PAGE;
      63             : 
      64             :     /* Treat new pages as unused. */
      65          64 :     if (!PageIsNew(page))
      66             :     {
      67             :         HashPageOpaque pageopaque;
      68             : 
      69          56 :         if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData)))
      70           8 :             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          48 :         pageopaque = HashPageGetOpaque(page);
      78          48 :         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          48 :         pagetype = pageopaque->hasho_flag & LH_PAGE_TYPE;
      86             :     }
      87             : 
      88             :     /* Check that page type is sane. */
      89          56 :     if (pagetype != LH_OVERFLOW_PAGE && pagetype != LH_BUCKET_PAGE &&
      90          16 :         pagetype != LH_BITMAP_PAGE && pagetype != LH_META_PAGE &&
      91             :         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          56 :     if (flags != 0 && (pagetype & flags) == 0)
      98             :     {
      99          24 :         switch (flags)
     100             :         {
     101          12 :             case LH_META_PAGE:
     102          12 :                 ereport(ERROR,
     103             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     104             :                          errmsg("page is not a hash meta page")));
     105             :                 break;
     106          12 :             case LH_BUCKET_PAGE | LH_OVERFLOW_PAGE:
     107          12 :                 ereport(ERROR,
     108             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     109             :                          errmsg("page is not a hash bucket or overflow page")));
     110             :                 break;
     111           0 :             case LH_OVERFLOW_PAGE:
     112           0 :                 ereport(ERROR,
     113             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     114             :                          errmsg("page is not a hash overflow page")));
     115             :                 break;
     116           0 :             default:
     117           0 :                 elog(ERROR,
     118             :                      "hash page of type %08x not in mask %08x",
     119             :                      pagetype, flags);
     120             :                 break;
     121             :         }
     122          32 :     }
     123             : 
     124             :     /*
     125             :      * If it is the metapage, also verify magic number and version.
     126             :      */
     127          32 :     if (pagetype == LH_META_PAGE)
     128             :     {
     129           4 :         HashMetaPage metap = HashPageGetMeta(page);
     130             : 
     131           4 :         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           4 :         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             :     }
     145             : 
     146          32 :     return page;
     147             : }
     148             : 
     149             : /* -------------------------------------------------
     150             :  * GetHashPageStatistics()
     151             :  *
     152             :  * Collect statistics of single hash page
     153             :  * -------------------------------------------------
     154             :  */
     155             : static void
     156           8 : GetHashPageStatistics(Page page, HashPageStat *stat)
     157             : {
     158           8 :     OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
     159           8 :     HashPageOpaque opaque = HashPageGetOpaque(page);
     160             :     int         off;
     161             : 
     162           8 :     stat->dead_items = stat->live_items = 0;
     163           8 :     stat->page_size = PageGetPageSize(page);
     164             : 
     165             :     /* hash page opaque data */
     166           8 :     stat->hasho_prevblkno = opaque->hasho_prevblkno;
     167           8 :     stat->hasho_nextblkno = opaque->hasho_nextblkno;
     168           8 :     stat->hasho_bucket = opaque->hasho_bucket;
     169           8 :     stat->hasho_flag = opaque->hasho_flag;
     170           8 :     stat->hasho_page_id = opaque->hasho_page_id;
     171             : 
     172             :     /* count live and dead tuples, and free space */
     173          10 :     for (off = FirstOffsetNumber; off <= maxoff; off++)
     174             :     {
     175           2 :         ItemId      id = PageGetItemId(page, off);
     176             : 
     177           2 :         if (!ItemIdIsDead(id))
     178           2 :             stat->live_items++;
     179             :         else
     180           0 :             stat->dead_items++;
     181             :     }
     182           8 :     stat->free_size = PageGetFreeSpace(page);
     183           8 : }
     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          18 : hash_page_type(PG_FUNCTION_ARGS)
     193             : {
     194          18 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     195             :     Page        page;
     196             :     HashPageOpaque opaque;
     197             :     int         pagetype;
     198             :     const char *type;
     199             : 
     200          18 :     if (!superuser())
     201           0 :         ereport(ERROR,
     202             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     203             :                  errmsg("must be superuser to use raw page functions")));
     204             : 
     205          18 :     page = verify_hash_page(raw_page, 0);
     206             : 
     207          14 :     if (PageIsNew(page))
     208           2 :         type = "unused";
     209             :     else
     210             :     {
     211          12 :         opaque = HashPageGetOpaque(page);
     212             : 
     213             :         /* page type (flags) */
     214          12 :         pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
     215          12 :         if (pagetype == LH_META_PAGE)
     216           2 :             type = "metapage";
     217          10 :         else if (pagetype == LH_OVERFLOW_PAGE)
     218           0 :             type = "overflow";
     219          10 :         else if (pagetype == LH_BUCKET_PAGE)
     220           8 :             type = "bucket";
     221           2 :         else if (pagetype == LH_BITMAP_PAGE)
     222           2 :             type = "bitmap";
     223             :         else
     224           0 :             type = "unused";
     225             :     }
     226             : 
     227          14 :     PG_RETURN_TEXT_P(cstring_to_text(type));
     228             : }
     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          18 : hash_page_stats(PG_FUNCTION_ARGS)
     238             : {
     239          18 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     240             :     Page        page;
     241             :     int         j;
     242             :     Datum       values[9];
     243          18 :     bool        nulls[9] = {0};
     244             :     HashPageStat stat;
     245             :     HeapTuple   tuple;
     246             :     TupleDesc   tupleDesc;
     247             : 
     248          18 :     if (!superuser())
     249           0 :         ereport(ERROR,
     250             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     251             :                  errmsg("must be superuser to use raw page functions")));
     252             : 
     253          18 :     page = verify_hash_page(raw_page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
     254             : 
     255             :     /* keep compiler quiet */
     256           8 :     stat.hasho_prevblkno = stat.hasho_nextblkno = InvalidBlockNumber;
     257           8 :     stat.hasho_flag = stat.hasho_page_id = stat.free_size = 0;
     258             : 
     259           8 :     GetHashPageStatistics(page, &stat);
     260             : 
     261             :     /* Build a tuple descriptor for our result type */
     262           8 :     if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
     263           0 :         elog(ERROR, "return type must be a row type");
     264           8 :     tupleDesc = BlessTupleDesc(tupleDesc);
     265             : 
     266           8 :     j = 0;
     267           8 :     values[j++] = Int32GetDatum(stat.live_items);
     268           8 :     values[j++] = Int32GetDatum(stat.dead_items);
     269           8 :     values[j++] = Int32GetDatum(stat.page_size);
     270           8 :     values[j++] = Int32GetDatum(stat.free_size);
     271           8 :     values[j++] = Int64GetDatum((int64) stat.hasho_prevblkno);
     272           8 :     values[j++] = Int64GetDatum((int64) stat.hasho_nextblkno);
     273           8 :     values[j++] = Int64GetDatum((int64) stat.hasho_bucket);
     274           8 :     values[j++] = Int32GetDatum((int32) stat.hasho_flag);
     275           8 :     values[j++] = Int32GetDatum((int32) stat.hasho_page_id);
     276             : 
     277           8 :     tuple = heap_form_tuple(tupleDesc, values, nulls);
     278             : 
     279           8 :     PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
     280             : }
     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          20 : hash_page_items(PG_FUNCTION_ARGS)
     301             : {
     302          20 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     303             :     Page        page;
     304             :     Datum       result;
     305             :     Datum       values[3];
     306          20 :     bool        nulls[3] = {0};
     307             :     uint32      hashkey;
     308             :     HeapTuple   tuple;
     309             :     FuncCallContext *fctx;
     310             :     MemoryContext mctx;
     311             :     struct user_args *uargs;
     312             : 
     313          20 :     if (!superuser())
     314           0 :         ereport(ERROR,
     315             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     316             :                  errmsg("must be superuser to use raw page functions")));
     317             : 
     318          20 :     if (SRF_IS_FIRSTCALL())
     319             :     {
     320             :         TupleDesc   tupleDesc;
     321             : 
     322          18 :         fctx = SRF_FIRSTCALL_INIT();
     323             : 
     324          18 :         mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
     325             : 
     326          18 :         page = verify_hash_page(raw_page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
     327             : 
     328           8 :         uargs = palloc(sizeof(struct user_args));
     329             : 
     330           8 :         uargs->page = page;
     331             : 
     332           8 :         uargs->offset = FirstOffsetNumber;
     333             : 
     334           8 :         fctx->max_calls = PageGetMaxOffsetNumber(uargs->page);
     335             : 
     336             :         /* Build a tuple descriptor for our result type */
     337           8 :         if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
     338           0 :             elog(ERROR, "return type must be a row type");
     339           8 :         tupleDesc = BlessTupleDesc(tupleDesc);
     340             : 
     341           8 :         fctx->attinmeta = TupleDescGetAttInMetadata(tupleDesc);
     342             : 
     343           8 :         fctx->user_fctx = uargs;
     344             : 
     345           8 :         MemoryContextSwitchTo(mctx);
     346             :     }
     347             : 
     348          10 :     fctx = SRF_PERCALL_SETUP();
     349          10 :     uargs = fctx->user_fctx;
     350             : 
     351          10 :     if (fctx->call_cntr < fctx->max_calls)
     352             :     {
     353             :         ItemId      id;
     354             :         IndexTuple  itup;
     355             :         int         j;
     356             : 
     357           2 :         id = PageGetItemId(uargs->page, uargs->offset);
     358             : 
     359           2 :         if (!ItemIdIsValid(id))
     360           0 :             elog(ERROR, "invalid ItemId");
     361             : 
     362           2 :         itup = (IndexTuple) PageGetItem(uargs->page, id);
     363             : 
     364           2 :         j = 0;
     365           2 :         values[j++] = Int32GetDatum((int32) uargs->offset);
     366           2 :         values[j++] = PointerGetDatum(&itup->t_tid);
     367             : 
     368           2 :         hashkey = _hash_get_indextuple_hashkey(itup);
     369           2 :         values[j] = Int64GetDatum((int64) hashkey);
     370             : 
     371           2 :         tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
     372           2 :         result = HeapTupleGetDatum(tuple);
     373             : 
     374           2 :         uargs->offset = uargs->offset + 1;
     375             : 
     376           2 :         SRF_RETURN_NEXT(fctx, result);
     377             :     }
     378             : 
     379           8 :     SRF_RETURN_DONE(fctx);
     380             : }
     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          20 : hash_bitmap_info(PG_FUNCTION_ARGS)
     392             : {
     393          20 :     Oid         indexRelid = PG_GETARG_OID(0);
     394          20 :     int64       ovflblkno = PG_GETARG_INT64(1);
     395             :     HashMetaPage metap;
     396             :     Buffer      metabuf,
     397             :                 mapbuf;
     398             :     BlockNumber bitmapblkno;
     399             :     Page        mappage;
     400          20 :     bool        bit = false;
     401             :     TupleDesc   tupleDesc;
     402             :     Relation    indexRel;
     403             :     uint32      ovflbitno;
     404             :     int32       bitmappage,
     405             :                 bitmapbit;
     406             :     HeapTuple   tuple;
     407             :     int         i,
     408             :                 j;
     409             :     Datum       values[3];
     410          20 :     bool        nulls[3] = {0};
     411             :     uint32     *freep;
     412             : 
     413          20 :     if (!superuser())
     414           0 :         ereport(ERROR,
     415             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     416             :                  errmsg("must be superuser to use raw page functions")));
     417             : 
     418          20 :     indexRel = relation_open(indexRelid, AccessShareLock);
     419             : 
     420          20 :     if (!IS_INDEX(indexRel) || !IS_HASH(indexRel))
     421           4 :         ereport(ERROR,
     422             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     423             :                  errmsg("\"%s\" is not a %s index",
     424             :                         RelationGetRelationName(indexRel), "hash")));
     425             : 
     426          16 :     if (RELATION_IS_OTHER_TEMP(indexRel))
     427           0 :         ereport(ERROR,
     428             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     429             :                  errmsg("cannot access temporary tables of other sessions")));
     430             : 
     431          16 :     if (ovflblkno < 0 || ovflblkno > MaxBlockNumber)
     432           2 :         ereport(ERROR,
     433             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     434             :                  errmsg("invalid block number")));
     435             : 
     436          14 :     if (ovflblkno >= RelationGetNumberOfBlocks(indexRel))
     437           2 :         ereport(ERROR,
     438             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     439             :                  errmsg("block number %lld is out of range for relation \"%s\"",
     440             :                         (long long int) ovflblkno, RelationGetRelationName(indexRel))));
     441             : 
     442             :     /* Read the metapage so we can determine which bitmap page to use */
     443          12 :     metabuf = _hash_getbuf(indexRel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
     444          12 :     metap = HashPageGetMeta(BufferGetPage(metabuf));
     445             : 
     446             :     /*
     447             :      * Reject attempt to read the bit for a metapage or bitmap page; this is
     448             :      * only meaningful for overflow pages.
     449             :      */
     450          12 :     if (ovflblkno == 0)
     451           2 :         ereport(ERROR,
     452             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     453             :                  errmsg("invalid overflow block number %u",
     454             :                         (BlockNumber) ovflblkno)));
     455          18 :     for (i = 0; i < metap->hashm_nmaps; i++)
     456          10 :         if (metap->hashm_mapp[i] == ovflblkno)
     457           2 :             ereport(ERROR,
     458             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     459             :                      errmsg("invalid overflow block number %u",
     460             :                             (BlockNumber) ovflblkno)));
     461             : 
     462             :     /*
     463             :      * Identify overflow bit number.  This will error out for primary bucket
     464             :      * pages, and we've already rejected the metapage and bitmap pages above.
     465             :      */
     466           8 :     ovflbitno = _hash_ovflblkno_to_bitno(metap, (BlockNumber) ovflblkno);
     467             : 
     468           0 :     bitmappage = ovflbitno >> BMPG_SHIFT(metap);
     469           0 :     bitmapbit = ovflbitno & BMPG_MASK(metap);
     470             : 
     471           0 :     if (bitmappage >= metap->hashm_nmaps)
     472           0 :         ereport(ERROR,
     473             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     474             :                  errmsg("invalid overflow block number %u",
     475             :                         (BlockNumber) ovflblkno)));
     476             : 
     477           0 :     bitmapblkno = metap->hashm_mapp[bitmappage];
     478             : 
     479           0 :     _hash_relbuf(indexRel, metabuf);
     480             : 
     481             :     /* Check the status of bitmap bit for overflow page */
     482           0 :     mapbuf = _hash_getbuf(indexRel, bitmapblkno, HASH_READ, LH_BITMAP_PAGE);
     483           0 :     mappage = BufferGetPage(mapbuf);
     484           0 :     freep = HashPageGetBitmap(mappage);
     485             : 
     486           0 :     bit = ISSET(freep, bitmapbit) != 0;
     487             : 
     488           0 :     _hash_relbuf(indexRel, mapbuf);
     489           0 :     index_close(indexRel, AccessShareLock);
     490             : 
     491             :     /* Build a tuple descriptor for our result type */
     492           0 :     if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
     493           0 :         elog(ERROR, "return type must be a row type");
     494           0 :     tupleDesc = BlessTupleDesc(tupleDesc);
     495             : 
     496           0 :     j = 0;
     497           0 :     values[j++] = Int64GetDatum((int64) bitmapblkno);
     498           0 :     values[j++] = Int32GetDatum(bitmapbit);
     499           0 :     values[j++] = BoolGetDatum(bit);
     500             : 
     501           0 :     tuple = heap_form_tuple(tupleDesc, values, nulls);
     502             : 
     503           0 :     PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
     504             : }
     505             : 
     506             : /* ------------------------------------------------
     507             :  * hash_metapage_info()
     508             :  *
     509             :  * Get the meta-page information for a hash index
     510             :  *
     511             :  * Usage: SELECT * FROM hash_metapage_info(get_raw_page('con_hash_index', 0))
     512             :  * ------------------------------------------------
     513             :  */
     514             : Datum
     515          18 : hash_metapage_info(PG_FUNCTION_ARGS)
     516             : {
     517          18 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     518             :     Page        page;
     519             :     HashMetaPageData *metad;
     520             :     TupleDesc   tupleDesc;
     521             :     HeapTuple   tuple;
     522             :     int         i,
     523             :                 j;
     524             :     Datum       values[16];
     525          18 :     bool        nulls[16] = {0};
     526             :     Datum       spares[HASH_MAX_SPLITPOINTS];
     527             :     Datum       mapp[HASH_MAX_BITMAPS];
     528             : 
     529          18 :     if (!superuser())
     530           0 :         ereport(ERROR,
     531             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     532             :                  errmsg("must be superuser to use raw page functions")));
     533             : 
     534          18 :     page = verify_hash_page(raw_page, LH_META_PAGE);
     535             : 
     536             :     /* Build a tuple descriptor for our result type */
     537           2 :     if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
     538           0 :         elog(ERROR, "return type must be a row type");
     539           2 :     tupleDesc = BlessTupleDesc(tupleDesc);
     540             : 
     541           2 :     metad = HashPageGetMeta(page);
     542             : 
     543           2 :     j = 0;
     544           2 :     values[j++] = Int64GetDatum((int64) metad->hashm_magic);
     545           2 :     values[j++] = Int64GetDatum((int64) metad->hashm_version);
     546           2 :     values[j++] = Float8GetDatum(metad->hashm_ntuples);
     547           2 :     values[j++] = Int32GetDatum((int32) metad->hashm_ffactor);
     548           2 :     values[j++] = Int32GetDatum((int32) metad->hashm_bsize);
     549           2 :     values[j++] = Int32GetDatum((int32) metad->hashm_bmsize);
     550           2 :     values[j++] = Int32GetDatum((int32) metad->hashm_bmshift);
     551           2 :     values[j++] = Int64GetDatum((int64) metad->hashm_maxbucket);
     552           2 :     values[j++] = Int64GetDatum((int64) metad->hashm_highmask);
     553           2 :     values[j++] = Int64GetDatum((int64) metad->hashm_lowmask);
     554           2 :     values[j++] = Int64GetDatum((int64) metad->hashm_ovflpoint);
     555           2 :     values[j++] = Int64GetDatum((int64) metad->hashm_firstfree);
     556           2 :     values[j++] = Int64GetDatum((int64) metad->hashm_nmaps);
     557           2 :     values[j++] = ObjectIdGetDatum((Oid) metad->hashm_procid);
     558             : 
     559         198 :     for (i = 0; i < HASH_MAX_SPLITPOINTS; i++)
     560         196 :         spares[i] = Int64GetDatum((int64) metad->hashm_spares[i]);
     561           2 :     values[j++] = PointerGetDatum(construct_array_builtin(spares, HASH_MAX_SPLITPOINTS, INT8OID));
     562             : 
     563        2050 :     for (i = 0; i < HASH_MAX_BITMAPS; i++)
     564        2048 :         mapp[i] = Int64GetDatum((int64) metad->hashm_mapp[i]);
     565           2 :     values[j++] = PointerGetDatum(construct_array_builtin(mapp, HASH_MAX_BITMAPS, INT8OID));
     566             : 
     567           2 :     tuple = heap_form_tuple(tupleDesc, values, nulls);
     568             : 
     569           2 :     PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
     570             : }

Generated by: LCOV version 1.14