LCOV - differential code coverage report
Current view: top level - contrib/pageinspect - gistfuncs.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 87.0 % 115 100 7 5 3 4 56 1 39 8 53 1
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 7 7 4 3 4
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*
       2                 :  * gistfuncs.c
       3                 :  *      Functions to investigate the content of GiST indexes
       4                 :  *
       5                 :  * Copyright (c) 2014-2023, PostgreSQL Global Development Group
       6                 :  *
       7                 :  * IDENTIFICATION
       8                 :  *      contrib/pageinspect/gistfuncs.c
       9                 :  */
      10                 : #include "postgres.h"
      11                 : 
      12                 : #include "access/gist.h"
      13                 : #include "access/gist_private.h"
      14                 : #include "access/htup.h"
      15                 : #include "access/relation.h"
      16                 : #include "catalog/namespace.h"
      17                 : #include "catalog/pg_am_d.h"
      18                 : #include "funcapi.h"
      19                 : #include "miscadmin.h"
      20                 : #include "pageinspect.h"
      21                 : #include "storage/itemptr.h"
      22                 : #include "utils/array.h"
      23                 : #include "utils/builtins.h"
      24                 : #include "utils/rel.h"
      25                 : #include "utils/pg_lsn.h"
      26                 : #include "utils/varlena.h"
      27                 : 
      28 CBC           7 : PG_FUNCTION_INFO_V1(gist_page_opaque_info);
      29               7 : PG_FUNCTION_INFO_V1(gist_page_items);
      30               7 : PG_FUNCTION_INFO_V1(gist_page_items_bytea);
      31                 : 
      32                 : #define IS_GIST(r) ((r)->rd_rel->relam == GIST_AM_OID)
      33                 : 
      34                 : 
      35                 : static Page verify_gist_page(bytea *raw_page);
      36                 : 
      37                 : /*
      38                 :  * Verify that the given bytea contains a GIST page or die in the attempt.
      39                 :  * A pointer to the page is returned.
      40 ECB             :  */
      41                 : static Page
      42 CBC          16 : verify_gist_page(bytea *raw_page)
      43                 : {
      44 GIC          16 :     Page        page = get_page_from_raw(raw_page);
      45 ECB             :     GISTPageOpaque opaq;
      46                 : 
      47 GIC          13 :     if (PageIsNew(page))
      48               3 :         return page;
      49 ECB             : 
      50                 :     /* verify the special space has the expected size */
      51 GIC          10 :     if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GISTPageOpaqueData)))
      52               2 :         ereport(ERROR,
      53                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      54                 :                  errmsg("input page is not a valid %s page", "GiST"),
      55                 :                  errdetail("Expected special size %d, got %d.",
      56                 :                            (int) MAXALIGN(sizeof(GISTPageOpaqueData)),
      57 ECB             :                            (int) PageGetSpecialSize(page))));
      58                 : 
      59 CBC           8 :     opaq = GistPageGetOpaque(page);
      60 GIC           8 :     if (opaq->gist_page_id != GIST_PAGE_ID)
      61               2 :         ereport(ERROR,
      62                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      63                 :                  errmsg("input page is not a valid %s page", "GiST"),
      64                 :                  errdetail("Expected %08x, got %08x.",
      65                 :                            GIST_PAGE_ID,
      66 ECB             :                            opaq->gist_page_id)));
      67                 : 
      68 GIC           6 :     return page;
      69                 : }
      70 ECB             : 
      71                 : Datum
      72 CBC           6 : gist_page_opaque_info(PG_FUNCTION_ARGS)
      73                 : {
      74 GIC           6 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
      75                 :     TupleDesc   tupdesc;
      76                 :     Page        page;
      77                 :     HeapTuple   resultTuple;
      78                 :     Datum       values[4];
      79 ECB             :     bool        nulls[4];
      80                 :     Datum       flags[16];
      81 GIC           6 :     int         nflags = 0;
      82 ECB             :     uint16      flagbits;
      83 EUB             : 
      84 GIC           6 :     if (!superuser())
      85 UIC           0 :         ereport(ERROR,
      86                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
      87 ECB             :                  errmsg("must be superuser to use raw page functions")));
      88                 : 
      89 CBC           6 :     page = verify_gist_page(raw_page);
      90 ECB             : 
      91 GIC           4 :     if (PageIsNew(page))
      92               1 :         PG_RETURN_NULL();
      93 ECB             : 
      94 EUB             :     /* Build a tuple descriptor for our result type */
      95 GIC           3 :     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
      96 UIC           0 :         elog(ERROR, "return type must be a row type");
      97 ECB             : 
      98                 :     /* Convert the flags bitmask to an array of human-readable names */
      99 CBC           3 :     flagbits = GistPageGetOpaque(page)->flags;
     100               3 :     if (flagbits & F_LEAF)
     101 GBC           2 :         flags[nflags++] = CStringGetTextDatum("leaf");
     102 CBC           3 :     if (flagbits & F_DELETED)
     103 UBC           0 :         flags[nflags++] = CStringGetTextDatum("deleted");
     104 CBC           3 :     if (flagbits & F_TUPLES_DELETED)
     105 UBC           0 :         flags[nflags++] = CStringGetTextDatum("tuples_deleted");
     106 CBC           3 :     if (flagbits & F_FOLLOW_RIGHT)
     107 UBC           0 :         flags[nflags++] = CStringGetTextDatum("follow_right");
     108 CBC           3 :     if (flagbits & F_HAS_GARBAGE)
     109 LBC           0 :         flags[nflags++] = CStringGetTextDatum("has_garbage");
     110 GIC           3 :     flagbits &= ~(F_LEAF | F_DELETED | F_TUPLES_DELETED | F_FOLLOW_RIGHT | F_HAS_GARBAGE);
     111               3 :     if (flagbits)
     112 EUB             :     {
     113                 :         /* any flags we don't recognize are printed in hex */
     114 UIC           0 :         flags[nflags++] = DirectFunctionCall1(to_hex32, Int32GetDatum(flagbits));
     115 ECB             :     }
     116                 : 
     117 CBC           3 :     memset(nulls, 0, sizeof(nulls));
     118 ECB             : 
     119 CBC           3 :     values[0] = LSNGetDatum(PageGetLSN(page));
     120               3 :     values[1] = LSNGetDatum(GistPageGetNSN(page));
     121 GIC           3 :     values[2] = Int64GetDatum(GistPageGetOpaque(page)->rightlink);
     122 GNC           3 :     values[3] = PointerGetDatum(construct_array_builtin(flags, nflags, TEXTOID));
     123 ECB             : 
     124                 :     /* Build and return the result tuple. */
     125 GIC           3 :     resultTuple = heap_form_tuple(tupdesc, values, nulls);
     126                 : 
     127 CBC           3 :     return HeapTupleGetDatum(resultTuple);
     128                 : }
     129 ECB             : 
     130                 : Datum
     131 GIC           5 : gist_page_items_bytea(PG_FUNCTION_ARGS)
     132                 : {
     133 CBC           5 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     134 GIC           5 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
     135 ECB             :     Page        page;
     136 EUB             :     OffsetNumber offset;
     137 GIC           5 :     OffsetNumber maxoff = InvalidOffsetNumber;
     138                 : 
     139               5 :     if (!superuser())
     140 LBC           0 :         ereport(ERROR,
     141                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     142 ECB             :                  errmsg("must be superuser to use raw page functions")));
     143                 : 
     144 CBC           5 :     InitMaterializedSRF(fcinfo, 0);
     145 ECB             : 
     146 GIC           5 :     page = verify_gist_page(raw_page);
     147                 : 
     148 CBC           2 :     if (PageIsNew(page))
     149 GBC           1 :         PG_RETURN_NULL();
     150                 : 
     151 ECB             :     /* Avoid bogus PageGetMaxOffsetNumber() call with deleted pages */
     152 GIC           1 :     if (GistPageIsDeleted(page))
     153 LBC           0 :         elog(NOTICE, "page is deleted");
     154 ECB             :     else
     155 CBC           1 :         maxoff = PageGetMaxOffsetNumber(page);
     156                 : 
     157 GIC           1 :     for (offset = FirstOffsetNumber;
     158               7 :          offset <= maxoff;
     159               6 :          offset++)
     160                 :     {
     161                 :         Datum       values[5];
     162                 :         bool        nulls[5];
     163                 :         ItemId      id;
     164 ECB             :         IndexTuple  itup;
     165                 :         bytea      *tuple_bytea;
     166                 :         int         tuple_len;
     167 EUB             : 
     168 GIC           6 :         id = PageGetItemId(page, offset);
     169 ECB             : 
     170 CBC           6 :         if (!ItemIdIsValid(id))
     171 UIC           0 :             elog(ERROR, "invalid ItemId");
     172 ECB             : 
     173 GIC           6 :         itup = (IndexTuple) PageGetItem(page, id);
     174 CBC           6 :         tuple_len = IndexTupleSize(itup);
     175 ECB             : 
     176 CBC           6 :         memset(nulls, 0, sizeof(nulls));
     177                 : 
     178               6 :         values[0] = DatumGetInt16(offset);
     179               6 :         values[1] = ItemPointerGetDatum(&itup->t_tid);
     180               6 :         values[2] = Int32GetDatum((int) IndexTupleSize(itup));
     181 ECB             : 
     182 CBC           6 :         tuple_bytea = (bytea *) palloc(tuple_len + VARHDRSZ);
     183 GIC           6 :         SET_VARSIZE(tuple_bytea, tuple_len + VARHDRSZ);
     184 CBC           6 :         memcpy(VARDATA(tuple_bytea), itup, tuple_len);
     185 GIC           6 :         values[3] = BoolGetDatum(ItemIdIsDead(id));
     186               6 :         values[4] = PointerGetDatum(tuple_bytea);
     187 ECB             : 
     188 GIC           6 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
     189                 :     }
     190                 : 
     191 CBC           1 :     return (Datum) 0;
     192                 : }
     193 ECB             : 
     194                 : Datum
     195 CBC           6 : gist_page_items(PG_FUNCTION_ARGS)
     196                 : {
     197 GIC           6 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     198               6 :     Oid         indexRelid = PG_GETARG_OID(1);
     199 CBC           6 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
     200                 :     Relation    indexRel;
     201 ECB             :     Page        page;
     202 EUB             :     OffsetNumber offset;
     203 GIC           6 :     OffsetNumber maxoff = InvalidOffsetNumber;
     204                 : 
     205               6 :     if (!superuser())
     206 LBC           0 :         ereport(ERROR,
     207                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     208                 :                  errmsg("must be superuser to use raw page functions")));
     209 ECB             : 
     210 GIC           6 :     InitMaterializedSRF(fcinfo, 0);
     211 ECB             : 
     212                 :     /* Open the relation */
     213 GIC           6 :     indexRel = index_open(indexRelid, AccessShareLock);
     214                 : 
     215               6 :     if (!IS_GIST(indexRel))
     216               1 :         ereport(ERROR,
     217 ECB             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     218                 :                  errmsg("\"%s\" is not a %s index",
     219                 :                         RelationGetRelationName(indexRel), "GiST")));
     220                 : 
     221 CBC           5 :     page = verify_gist_page(raw_page);
     222 ECB             : 
     223 GIC           3 :     if (PageIsNew(page))
     224                 :     {
     225               1 :         index_close(indexRel, AccessShareLock);
     226 CBC           1 :         PG_RETURN_NULL();
     227 EUB             :     }
     228                 : 
     229 ECB             :     /* Avoid bogus PageGetMaxOffsetNumber() call with deleted pages */
     230 GIC           2 :     if (GistPageIsDeleted(page))
     231 LBC           0 :         elog(NOTICE, "page is deleted");
     232 ECB             :     else
     233 CBC           2 :         maxoff = PageGetMaxOffsetNumber(page);
     234                 : 
     235 GIC           2 :     for (offset = FirstOffsetNumber;
     236             193 :          offset <= maxoff;
     237             191 :          offset++)
     238                 :     {
     239                 :         Datum       values[5];
     240                 :         bool        nulls[5];
     241                 :         ItemId      id;
     242                 :         IndexTuple  itup;
     243 ECB             :         Datum       itup_values[INDEX_MAX_KEYS];
     244                 :         bool        itup_isnull[INDEX_MAX_KEYS];
     245                 :         char       *key_desc;
     246 EUB             : 
     247 GIC         191 :         id = PageGetItemId(page, offset);
     248 ECB             : 
     249 GIC         191 :         if (!ItemIdIsValid(id))
     250 LBC           0 :             elog(ERROR, "invalid ItemId");
     251                 : 
     252 GIC         191 :         itup = (IndexTuple) PageGetItem(page, id);
     253 ECB             : 
     254 GIC         191 :         index_deform_tuple(itup, RelationGetDescr(indexRel),
     255 ECB             :                            itup_values, itup_isnull);
     256                 : 
     257 CBC         191 :         memset(nulls, 0, sizeof(nulls));
     258 ECB             : 
     259 GIC         191 :         values[0] = DatumGetInt16(offset);
     260 CBC         191 :         values[1] = ItemPointerGetDatum(&itup->t_tid);
     261             191 :         values[2] = Int32GetDatum((int) IndexTupleSize(itup));
     262             191 :         values[3] = BoolGetDatum(ItemIdIsDead(id));
     263                 : 
     264 GIC         191 :         key_desc = BuildIndexValueDescription(indexRel, itup_values, itup_isnull);
     265 GBC         191 :         if (key_desc)
     266             191 :             values[4] = CStringGetTextDatum(key_desc);
     267                 :         else
     268                 :         {
     269 LBC           0 :             values[4] = (Datum) 0;
     270 UIC           0 :             nulls[4] = true;
     271                 :         }
     272 ECB             : 
     273 GIC         191 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
     274 ECB             :     }
     275                 : 
     276 GIC           2 :     relation_close(indexRel, AccessShareLock);
     277                 : 
     278               2 :     return (Datum) 0;
     279                 : }
        

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