LCOV - differential code coverage report
Current view: top level - contrib/pageinspect - hashfuncs.c (source / functions) Coverage Total Hit LBC UIC UBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 79.9 % 209 167 4 14 24 46 6 115 16 41 2 7
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 12 12 3 1 8 3
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a