LCOV - differential code coverage report
Current view: top level - contrib/pageinspect - brinfuncs.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 86.2 % 167 144 1 7 15 2 38 2 102 6 38 3
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 9 9 2 1 6 2
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (120,180] days: 100.0 % 1 1 1
Legend: Lines: hit not hit (240..) days: 86.1 % 166 143 1 7 15 2 38 2 101 6 38
Function coverage date bins:
(240..) days: 81.8 % 11 9 2 1 6 2

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*
                                  2                 :  * brinfuncs.c
                                  3                 :  *      Functions to investigate BRIN indexes
                                  4                 :  *
                                  5                 :  * Copyright (c) 2014-2023, PostgreSQL Global Development Group
                                  6                 :  *
                                  7                 :  * IDENTIFICATION
                                  8                 :  *      contrib/pageinspect/brinfuncs.c
                                  9                 :  */
                                 10                 : #include "postgres.h"
                                 11                 : 
                                 12                 : #include "access/brin.h"
                                 13                 : #include "access/brin_internal.h"
                                 14                 : #include "access/brin_page.h"
                                 15                 : #include "access/brin_revmap.h"
                                 16                 : #include "access/brin_tuple.h"
                                 17                 : #include "access/htup_details.h"
                                 18                 : #include "catalog/index.h"
                                 19                 : #include "catalog/pg_am_d.h"
                                 20                 : #include "catalog/pg_type.h"
                                 21                 : #include "funcapi.h"
                                 22                 : #include "lib/stringinfo.h"
                                 23                 : #include "miscadmin.h"
                                 24                 : #include "pageinspect.h"
                                 25                 : #include "utils/array.h"
                                 26                 : #include "utils/builtins.h"
                                 27                 : #include "utils/lsyscache.h"
                                 28                 : #include "utils/rel.h"
                                 29                 : 
 3075 alvherre                   30 CBC           7 : PG_FUNCTION_INFO_V1(brin_page_type);
                                 31              18 : PG_FUNCTION_INFO_V1(brin_page_items);
                                 32               8 : PG_FUNCTION_INFO_V1(brin_metapage_info);
                                 33               7 : PG_FUNCTION_INFO_V1(brin_revmap_data);
                                 34                 : 
                                 35                 : #define IS_BRIN(r) ((r)->rd_rel->relam == BRIN_AM_OID)
                                 36                 : 
                                 37                 : typedef struct brin_column_state
                                 38                 : {
                                 39                 :     int         nstored;
                                 40                 :     FmgrInfo    outputFn[FLEXIBLE_ARRAY_MEMBER];
                                 41                 : } brin_column_state;
                                 42                 : 
                                 43                 : 
                                 44                 : static Page verify_brin_page(bytea *raw_page, uint16 type,
                                 45                 :                              const char *strtype);
                                 46                 : 
                                 47                 : Datum
                                 48               5 : brin_page_type(PG_FUNCTION_ARGS)
                                 49                 : {
                                 50               5 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
                                 51                 :     Page        page;
                                 52                 :     char       *type;
                                 53                 : 
 2568                            54               5 :     if (!superuser())
 2568 alvherre                   55 UBC           0 :         ereport(ERROR,
                                 56                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 57                 :                  errmsg("must be superuser to use raw page functions")));
                                 58                 : 
  389 michael                    59 CBC           5 :     page = get_page_from_raw(raw_page);
                                 60                 : 
  360                            61               5 :     if (PageIsNew(page))
                                 62               1 :         PG_RETURN_NULL();
                                 63                 : 
                                 64                 :     /* verify the special space has the expected size */
  378                            65               4 :     if (PageGetSpecialSize(page) != MAXALIGN(sizeof(BrinSpecialSpace)))
  332 tgl                        66               1 :         ereport(ERROR,
                                 67                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 68                 :                  errmsg("input page is not a valid %s page", "BRIN"),
                                 69                 :                  errdetail("Expected special size %d, got %d.",
                                 70                 :                            (int) MAXALIGN(sizeof(BrinSpecialSpace)),
                                 71                 :                            (int) PageGetSpecialSize(page))));
                                 72                 : 
 2952 alvherre                   73               3 :     switch (BrinPageType(page))
                                 74                 :     {
 3075                            75               1 :         case BRIN_PAGETYPE_META:
                                 76               1 :             type = "meta";
                                 77               1 :             break;
                                 78               1 :         case BRIN_PAGETYPE_REVMAP:
                                 79               1 :             type = "revmap";
                                 80               1 :             break;
                                 81               1 :         case BRIN_PAGETYPE_REGULAR:
                                 82               1 :             type = "regular";
                                 83               1 :             break;
 3075 alvherre                   84 UBC           0 :         default:
 2952                            85               0 :             type = psprintf("unknown (%02x)", BrinPageType(page));
 3075                            86               0 :             break;
                                 87                 :     }
                                 88                 : 
 3075 alvherre                   89 CBC           3 :     PG_RETURN_TEXT_P(cstring_to_text(type));
                                 90                 : }
                                 91                 : 
                                 92                 : /*
                                 93                 :  * Verify that the given bytea contains a BRIN page of the indicated page
                                 94                 :  * type, or die in the attempt.  A pointer to the page is returned.
                                 95                 :  */
                                 96                 : static Page
                                 97              29 : verify_brin_page(bytea *raw_page, uint16 type, const char *strtype)
                                 98                 : {
  389 michael                    99              29 :     Page        page = get_page_from_raw(raw_page);
                                100                 : 
  360                           101              29 :     if (PageIsNew(page))
                                102               3 :         return page;
                                103                 : 
                                104                 :     /* verify the special space has the expected size */
  378                           105              26 :     if (PageGetSpecialSize(page) != MAXALIGN(sizeof(BrinSpecialSpace)))
  332 tgl                       106               3 :         ereport(ERROR,
                                107                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                108                 :                  errmsg("input page is not a valid %s page", "BRIN"),
                                109                 :                  errdetail("Expected special size %d, got %d.",
                                110                 :                            (int) MAXALIGN(sizeof(BrinSpecialSpace)),
                                111                 :                            (int) PageGetSpecialSize(page))));
                                112                 : 
                                113                 :     /* verify the special space says this page is what we want */
 2952 alvherre                  114              23 :     if (BrinPageType(page) != type)
 3075                           115               2 :         ereport(ERROR,
                                116                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                117                 :                  errmsg("page is not a BRIN page of type \"%s\"", strtype),
                                118                 :                  errdetail("Expected special type %08x, got %08x.",
                                119                 :                            type, BrinPageType(page))));
                                120                 : 
                                121              21 :     return page;
                                122                 : }
                                123                 : 
                                124                 : 
                                125                 : /*
                                126                 :  * Extract all item values from a BRIN index page
                                127                 :  *
                                128                 :  * Usage: SELECT * FROM brin_page_items(get_raw_page('idx', 1), 'idx'::regclass);
                                129                 :  */
                                130                 : Datum
                                131              12 : brin_page_items(PG_FUNCTION_ARGS)
                                132                 : {
 2796                           133              12 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
                                134              12 :     Oid         indexRelid = PG_GETARG_OID(1);
                                135              12 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
                                136                 :     Relation    indexRel;
                                137                 :     brin_column_state **columns;
                                138                 :     BrinDesc   *bdesc;
                                139                 :     BrinMemTuple *dtup;
                                140                 :     Page        page;
                                141                 :     OffsetNumber offset;
                                142                 :     AttrNumber  attno;
                                143                 :     bool        unusedItem;
                                144                 : 
 3075                           145              12 :     if (!superuser())
 3075 alvherre                  146 UBC           0 :         ereport(ERROR,
                                147                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                148                 :                  errmsg("must be superuser to use raw page functions")));
                                149                 : 
  173 michael                   150 CBC          12 :     InitMaterializedSRF(fcinfo, 0);
                                151                 : 
 2796 alvherre                  152              12 :     indexRel = index_open(indexRelid, AccessShareLock);
                                153                 : 
  389 michael                   154              12 :     if (!IS_BRIN(indexRel))
                                155               1 :         ereport(ERROR,
                                156                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                157                 :                  errmsg("\"%s\" is not a %s index",
                                158                 :                         RelationGetRelationName(indexRel), "BRIN")));
                                159                 : 
 2796 alvherre                  160              11 :     bdesc = brin_build_desc(indexRel);
                                161                 : 
                                162                 :     /* minimally verify the page we got */
                                163              11 :     page = verify_brin_page(raw_page, BRIN_PAGETYPE_REGULAR, "regular");
                                164                 : 
  360 michael                   165              10 :     if (PageIsNew(page))
                                166                 :     {
                                167               1 :         brin_free_desc(bdesc);
                                168               1 :         index_close(indexRel, AccessShareLock);
                                169               1 :         PG_RETURN_NULL();
                                170                 :     }
                                171                 : 
                                172                 :     /*
                                173                 :      * Initialize output functions for all indexed datatypes; simplifies
                                174                 :      * calling them later.
                                175                 :      */
 2796 alvherre                  176               9 :     columns = palloc(sizeof(brin_column_state *) * RelationGetDescr(indexRel)->natts);
                                177              18 :     for (attno = 1; attno <= bdesc->bd_tupdesc->natts; attno++)
                                178                 :     {
                                179                 :         Oid         output;
                                180                 :         bool        isVarlena;
                                181                 :         BrinOpcInfo *opcinfo;
                                182                 :         int         i;
                                183                 :         brin_column_state *column;
                                184                 : 
                                185               9 :         opcinfo = bdesc->bd_info[attno - 1];
                                186               9 :         column = palloc(offsetof(brin_column_state, outputFn) +
                                187               9 :                         sizeof(FmgrInfo) * opcinfo->oi_nstored);
                                188                 : 
                                189               9 :         column->nstored = opcinfo->oi_nstored;
                                190              27 :         for (i = 0; i < opcinfo->oi_nstored; i++)
                                191                 :         {
                                192              18 :             getTypeOutputInfo(opcinfo->oi_typcache[i]->type_id, &output, &isVarlena);
                                193              18 :             fmgr_info(output, &column->outputFn[i]);
                                194                 :         }
                                195                 : 
                                196               9 :         columns[attno - 1] = column;
                                197                 :     }
                                198                 : 
                                199               9 :     offset = FirstOffsetNumber;
                                200               9 :     unusedItem = false;
                                201               9 :     dtup = NULL;
                                202                 :     for (;;)
 3075                           203               8 :     {
                                204                 :         Datum       values[7];
  267 peter                     205 GNC          17 :         bool        nulls[7] = {0};
                                206                 : 
                                207                 :         /*
                                208                 :          * This loop is called once for every attribute of every tuple in the
                                209                 :          * page.  At the start of a tuple, we get a NULL dtup; that's our
                                210                 :          * signal for obtaining and decoding the next one.  If that's not the
                                211                 :          * case, we output the next attribute.
                                212                 :          */
 2796 alvherre                  213 CBC          17 :         if (dtup == NULL)
                                214                 :         {
                                215                 :             ItemId      itemId;
                                216                 : 
                                217                 :             /* verify item status: if there's no data, we can't decode */
                                218              17 :             itemId = PageGetItemId(page, offset);
 3075                           219              17 :             if (ItemIdIsUsed(itemId))
                                220                 :             {
 2796                           221              17 :                 dtup = brin_deform_tuple(bdesc,
 2118 tgl                       222              17 :                                          (BrinTuple *) PageGetItem(page, itemId),
                                223                 :                                          NULL);
 2796 alvherre                  224              17 :                 attno = 1;
                                225              17 :                 unusedItem = false;
                                226                 :             }
                                227                 :             else
 2796 alvherre                  228 UBC           0 :                 unusedItem = true;
                                229                 :         }
                                230                 :         else
                                231               0 :             attno++;
                                232                 : 
 2796 alvherre                  233 GBC          17 :         if (unusedItem)
 3075 alvherre                  234 EUB             :         {
 2796 alvherre                  235 UBC           0 :             values[0] = UInt16GetDatum(offset);
 3075                           236               0 :             nulls[1] = true;
                                237               0 :             nulls[2] = true;
                                238               0 :             nulls[3] = true;
                                239               0 :             nulls[4] = true;
 3075 alvherre                  240 UIC           0 :             nulls[5] = true;
                                241               0 :             nulls[6] = true;
                                242                 :         }
 3075 alvherre                  243 ECB             :         else
                                244                 :         {
 2796 alvherre                  245 CBC          17 :             int         att = attno - 1;
 2796 alvherre                  246 ECB             : 
 2796 alvherre                  247 GIC          17 :             values[0] = UInt16GetDatum(offset);
  397 michael                   248 CBC          17 :             switch (TupleDescAttr(rsinfo->setDesc, 1)->atttypid)
  810 peter                     249 ECB             :             {
  810 peter                     250 CBC          17 :                 case INT8OID:
  810 peter                     251 GBC          17 :                     values[1] = Int64GetDatum((int64) dtup->bt_blkno);
  810 peter                     252 GIC          17 :                     break;
  810 peter                     253 UBC           0 :                 case INT4OID:
  810 peter                     254 EUB             :                     /* support for old extension version */
  810 peter                     255 UBC           0 :                     values[1] = UInt32GetDatum(dtup->bt_blkno);
                                256               0 :                     break;
  810 peter                     257 UIC           0 :                 default:
  810 peter                     258 LBC           0 :                     elog(ERROR, "incorrect output types");
  810 peter                     259 ECB             :             }
 2796 alvherre                  260 CBC          17 :             values[2] = UInt16GetDatum(attno);
                                261              17 :             values[3] = BoolGetDatum(dtup->bt_columns[att].bv_allnulls);
                                262              17 :             values[4] = BoolGetDatum(dtup->bt_columns[att].bv_hasnulls);
 2796 alvherre                  263 GIC          17 :             values[5] = BoolGetDatum(dtup->bt_placeholder);
 2796 alvherre                  264 CBC          17 :             if (!dtup->bt_columns[att].bv_allnulls)
                                265                 :             {
 2796 alvherre                  266 GIC          16 :                 BrinValues *bvalues = &dtup->bt_columns[att];
                                267                 :                 StringInfoData s;
                                268                 :                 bool        first;
 3075 alvherre                  269 ECB             :                 int         i;
                                270                 : 
 3075 alvherre                  271 GIC          16 :                 initStringInfo(&s);
 3075 alvherre                  272 CBC          16 :                 appendStringInfoChar(&s, '{');
 3075 alvherre                  273 ECB             : 
 3075 alvherre                  274 GIC          16 :                 first = true;
 2796                           275              48 :                 for (i = 0; i < columns[att]->nstored; i++)
                                276                 :                 {
 2878 bruce                     277 ECB             :                     char       *val;
 3075 alvherre                  278                 : 
 3075 alvherre                  279 CBC          32 :                     if (!first)
                                280              16 :                         appendStringInfoString(&s, " .. ");
                                281              32 :                     first = false;
 2796                           282              32 :                     val = OutputFunctionCall(&columns[att]->outputFn[i],
 3075                           283              32 :                                              bvalues->bv_values[i]);
 3075 alvherre                  284 GIC          32 :                     appendStringInfoString(&s, val);
 3075 alvherre                  285 CBC          32 :                     pfree(val);
                                286                 :                 }
                                287              16 :                 appendStringInfoChar(&s, '}');
 3075 alvherre                  288 ECB             : 
 3075 alvherre                  289 GIC          16 :                 values[6] = CStringGetTextDatum(s.data);
                                290              16 :                 pfree(s.data);
                                291                 :             }
 3075 alvherre                  292 ECB             :             else
                                293                 :             {
 3075 alvherre                  294 GIC           1 :                 nulls[6] = true;
                                295                 :             }
 3075 alvherre                  296 ECB             :         }
                                297                 : 
  397 michael                   298 GIC          17 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
                                299                 : 
                                300                 :         /*
                                301                 :          * If the item was unused, jump straight to the next one; otherwise,
                                302                 :          * the only cleanup needed here is to set our signal to go to the next
 3075 alvherre                  303 ECB             :          * tuple in the following iteration, by freeing the current one.
 3075 alvherre                  304 EUB             :          */
 2796 alvherre                  305 CBC          17 :         if (unusedItem)
 2796 alvherre                  306 UIC           0 :             offset = OffsetNumberNext(offset);
 2796 alvherre                  307 CBC          17 :         else if (attno >= bdesc->bd_tupdesc->natts)
 3075 alvherre                  308 ECB             :         {
 2796 alvherre                  309 CBC          17 :             pfree(dtup);
 2796 alvherre                  310 GIC          17 :             dtup = NULL;
                                311              17 :             offset = OffsetNumberNext(offset);
                                312                 :         }
                                313                 : 
                                314                 :         /*
 2796 alvherre                  315 ECB             :          * If we're beyond the end of the page, we're done.
 3075                           316                 :          */
 2796 alvherre                  317 GIC          17 :         if (offset > PageGetMaxOffsetNumber(page))
                                318               9 :             break;
 3075 alvherre                  319 ECB             :     }
                                320                 : 
 2796 alvherre                  321 GIC           9 :     brin_free_desc(bdesc);
 2796 alvherre                  322 CBC           9 :     index_close(indexRel, AccessShareLock);
                                323                 : 
 2796 alvherre                  324 GIC           9 :     return (Datum) 0;
                                325                 : }
 3075 alvherre                  326 ECB             : 
                                327                 : Datum
 3075 alvherre                  328 CBC          14 : brin_metapage_info(PG_FUNCTION_ARGS)
                                329                 : {
 3075 alvherre                  330 GIC          14 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
                                331                 :     Page        page;
                                332                 :     BrinMetaPageData *meta;
 3075 alvherre                  333 ECB             :     TupleDesc   tupdesc;
                                334                 :     Datum       values[4];
  267 peter                     335 GNC          14 :     bool        nulls[4] = {0};
 3075 alvherre                  336 ECB             :     HeapTuple   htup;
 3075 alvherre                  337 EUB             : 
 2568 alvherre                  338 GIC          14 :     if (!superuser())
 2568 alvherre                  339 UIC           0 :         ereport(ERROR,
                                340                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 1165 alvherre                  341 ECB             :                  errmsg("must be superuser to use raw page functions")));
                                342                 : 
 3075 alvherre                  343 CBC          14 :     page = verify_brin_page(raw_page, BRIN_PAGETYPE_META, "metapage");
 3075 alvherre                  344 ECB             : 
  360 michael                   345 GIC          12 :     if (PageIsNew(page))
                                346               1 :         PG_RETURN_NULL();
  360 michael                   347 ECB             : 
 3075 alvherre                  348 EUB             :     /* Build a tuple descriptor for our result type */
 3075 alvherre                  349 CBC          11 :     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
 3075 alvherre                  350 UIC           0 :         elog(ERROR, "return type must be a row type");
 3075 alvherre                  351 GIC          11 :     tupdesc = BlessTupleDesc(tupdesc);
 3075 alvherre                  352 ECB             : 
                                353                 :     /* Extract values from the metapage */
 3075 alvherre                  354 CBC          11 :     meta = (BrinMetaPageData *) PageGetContents(page);
                                355              11 :     values[0] = CStringGetTextDatum(psprintf("0x%08X", meta->brinMagic));
 3075 alvherre                  356 GIC          11 :     values[1] = Int32GetDatum(meta->brinVersion);
 3075 alvherre                  357 CBC          11 :     values[2] = Int32GetDatum(meta->pagesPerRange);
 3075 alvherre                  358 GIC          11 :     values[3] = Int64GetDatum(meta->lastRevmapPage);
 3075 alvherre                  359 ECB             : 
 3075 alvherre                  360 GIC          11 :     htup = heap_form_tuple(tupdesc, values, nulls);
                                361                 : 
                                362              11 :     PG_RETURN_DATUM(HeapTupleGetDatum(htup));
                                363                 : }
                                364                 : 
                                365                 : /*
 3075 alvherre                  366 ECB             :  * Return the TID array stored in a BRIN revmap page
                                367                 :  */
                                368                 : Datum
 3075 alvherre                  369 GIC        1364 : brin_revmap_data(PG_FUNCTION_ARGS)
                                370                 : {
                                371                 :     struct
                                372                 :     {
                                373                 :         ItemPointerData *tids;
                                374                 :         int         idx;
 2878 bruce                     375 ECB             :     }          *state;
 3075 alvherre                  376 EUB             :     FuncCallContext *fctx;
                                377                 : 
 3075 alvherre                  378 GIC        1364 :     if (!superuser())
 3075 alvherre                  379 UIC           0 :         ereport(ERROR,
 3075 alvherre                  380 ECB             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                381                 :                  errmsg("must be superuser to use raw page functions")));
                                382                 : 
 3075 alvherre                  383 GIC        1364 :     if (SRF_IS_FIRSTCALL())
                                384                 :     {
                                385               4 :         bytea      *raw_page = PG_GETARG_BYTEA_P(0);
                                386                 :         MemoryContext mctx;
 3075 alvherre                  387 ECB             :         Page        page;
                                388                 : 
                                389                 :         /* create a function context for cross-call persistence */
 3075 alvherre                  390 CBC           4 :         fctx = SRF_FIRSTCALL_INIT();
                                391                 : 
                                392                 :         /* switch to memory context appropriate for multiple function calls */
                                393               4 :         mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
                                394                 : 
  389 michael                   395 ECB             :         /* minimally verify the page we got */
  389 michael                   396 GIC           4 :         page = verify_brin_page(raw_page, BRIN_PAGETYPE_REVMAP, "revmap");
  389 michael                   397 ECB             : 
  360 michael                   398 CBC           2 :         if (PageIsNew(page))
                                399                 :         {
  360 michael                   400 GIC           1 :             MemoryContextSwitchTo(mctx);
  360 michael                   401 CBC           1 :             PG_RETURN_NULL();
  360 michael                   402 ECB             :         }
                                403                 : 
 3075 alvherre                  404 GIC           1 :         state = palloc(sizeof(*state));
 3075 alvherre                  405 CBC           1 :         state->tids = ((RevmapContents *) PageGetContents(page))->rm_tids;
 3075 alvherre                  406 GIC           1 :         state->idx = 0;
 3075 alvherre                  407 ECB             : 
 3075 alvherre                  408 GIC           1 :         fctx->user_fctx = state;
                                409                 : 
 3075 alvherre                  410 CBC           1 :         MemoryContextSwitchTo(mctx);
 3075 alvherre                  411 ECB             :     }
                                412                 : 
 3075 alvherre                  413 CBC        1361 :     fctx = SRF_PERCALL_SETUP();
                                414            1361 :     state = fctx->user_fctx;
                                415                 : 
                                416            1361 :     if (state->idx < REVMAP_PAGE_MAXITEMS)
 3075 alvherre                  417 GIC        1360 :         SRF_RETURN_NEXT(fctx, PointerGetDatum(&state->tids[state->idx++]));
                                418                 : 
                                419               1 :     SRF_RETURN_DONE(fctx);
                                420                 : }
        

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