LCOV - code coverage report
Current view: top level - contrib/pageinspect - hashfuncs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 79.9 % 209 167
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 12 12
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 51.4 % 146 75

             Branch data     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                 :           8 : PG_FUNCTION_INFO_V1(hash_page_type);
      26                 :           8 : PG_FUNCTION_INFO_V1(hash_page_stats);
      27                 :           8 : PG_FUNCTION_INFO_V1(hash_page_items);
      28                 :           8 : PG_FUNCTION_INFO_V1(hash_bitmap_info);
      29                 :           8 : 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                 :          36 : verify_hash_page(bytea *raw_page, int flags)
      60                 :             : {
      61                 :          36 :     Page        page = get_page_from_raw(raw_page);
      62                 :          32 :     int         pagetype = LH_UNUSED_PAGE;
      63                 :             : 
      64                 :             :     /* Treat new pages as unused. */
      65         [ +  + ]:          32 :     if (!PageIsNew(page))
      66                 :             :     {
      67                 :             :         HashPageOpaque pageopaque;
      68                 :             : 
      69         [ +  + ]:          28 :         if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData)))
      70         [ +  - ]:           4 :             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                 :          24 :         pageopaque = HashPageGetOpaque(page);
      78         [ -  + ]:          24 :         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                 :          24 :         pagetype = pageopaque->hasho_flag & LH_PAGE_TYPE;
      86                 :             :     }
      87                 :             : 
      88                 :             :     /* Check that page type is sane. */
      89   [ +  -  +  +  :          28 :     if (pagetype != LH_OVERFLOW_PAGE && pagetype != LH_BUCKET_PAGE &&
                   +  + ]
      90   [ +  +  -  + ]:           8 :         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   [ +  +  +  + ]:          28 :     if (flags != 0 && (pagetype & flags) == 0)
      98                 :             :     {
      99   [ +  +  -  - ]:          12 :         switch (flags)
     100                 :             :         {
     101                 :           6 :             case LH_META_PAGE:
     102         [ +  - ]:           6 :                 ereport(ERROR,
     103                 :             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     104                 :             :                          errmsg("page is not a hash meta page")));
     105                 :             :                 break;
     106                 :           6 :             case LH_BUCKET_PAGE | LH_OVERFLOW_PAGE:
     107         [ +  - ]:           6 :                 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                 :             :     }
     123                 :             : 
     124                 :             :     /*
     125                 :             :      * If it is the metapage, also verify magic number and version.
     126                 :             :      */
     127         [ +  + ]:          16 :     if (pagetype == LH_META_PAGE)
     128                 :             :     {
     129                 :           2 :         HashMetaPage metap = HashPageGetMeta(page);
     130                 :             : 
     131         [ -  + ]:           2 :         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         [ -  + ]:           2 :         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                 :          16 :     return page;
     147                 :             : }
     148                 :             : 
     149                 :             : /* -------------------------------------------------
     150                 :             :  * GetHashPageStatistics()
     151                 :             :  *
     152                 :             :  * Collect statistics of single hash page
     153                 :             :  * -------------------------------------------------
     154                 :             :  */
     155                 :             : static void
     156                 :           4 : GetHashPageStatistics(Page page, HashPageStat *stat)
     157                 :             : {
     158                 :           4 :     OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
     159                 :           4 :     HashPageOpaque opaque = HashPageGetOpaque(page);
     160                 :             :     int         off;
     161                 :             : 
     162                 :           4 :     stat->dead_items = stat->live_items = 0;
     163                 :           4 :     stat->page_size = PageGetPageSize(page);
     164                 :             : 
     165                 :             :     /* hash page opaque data */
     166                 :           4 :     stat->hasho_prevblkno = opaque->hasho_prevblkno;
     167                 :           4 :     stat->hasho_nextblkno = opaque->hasho_nextblkno;
     168                 :           4 :     stat->hasho_bucket = opaque->hasho_bucket;
     169                 :           4 :     stat->hasho_flag = opaque->hasho_flag;
     170                 :           4 :     stat->hasho_page_id = opaque->hasho_page_id;
     171                 :             : 
     172                 :             :     /* count live and dead tuples, and free space */
     173         [ +  + ]:           5 :     for (off = FirstOffsetNumber; off <= maxoff; off++)
     174                 :             :     {
     175                 :           1 :         ItemId      id = PageGetItemId(page, off);
     176                 :             : 
     177         [ +  - ]:           1 :         if (!ItemIdIsDead(id))
     178                 :           1 :             stat->live_items++;
     179                 :             :         else
     180                 :           0 :             stat->dead_items++;
     181                 :             :     }
     182                 :           4 :     stat->free_size = PageGetFreeSpace(page);
     183                 :           4 : }
     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                 :           9 : hash_page_type(PG_FUNCTION_ARGS)
     193                 :             : {
     194                 :           9 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     195                 :             :     Page        page;
     196                 :             :     HashPageOpaque opaque;
     197                 :             :     int         pagetype;
     198                 :             :     const char *type;
     199                 :             : 
     200         [ -  + ]:           9 :     if (!superuser())
     201         [ #  # ]:           0 :         ereport(ERROR,
     202                 :             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     203                 :             :                  errmsg("must be superuser to use raw page functions")));
     204                 :             : 
     205                 :           9 :     page = verify_hash_page(raw_page, 0);
     206                 :             : 
     207         [ +  + ]:           7 :     if (PageIsNew(page))
     208                 :           1 :         type = "unused";
     209                 :             :     else
     210                 :             :     {
     211                 :           6 :         opaque = HashPageGetOpaque(page);
     212                 :             : 
     213                 :             :         /* page type (flags) */
     214                 :           6 :         pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
     215         [ +  + ]:           6 :         if (pagetype == LH_META_PAGE)
     216                 :           1 :             type = "metapage";
     217         [ -  + ]:           5 :         else if (pagetype == LH_OVERFLOW_PAGE)
     218                 :           0 :             type = "overflow";
     219         [ +  + ]:           5 :         else if (pagetype == LH_BUCKET_PAGE)
     220                 :           4 :             type = "bucket";
     221         [ +  - ]:           1 :         else if (pagetype == LH_BITMAP_PAGE)
     222                 :           1 :             type = "bitmap";
     223                 :             :         else
     224                 :           0 :             type = "unused";
     225                 :             :     }
     226                 :             : 
     227                 :           7 :     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                 :           9 : hash_page_stats(PG_FUNCTION_ARGS)
     238                 :             : {
     239                 :           9 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     240                 :             :     Page        page;
     241                 :             :     int         j;
     242                 :             :     Datum       values[9];
     243                 :           9 :     bool        nulls[9] = {0};
     244                 :             :     HashPageStat stat;
     245                 :             :     HeapTuple   tuple;
     246                 :             :     TupleDesc   tupleDesc;
     247                 :             : 
     248         [ -  + ]:           9 :     if (!superuser())
     249         [ #  # ]:           0 :         ereport(ERROR,
     250                 :             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     251                 :             :                  errmsg("must be superuser to use raw page functions")));
     252                 :             : 
     253                 :           9 :     page = verify_hash_page(raw_page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
     254                 :             : 
     255                 :             :     /* keep compiler quiet */
     256                 :           4 :     stat.hasho_prevblkno = stat.hasho_nextblkno = InvalidBlockNumber;
     257                 :           4 :     stat.hasho_flag = stat.hasho_page_id = stat.free_size = 0;
     258                 :             : 
     259                 :           4 :     GetHashPageStatistics(page, &stat);
     260                 :             : 
     261                 :             :     /* Build a tuple descriptor for our result type */
     262         [ -  + ]:           4 :     if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
     263         [ #  # ]:           0 :         elog(ERROR, "return type must be a row type");
     264                 :           4 :     tupleDesc = BlessTupleDesc(tupleDesc);
     265                 :             : 
     266                 :           4 :     j = 0;
     267                 :           4 :     values[j++] = Int32GetDatum(stat.live_items);
     268                 :           4 :     values[j++] = Int32GetDatum(stat.dead_items);
     269                 :           4 :     values[j++] = Int32GetDatum(stat.page_size);
     270                 :           4 :     values[j++] = Int32GetDatum(stat.free_size);
     271                 :           4 :     values[j++] = Int64GetDatum((int64) stat.hasho_prevblkno);
     272                 :           4 :     values[j++] = Int64GetDatum((int64) stat.hasho_nextblkno);
     273                 :           4 :     values[j++] = Int64GetDatum((int64) stat.hasho_bucket);
     274                 :           4 :     values[j++] = Int32GetDatum((int32) stat.hasho_flag);
     275                 :           4 :     values[j++] = Int32GetDatum((int32) stat.hasho_page_id);
     276                 :             : 
     277                 :           4 :     tuple = heap_form_tuple(tupleDesc, values, nulls);
     278                 :             : 
     279                 :           4 :     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                 :          10 : hash_page_items(PG_FUNCTION_ARGS)
     301                 :             : {
     302                 :          10 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     303                 :             :     Page        page;
     304                 :             :     Datum       result;
     305                 :             :     Datum       values[3];
     306                 :          10 :     bool        nulls[3] = {0};
     307                 :             :     uint32      hashkey;
     308                 :             :     HeapTuple   tuple;
     309                 :             :     FuncCallContext *fctx;
     310                 :             :     MemoryContext mctx;
     311                 :             :     struct user_args *uargs;
     312                 :             : 
     313         [ -  + ]:          10 :     if (!superuser())
     314         [ #  # ]:           0 :         ereport(ERROR,
     315                 :             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     316                 :             :                  errmsg("must be superuser to use raw page functions")));
     317                 :             : 
     318         [ +  + ]:          10 :     if (SRF_IS_FIRSTCALL())
     319                 :             :     {
     320                 :             :         TupleDesc   tupleDesc;
     321                 :             : 
     322                 :           9 :         fctx = SRF_FIRSTCALL_INIT();
     323                 :             : 
     324                 :           9 :         mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
     325                 :             : 
     326                 :           9 :         page = verify_hash_page(raw_page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
     327                 :             : 
     328                 :           4 :         uargs = palloc_object(struct user_args);
     329                 :             : 
     330                 :           4 :         uargs->page = page;
     331                 :             : 
     332                 :           4 :         uargs->offset = FirstOffsetNumber;
     333                 :             : 
     334                 :           4 :         fctx->max_calls = PageGetMaxOffsetNumber(uargs->page);
     335                 :             : 
     336                 :             :         /* Build a tuple descriptor for our result type */
     337         [ -  + ]:           4 :         if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
     338         [ #  # ]:           0 :             elog(ERROR, "return type must be a row type");
     339                 :           4 :         tupleDesc = BlessTupleDesc(tupleDesc);
     340                 :             : 
     341                 :           4 :         fctx->attinmeta = TupleDescGetAttInMetadata(tupleDesc);
     342                 :             : 
     343                 :           4 :         fctx->user_fctx = uargs;
     344                 :             : 
     345                 :           4 :         MemoryContextSwitchTo(mctx);
     346                 :             :     }
     347                 :             : 
     348                 :           5 :     fctx = SRF_PERCALL_SETUP();
     349                 :           5 :     uargs = fctx->user_fctx;
     350                 :             : 
     351         [ +  + ]:           5 :     if (fctx->call_cntr < fctx->max_calls)
     352                 :             :     {
     353                 :             :         ItemId      id;
     354                 :             :         IndexTuple  itup;
     355                 :             :         int         j;
     356                 :             : 
     357                 :           1 :         id = PageGetItemId(uargs->page, uargs->offset);
     358                 :             : 
     359         [ -  + ]:           1 :         if (!ItemIdIsValid(id))
     360         [ #  # ]:           0 :             elog(ERROR, "invalid ItemId");
     361                 :             : 
     362                 :           1 :         itup = (IndexTuple) PageGetItem(uargs->page, id);
     363                 :             : 
     364                 :           1 :         j = 0;
     365                 :           1 :         values[j++] = Int32GetDatum((int32) uargs->offset);
     366                 :           1 :         values[j++] = PointerGetDatum(&itup->t_tid);
     367                 :             : 
     368                 :           1 :         hashkey = _hash_get_indextuple_hashkey(itup);
     369                 :           1 :         values[j] = Int64GetDatum((int64) hashkey);
     370                 :             : 
     371                 :           1 :         tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
     372                 :           1 :         result = HeapTupleGetDatum(tuple);
     373                 :             : 
     374                 :           1 :         uargs->offset = uargs->offset + 1;
     375                 :             : 
     376                 :           1 :         SRF_RETURN_NEXT(fctx, result);
     377                 :             :     }
     378                 :             : 
     379                 :           4 :     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                 :          10 : hash_bitmap_info(PG_FUNCTION_ARGS)
     392                 :             : {
     393                 :          10 :     Oid         indexRelid = PG_GETARG_OID(0);
     394                 :          10 :     int64       ovflblkno = PG_GETARG_INT64(1);
     395                 :             :     HashMetaPage metap;
     396                 :             :     Buffer      metabuf,
     397                 :             :                 mapbuf;
     398                 :             :     BlockNumber bitmapblkno;
     399                 :             :     Page        mappage;
     400                 :          10 :     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                 :          10 :     bool        nulls[3] = {0};
     411                 :             :     uint32     *freep;
     412                 :             : 
     413         [ -  + ]:          10 :     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                 :          10 :     indexRel = relation_open(indexRelid, AccessShareLock);
     423                 :             : 
     424   [ +  +  +  + ]:          10 :     if (!IS_INDEX(indexRel) || !IS_HASH(indexRel))
     425         [ +  - ]:           2 :         ereport(ERROR,
     426                 :             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     427                 :             :                  errmsg("\"%s\" is not a %s index",
     428                 :             :                         RelationGetRelationName(indexRel), "hash")));
     429                 :             : 
     430   [ -  +  -  - ]:           8 :     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   [ +  +  -  + ]:           8 :     if (ovflblkno < 0 || ovflblkno > MaxBlockNumber)
     436         [ +  - ]:           1 :         ereport(ERROR,
     437                 :             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     438                 :             :                  errmsg("invalid block number")));
     439                 :             : 
     440         [ +  + ]:           7 :     if (ovflblkno >= RelationGetNumberOfBlocks(indexRel))
     441         [ +  - ]:           1 :         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                 :           6 :     metabuf = _hash_getbuf(indexRel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
     448                 :           6 :     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         [ +  + ]:           6 :     if (ovflblkno == 0)
     455         [ +  - ]:           1 :         ereport(ERROR,
     456                 :             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     457                 :             :                  errmsg("invalid overflow block number %u",
     458                 :             :                         (BlockNumber) ovflblkno)));
     459         [ +  + ]:           9 :     for (i = 0; i < metap->hashm_nmaps; i++)
     460         [ +  + ]:           5 :         if (metap->hashm_mapp[i] == ovflblkno)
     461         [ +  - ]:           1 :             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                 :           4 :     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                 :             : }
     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                 :           9 : hash_metapage_info(PG_FUNCTION_ARGS)
     520                 :             : {
     521                 :           9 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     522                 :             :     Page        page;
     523                 :             :     HashMetaPageData *metad;
     524                 :             :     TupleDesc   tupleDesc;
     525                 :             :     HeapTuple   tuple;
     526                 :             :     int         i,
     527                 :             :                 j;
     528                 :             :     Datum       values[16];
     529                 :           9 :     bool        nulls[16] = {0};
     530                 :             :     Datum       spares[HASH_MAX_SPLITPOINTS];
     531                 :             :     Datum       mapp[HASH_MAX_BITMAPS];
     532                 :             : 
     533         [ -  + ]:           9 :     if (!superuser())
     534         [ #  # ]:           0 :         ereport(ERROR,
     535                 :             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     536                 :             :                  errmsg("must be superuser to use raw page functions")));
     537                 :             : 
     538                 :           9 :     page = verify_hash_page(raw_page, LH_META_PAGE);
     539                 :             : 
     540                 :             :     /* Build a tuple descriptor for our result type */
     541         [ -  + ]:           1 :     if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
     542         [ #  # ]:           0 :         elog(ERROR, "return type must be a row type");
     543                 :           1 :     tupleDesc = BlessTupleDesc(tupleDesc);
     544                 :             : 
     545                 :           1 :     metad = HashPageGetMeta(page);
     546                 :             : 
     547                 :           1 :     j = 0;
     548                 :           1 :     values[j++] = Int64GetDatum((int64) metad->hashm_magic);
     549                 :           1 :     values[j++] = Int64GetDatum((int64) metad->hashm_version);
     550                 :           1 :     values[j++] = Float8GetDatum(metad->hashm_ntuples);
     551                 :           1 :     values[j++] = Int32GetDatum((int32) metad->hashm_ffactor);
     552                 :           1 :     values[j++] = Int32GetDatum((int32) metad->hashm_bsize);
     553                 :           1 :     values[j++] = Int32GetDatum((int32) metad->hashm_bmsize);
     554                 :           1 :     values[j++] = Int32GetDatum((int32) metad->hashm_bmshift);
     555                 :           1 :     values[j++] = Int64GetDatum((int64) metad->hashm_maxbucket);
     556                 :           1 :     values[j++] = Int64GetDatum((int64) metad->hashm_highmask);
     557                 :           1 :     values[j++] = Int64GetDatum((int64) metad->hashm_lowmask);
     558                 :           1 :     values[j++] = Int64GetDatum((int64) metad->hashm_ovflpoint);
     559                 :           1 :     values[j++] = Int64GetDatum((int64) metad->hashm_firstfree);
     560                 :           1 :     values[j++] = Int64GetDatum((int64) metad->hashm_nmaps);
     561                 :           1 :     values[j++] = ObjectIdGetDatum((Oid) metad->hashm_procid);
     562                 :             : 
     563         [ +  + ]:          99 :     for (i = 0; i < HASH_MAX_SPLITPOINTS; i++)
     564                 :          98 :         spares[i] = Int64GetDatum((int64) metad->hashm_spares[i]);
     565                 :           1 :     values[j++] = PointerGetDatum(construct_array_builtin(spares, HASH_MAX_SPLITPOINTS, INT8OID));
     566                 :             : 
     567         [ +  + ]:        1025 :     for (i = 0; i < HASH_MAX_BITMAPS; i++)
     568                 :        1024 :         mapp[i] = Int64GetDatum((int64) metad->hashm_mapp[i]);
     569                 :           1 :     values[j++] = PointerGetDatum(construct_array_builtin(mapp, HASH_MAX_BITMAPS, INT8OID));
     570                 :             : 
     571                 :           1 :     tuple = heap_form_tuple(tupleDesc, values, nulls);
     572                 :             : 
     573                 :           1 :     PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
     574                 :             : }
        

Generated by: LCOV version 2.0-1