LCOV - differential code coverage report
Current view: top level - contrib/pageinspect - ginfuncs.c (source / functions) Coverage Total Hit LBC UIC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 87.8 % 115 101 10 4 8 55 2 36 6 48 7
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 6 6 6 4 2
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*
       2                 :  * ginfuncs.c
       3                 :  *      Functions to investigate the content of GIN indexes
       4                 :  *
       5                 :  * Copyright (c) 2014-2023, PostgreSQL Global Development Group
       6                 :  *
       7                 :  * IDENTIFICATION
       8                 :  *      contrib/pageinspect/ginfuncs.c
       9                 :  */
      10                 : #include "postgres.h"
      11                 : 
      12                 : #include "access/gin.h"
      13                 : #include "access/gin_private.h"
      14                 : #include "access/htup_details.h"
      15                 : #include "catalog/namespace.h"
      16                 : #include "catalog/pg_type.h"
      17                 : #include "funcapi.h"
      18                 : #include "miscadmin.h"
      19                 : #include "pageinspect.h"
      20                 : #include "utils/array.h"
      21                 : #include "utils/builtins.h"
      22                 : #include "utils/rel.h"
      23                 : 
      24 ECB             : 
      25 GIC           7 : PG_FUNCTION_INFO_V1(gin_metapage_info);
      26               7 : PG_FUNCTION_INFO_V1(gin_page_opaque_info);
      27               7 : PG_FUNCTION_INFO_V1(gin_leafpage_items);
      28 ECB             : 
      29                 : 
      30                 : Datum
      31 GIC           5 : gin_metapage_info(PG_FUNCTION_ARGS)
      32                 : {
      33               5 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
      34                 :     TupleDesc   tupdesc;
      35                 :     Page        page;
      36                 :     GinPageOpaque opaq;
      37                 :     GinMetaPageData *metadata;
      38                 :     HeapTuple   resultTuple;
      39 ECB             :     Datum       values[10];
      40 EUB             :     bool        nulls[10];
      41                 : 
      42 GIC           5 :     if (!superuser())
      43 UIC           0 :         ereport(ERROR,
      44 ECB             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
      45                 :                  errmsg("must be superuser to use raw page functions")));
      46                 : 
      47 CBC           5 :     page = get_page_from_raw(raw_page);
      48                 : 
      49               4 :     if (PageIsNew(page))
      50               1 :         PG_RETURN_NULL();
      51                 : 
      52 GIC           3 :     if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData)))
      53               1 :         ereport(ERROR,
      54                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      55                 :                  errmsg("input page is not a valid GIN metapage"),
      56                 :                  errdetail("Expected special size %d, got %d.",
      57 ECB             :                            (int) MAXALIGN(sizeof(GinPageOpaqueData)),
      58                 :                            (int) PageGetSpecialSize(page))));
      59                 : 
      60 CBC           2 :     opaq = GinPageGetOpaque(page);
      61                 : 
      62 GIC           2 :     if (opaq->flags != GIN_META)
      63               1 :         ereport(ERROR,
      64                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      65                 :                  errmsg("input page is not a GIN metapage"),
      66                 :                  errdetail("Flags %04X, expected %04X",
      67 ECB             :                            opaq->flags, GIN_META)));
      68 EUB             : 
      69                 :     /* Build a tuple descriptor for our result type */
      70 CBC           1 :     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
      71 UIC           0 :         elog(ERROR, "return type must be a row type");
      72 ECB             : 
      73 GIC           1 :     metadata = GinPageGetMeta(page);
      74 ECB             : 
      75 CBC           1 :     memset(nulls, 0, sizeof(nulls));
      76 ECB             : 
      77 CBC           1 :     values[0] = Int64GetDatum(metadata->head);
      78               1 :     values[1] = Int64GetDatum(metadata->tail);
      79 GIC           1 :     values[2] = Int32GetDatum(metadata->tailFreeSize);
      80               1 :     values[3] = Int64GetDatum(metadata->nPendingPages);
      81 CBC           1 :     values[4] = Int64GetDatum(metadata->nPendingHeapTuples);
      82 ECB             : 
      83                 :     /* statistics, updated by VACUUM */
      84 CBC           1 :     values[5] = Int64GetDatum(metadata->nTotalPages);
      85 GIC           1 :     values[6] = Int64GetDatum(metadata->nEntryPages);
      86 CBC           1 :     values[7] = Int64GetDatum(metadata->nDataPages);
      87 GIC           1 :     values[8] = Int64GetDatum(metadata->nEntries);
      88                 : 
      89 CBC           1 :     values[9] = Int32GetDatum(metadata->ginVersion);
      90                 : 
      91 ECB             :     /* Build and return the result tuple. */
      92 GIC           1 :     resultTuple = heap_form_tuple(tupdesc, values, nulls);
      93                 : 
      94               1 :     return HeapTupleGetDatum(resultTuple);
      95                 : }
      96 ECB             : 
      97                 : 
      98                 : Datum
      99 GIC           4 : gin_page_opaque_info(PG_FUNCTION_ARGS)
     100                 : {
     101               4 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     102                 :     TupleDesc   tupdesc;
     103                 :     Page        page;
     104                 :     GinPageOpaque opaq;
     105                 :     HeapTuple   resultTuple;
     106 ECB             :     Datum       values[3];
     107                 :     bool        nulls[3];
     108                 :     Datum       flags[16];
     109 CBC           4 :     int         nflags = 0;
     110 EUB             :     uint16      flagbits;
     111                 : 
     112 GIC           4 :     if (!superuser())
     113 UIC           0 :         ereport(ERROR,
     114 ECB             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     115                 :                  errmsg("must be superuser to use raw page functions")));
     116                 : 
     117 CBC           4 :     page = get_page_from_raw(raw_page);
     118                 : 
     119               3 :     if (PageIsNew(page))
     120               1 :         PG_RETURN_NULL();
     121                 : 
     122 GIC           2 :     if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData)))
     123               1 :         ereport(ERROR,
     124                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     125                 :                  errmsg("input page is not a valid GIN data leaf page"),
     126                 :                  errdetail("Expected special size %d, got %d.",
     127 ECB             :                            (int) MAXALIGN(sizeof(GinPageOpaqueData)),
     128                 :                            (int) PageGetSpecialSize(page))));
     129                 : 
     130 CBC           1 :     opaq = GinPageGetOpaque(page);
     131 EUB             : 
     132                 :     /* Build a tuple descriptor for our result type */
     133 GIC           1 :     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
     134 LBC           0 :         elog(ERROR, "return type must be a row type");
     135 ECB             : 
     136 EUB             :     /* Convert the flags bitmask to an array of human-readable names */
     137 CBC           1 :     flagbits = opaq->flags;
     138               1 :     if (flagbits & GIN_DATA)
     139 LBC           0 :         flags[nflags++] = CStringGetTextDatum("data");
     140 GBC           1 :     if (flagbits & GIN_LEAF)
     141 CBC           1 :         flags[nflags++] = CStringGetTextDatum("leaf");
     142 GBC           1 :     if (flagbits & GIN_DELETED)
     143 LBC           0 :         flags[nflags++] = CStringGetTextDatum("deleted");
     144 GBC           1 :     if (flagbits & GIN_META)
     145 LBC           0 :         flags[nflags++] = CStringGetTextDatum("meta");
     146 GBC           1 :     if (flagbits & GIN_LIST)
     147 LBC           0 :         flags[nflags++] = CStringGetTextDatum("list");
     148 GBC           1 :     if (flagbits & GIN_LIST_FULLROW)
     149 LBC           0 :         flags[nflags++] = CStringGetTextDatum("list_fullrow");
     150 GBC           1 :     if (flagbits & GIN_INCOMPLETE_SPLIT)
     151 LBC           0 :         flags[nflags++] = CStringGetTextDatum("incomplete_split");
     152 GIC           1 :     if (flagbits & GIN_COMPRESSED)
     153 LBC           0 :         flags[nflags++] = CStringGetTextDatum("compressed");
     154 GIC           1 :     flagbits &= ~(GIN_DATA | GIN_LEAF | GIN_DELETED | GIN_META | GIN_LIST |
     155                 :                   GIN_LIST_FULLROW | GIN_INCOMPLETE_SPLIT | GIN_COMPRESSED);
     156 GBC           1 :     if (flagbits)
     157                 :     {
     158                 :         /* any flags we don't recognize are printed in hex */
     159 LBC           0 :         flags[nflags++] = DirectFunctionCall1(to_hex32, Int32GetDatum(flagbits));
     160                 :     }
     161 ECB             : 
     162 CBC           1 :     memset(nulls, 0, sizeof(nulls));
     163 ECB             : 
     164 GIC           1 :     values[0] = Int64GetDatum(opaq->rightlink);
     165               1 :     values[1] = Int32GetDatum(opaq->maxoff);
     166 GNC           1 :     values[2] = PointerGetDatum(construct_array_builtin(flags, nflags, TEXTOID));
     167                 : 
     168                 :     /* Build and return the result tuple. */
     169 GIC           1 :     resultTuple = heap_form_tuple(tupdesc, values, nulls);
     170                 : 
     171               1 :     return HeapTupleGetDatum(resultTuple);
     172                 : }
     173                 : 
     174                 : typedef struct gin_leafpage_items_state
     175                 : {
     176                 :     TupleDesc   tupd;
     177 ECB             :     GinPostingList *seg;
     178                 :     GinPostingList *lastseg;
     179                 : } gin_leafpage_items_state;
     180                 : 
     181                 : Datum
     182 GIC          26 : gin_leafpage_items(PG_FUNCTION_ARGS)
     183 ECB             : {
     184 GBC          26 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
     185                 :     FuncCallContext *fctx;
     186                 :     gin_leafpage_items_state *inter_call_data;
     187                 : 
     188 CBC          26 :     if (!superuser())
     189 UIC           0 :         ereport(ERROR,
     190                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     191                 :                  errmsg("must be superuser to use raw page functions")));
     192                 : 
     193 GIC          26 :     if (SRF_IS_FIRSTCALL())
     194                 :     {
     195 ECB             :         TupleDesc   tupdesc;
     196                 :         MemoryContext mctx;
     197                 :         Page        page;
     198                 :         GinPageOpaque opaq;
     199                 : 
     200 CBC           5 :         fctx = SRF_FIRSTCALL_INIT();
     201 GIC           5 :         mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
     202 ECB             : 
     203 CBC           5 :         page = get_page_from_raw(raw_page);
     204                 : 
     205 GIC           4 :         if (PageIsNew(page))
     206 ECB             :         {
     207 CBC           1 :             MemoryContextSwitchTo(mctx);
     208 GIC           1 :             PG_RETURN_NULL();
     209                 :         }
     210                 : 
     211               3 :         if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData)))
     212               1 :             ereport(ERROR,
     213                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     214 ECB             :                      errmsg("input page is not a valid GIN data leaf page"),
     215                 :                      errdetail("Expected special size %d, got %d.",
     216                 :                                (int) MAXALIGN(sizeof(GinPageOpaqueData)),
     217                 :                                (int) PageGetSpecialSize(page))));
     218                 : 
     219 GIC           2 :         opaq = GinPageGetOpaque(page);
     220               2 :         if (opaq->flags != (GIN_DATA | GIN_LEAF | GIN_COMPRESSED))
     221               1 :             ereport(ERROR,
     222                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     223 ECB             :                      errmsg("input page is not a compressed GIN data leaf page"),
     224                 :                      errdetail("Flags %04X, expected %04X",
     225                 :                                opaq->flags,
     226                 :                                (GIN_DATA | GIN_LEAF | GIN_COMPRESSED))));
     227 EUB             : 
     228 GIC           1 :         inter_call_data = palloc(sizeof(gin_leafpage_items_state));
     229 ECB             : 
     230                 :         /* Build a tuple descriptor for our result type */
     231 CBC           1 :         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
     232 LBC           0 :             elog(ERROR, "return type must be a row type");
     233 ECB             : 
     234 CBC           1 :         inter_call_data->tupd = tupdesc;
     235                 : 
     236               1 :         inter_call_data->seg = GinDataLeafPageGetPostingList(page);
     237 GIC           1 :         inter_call_data->lastseg = (GinPostingList *)
     238 CBC           1 :             (((char *) inter_call_data->seg) +
     239 GIC           1 :              GinDataLeafPageGetPostingListSize(page));
     240                 : 
     241 CBC           1 :         fctx->user_fctx = inter_call_data;
     242 ECB             : 
     243 GIC           1 :         MemoryContextSwitchTo(mctx);
     244 ECB             :     }
     245                 : 
     246 CBC          22 :     fctx = SRF_PERCALL_SETUP();
     247 GIC          22 :     inter_call_data = fctx->user_fctx;
     248                 : 
     249              22 :     if (inter_call_data->seg != inter_call_data->lastseg)
     250                 :     {
     251              21 :         GinPostingList *cur = inter_call_data->seg;
     252                 :         HeapTuple   resultTuple;
     253                 :         Datum       result;
     254                 :         Datum       values[3];
     255                 :         bool        nulls[3];
     256 ECB             :         int         ndecoded,
     257                 :                     i;
     258                 :         ItemPointer tids;
     259                 :         Datum      *tids_datum;
     260                 : 
     261 GIC          21 :         memset(nulls, 0, sizeof(nulls));
     262 ECB             : 
     263 CBC          21 :         values[0] = ItemPointerGetDatum(&cur->first);
     264              21 :         values[1] = UInt16GetDatum(cur->nbytes);
     265 ECB             : 
     266                 :         /* build an array of decoded item pointers */
     267 CBC          21 :         tids = ginPostingListDecode(cur, &ndecoded);
     268              21 :         tids_datum = (Datum *) palloc(ndecoded * sizeof(Datum));
     269 GIC        6082 :         for (i = 0; i < ndecoded; i++)
     270            6061 :             tids_datum[i] = ItemPointerGetDatum(&tids[i]);
     271 GNC          21 :         values[2] = PointerGetDatum(construct_array_builtin(tids_datum, ndecoded, TIDOID));
     272 CBC          21 :         pfree(tids_datum);
     273 GIC          21 :         pfree(tids);
     274                 : 
     275 ECB             :         /* Build and return the result tuple. */
     276 GIC          21 :         resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
     277              21 :         result = HeapTupleGetDatum(resultTuple);
     278                 : 
     279              21 :         inter_call_data->seg = GinNextPostingListSegment(cur);
     280                 : 
     281              21 :         SRF_RETURN_NEXT(fctx, result);
     282                 :     }
     283                 : 
     284               1 :     SRF_RETURN_DONE(fctx);
     285                 : }
        

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