LCOV - differential code coverage report
Current view: top level - contrib/pageinspect - rawpage.c (source / functions) Coverage Total Hit LBC UIC UBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 91.6 % 119 109 3 4 3 21 11 77 7 26 3
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 18 18 5 1 12 5
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 91.6 % 119 109 3 4 3 21 11 77 7 25
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 78.3 % 23 18 5 1 12 5

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * rawpage.c
                                  4                 :  *    Functions to extract a raw page as bytea and inspect it
                                  5                 :  *
                                  6                 :  * Access-method specific inspection functions are in separate files.
                                  7                 :  *
                                  8                 :  * Copyright (c) 2007-2023, PostgreSQL Global Development Group
                                  9                 :  *
                                 10                 :  * IDENTIFICATION
                                 11                 :  *    contrib/pageinspect/rawpage.c
                                 12                 :  *
                                 13                 :  *-------------------------------------------------------------------------
                                 14                 :  */
                                 15                 : 
                                 16                 : #include "postgres.h"
                                 17                 : 
                                 18                 : #include "access/htup_details.h"
                                 19                 : #include "access/relation.h"
                                 20                 : #include "catalog/namespace.h"
                                 21                 : #include "catalog/pg_type.h"
                                 22                 : #include "funcapi.h"
                                 23                 : #include "miscadmin.h"
                                 24                 : #include "pageinspect.h"
                                 25                 : #include "storage/bufmgr.h"
                                 26                 : #include "storage/checksum.h"
                                 27                 : #include "utils/builtins.h"
                                 28                 : #include "utils/pg_lsn.h"
                                 29                 : #include "utils/rel.h"
                                 30                 : #include "utils/varlena.h"
                                 31                 : 
 5806 bruce                      32 CBC          19 : PG_MODULE_MAGIC;
                                 33                 : 
                                 34                 : static bytea *get_raw_page_internal(text *relname, ForkNumber forknum,
                                 35                 :                                     BlockNumber blkno);
                                 36                 : 
                                 37                 : 
                                 38                 : /*
                                 39                 :  * get_raw_page
                                 40                 :  *
                                 41                 :  * Returns a copy of a page from shared buffers as a bytea
                                 42                 :  */
  810 peter                      43              19 : PG_FUNCTION_INFO_V1(get_raw_page_1_9);
                                 44                 : 
                                 45                 : Datum
                                 46              99 : get_raw_page_1_9(PG_FUNCTION_ARGS)
                                 47                 : {
                                 48              99 :     text       *relname = PG_GETARG_TEXT_PP(0);
                                 49              99 :     int64       blkno = PG_GETARG_INT64(1);
                                 50                 :     bytea      *raw_page;
                                 51                 : 
                                 52              99 :     if (blkno < 0 || blkno > MaxBlockNumber)
                                 53               1 :         ereport(ERROR,
                                 54                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 55                 :                  errmsg("invalid block number")));
                                 56                 : 
                                 57              98 :     raw_page = get_raw_page_internal(relname, MAIN_FORKNUM, blkno);
                                 58                 : 
                                 59              93 :     PG_RETURN_BYTEA_P(raw_page);
                                 60                 : }
                                 61                 : 
                                 62                 : /*
                                 63                 :  * entry point for old extension version
                                 64                 :  */
 5806 bruce                      65               7 : PG_FUNCTION_INFO_V1(get_raw_page);
                                 66                 : 
                                 67                 : Datum
                                 68               2 : get_raw_page(PG_FUNCTION_ARGS)
                                 69                 : {
 2219 noah                       70               2 :     text       *relname = PG_GETARG_TEXT_PP(0);
 5053 tgl                        71               2 :     uint32      blkno = PG_GETARG_UINT32(1);
                                 72                 :     bytea      *raw_page;
                                 73                 : 
                                 74                 :     /*
                                 75                 :      * We don't normally bother to check the number of arguments to a C
                                 76                 :      * function, but here it's needed for safety because early 8.4 beta
                                 77                 :      * releases mistakenly redefined get_raw_page() as taking three arguments.
                                 78                 :      */
                                 79               2 :     if (PG_NARGS() != 2)
 5053 tgl                        80 UBC           0 :         ereport(ERROR,
                                 81                 :                 (errmsg("wrong number of arguments to get_raw_page()"),
                                 82                 :                  errhint("Run the updated pageinspect.sql script.")));
                                 83                 : 
 5053 tgl                        84 CBC           2 :     raw_page = get_raw_page_internal(relname, MAIN_FORKNUM, blkno);
                                 85                 : 
                                 86               2 :     PG_RETURN_BYTEA_P(raw_page);
                                 87                 : }
                                 88                 : 
                                 89                 : /*
                                 90                 :  * get_raw_page_fork
                                 91                 :  *
                                 92                 :  * Same, for any fork
                                 93                 :  */
  810 peter                      94               8 : PG_FUNCTION_INFO_V1(get_raw_page_fork_1_9);
                                 95                 : 
                                 96                 : Datum
                                 97              12 : get_raw_page_fork_1_9(PG_FUNCTION_ARGS)
                                 98                 : {
                                 99              12 :     text       *relname = PG_GETARG_TEXT_PP(0);
                                100              12 :     text       *forkname = PG_GETARG_TEXT_PP(1);
                                101              12 :     int64       blkno = PG_GETARG_INT64(2);
                                102                 :     bytea      *raw_page;
                                103                 :     ForkNumber  forknum;
                                104                 : 
                                105              12 :     forknum = forkname_to_number(text_to_cstring(forkname));
                                106                 : 
                                107              11 :     if (blkno < 0 || blkno > MaxBlockNumber)
                                108               1 :         ereport(ERROR,
                                109                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                110                 :                  errmsg("invalid block number")));
                                111                 : 
                                112              10 :     raw_page = get_raw_page_internal(relname, forknum, blkno);
                                113                 : 
                                114               7 :     PG_RETURN_BYTEA_P(raw_page);
                                115                 : }
                                116                 : 
                                117                 : /*
                                118                 :  * Entry point for old extension version
                                119                 :  */
 5053 tgl                       120               7 : PG_FUNCTION_INFO_V1(get_raw_page_fork);
                                121                 : 
                                122                 : Datum
                                123               1 : get_raw_page_fork(PG_FUNCTION_ARGS)
                                124                 : {
 2219 noah                      125               1 :     text       *relname = PG_GETARG_TEXT_PP(0);
                                126               1 :     text       *forkname = PG_GETARG_TEXT_PP(1);
 5304 heikki.linnakangas        127               1 :     uint32      blkno = PG_GETARG_UINT32(2);
                                128                 :     bytea      *raw_page;
                                129                 :     ForkNumber  forknum;
                                130                 : 
 5053 tgl                       131               1 :     forknum = forkname_to_number(text_to_cstring(forkname));
                                132                 : 
                                133               1 :     raw_page = get_raw_page_internal(relname, forknum, blkno);
                                134                 : 
                                135               1 :     PG_RETURN_BYTEA_P(raw_page);
                                136                 : }
                                137                 : 
                                138                 : /*
                                139                 :  * workhorse
                                140                 :  */
                                141                 : static bytea *
                                142             111 : get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
                                143                 : {
                                144                 :     bytea      *raw_page;
                                145                 :     RangeVar   *relrv;
                                146                 :     Relation    rel;
                                147                 :     char       *raw_page_data;
                                148                 :     Buffer      buf;
                                149                 : 
 5806 bruce                     150             111 :     if (!superuser())
 5806 bruce                     151 UBC           0 :         ereport(ERROR,
                                152                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                153                 :                  errmsg("must be superuser to use raw page functions")));
                                154                 : 
 5806 bruce                     155 CBC         111 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
                                156             111 :     rel = relation_openrv(relrv, AccessShareLock);
                                157                 : 
  640 peter                     158             110 :     if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
 5806 bruce                     159               2 :         ereport(ERROR,
                                160                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                161                 :                  errmsg("cannot get raw page from relation \"%s\"",
                                162                 :                         RelationGetRelationName(rel)),
                                163                 :                  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
                                164                 : 
                                165                 :     /*
                                166                 :      * Reject attempts to read non-local temporary relations; we would be
                                167                 :      * likely to get wrong data since we have no visibility into the owning
                                168                 :      * session's local buffers.
                                169                 :      */
 5122 tgl                       170             108 :     if (RELATION_IS_OTHER_TEMP(rel))
 5122 tgl                       171 UBC           0 :         ereport(ERROR,
                                172                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                173                 :                  errmsg("cannot access temporary tables of other sessions")));
                                174                 : 
 3183 tgl                       175 CBC         108 :     if (blkno >= RelationGetNumberOfBlocksInFork(rel, forknum))
                                176               5 :         ereport(ERROR,
                                177                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                178                 :                  errmsg("block number %u is out of range for relation \"%s\"",
                                179                 :                         blkno, RelationGetRelationName(rel))));
                                180                 : 
                                181                 :     /* Initialize buffer to copy to */
 5806 bruce                     182             103 :     raw_page = (bytea *) palloc(BLCKSZ + VARHDRSZ);
                                183             103 :     SET_VARSIZE(raw_page, BLCKSZ + VARHDRSZ);
                                184             103 :     raw_page_data = VARDATA(raw_page);
                                185                 : 
                                186                 :     /* Take a verbatim copy of the page */
                                187                 : 
 5273 heikki.linnakangas        188             103 :     buf = ReadBufferExtended(rel, forknum, blkno, RBM_NORMAL, NULL);
 5806 bruce                     189             103 :     LockBuffer(buf, BUFFER_LOCK_SHARE);
                                190                 : 
 2545 kgrittn                   191             103 :     memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ);
                                192                 : 
 5806 bruce                     193             103 :     LockBuffer(buf, BUFFER_LOCK_UNLOCK);
                                194             103 :     ReleaseBuffer(buf);
                                195                 : 
                                196             103 :     relation_close(rel, AccessShareLock);
                                197                 : 
 5053 tgl                       198             103 :     return raw_page;
                                199                 : }
                                200                 : 
                                201                 : 
                                202                 : /*
                                203                 :  * get_page_from_raw
                                204                 :  *
                                205                 :  * Get a palloc'd, maxalign'ed page image from the result of get_raw_page()
                                206                 :  *
                                207                 :  * On machines with MAXALIGN = 8, the payload of a bytea is not maxaligned,
                                208                 :  * since it will start 4 bytes into a palloc'd value.  On alignment-picky
                                209                 :  * machines, this will cause failures in accesses to 8-byte-wide values
                                210                 :  * within the page.  We don't need to worry if accessing only 4-byte or
                                211                 :  * smaller fields, but when examining a struct that contains 8-byte fields,
                                212                 :  * use this function for safety.
                                213                 :  */
                                214                 : Page
 2256                           215             137 : get_page_from_raw(bytea *raw_page)
                                216                 : {
                                217                 :     Page        page;
                                218                 :     int         raw_page_size;
                                219                 : 
 2219 noah                      220             137 :     raw_page_size = VARSIZE_ANY_EXHDR(raw_page);
                                221                 : 
 2256 tgl                       222             137 :     if (raw_page_size != BLCKSZ)
                                223              14 :         ereport(ERROR,
                                224                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                225                 :                  errmsg("invalid page size"),
                                226                 :                  errdetail("Expected %d bytes, got %d.",
                                227                 :                            BLCKSZ, raw_page_size)));
                                228                 : 
                                229             123 :     page = palloc(raw_page_size);
                                230                 : 
 2219 noah                      231             123 :     memcpy(page, VARDATA_ANY(raw_page), raw_page_size);
                                232                 : 
 2256 tgl                       233             123 :     return page;
                                234                 : }
                                235                 : 
                                236                 : 
                                237                 : /*
                                238                 :  * page_header
                                239                 :  *
                                240                 :  * Allows inspection of page header fields of a raw page
                                241                 :  */
                                242                 : 
 5806 bruce                     243              13 : PG_FUNCTION_INFO_V1(page_header);
                                244                 : 
                                245                 : Datum
                                246               4 : page_header(PG_FUNCTION_ARGS)
                                247                 : {
                                248               4 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
                                249                 : 
                                250                 :     TupleDesc   tupdesc;
                                251                 : 
                                252                 :     Datum       result;
                                253                 :     HeapTuple   tuple;
                                254                 :     Datum       values[9];
                                255                 :     bool        nulls[9];
                                256                 : 
                                257                 :     Page        page;
                                258                 :     PageHeader  pageheader;
                                259                 :     XLogRecPtr  lsn;
                                260                 : 
 5806 bruce                     261 GIC           4 :     if (!superuser())
 5806 bruce                     262 LBC           0 :         ereport(ERROR,
 5806 bruce                     263 EUB             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                264                 :                  errmsg("must be superuser to use raw page functions")));
                                265                 : 
  272 peter                     266 GNC           4 :     page = get_page_from_raw(raw_page);
                                267               3 :     pageheader = (PageHeader) page;
 5806 bruce                     268 ECB             : 
                                269                 :     /* Build a tuple descriptor for our result type */
 5806 bruce                     270 GIC           3 :     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
 5806 bruce                     271 UIC           0 :         elog(ERROR, "return type must be a row type");
 5806 bruce                     272 ECB             : 
 5806 bruce                     273 EUB             :     /* Extract information from the page header */
                                274                 : 
 5806 bruce                     275 GIC           3 :     lsn = PageGetLSN(page);
                                276                 : 
 3324 rhaas                     277 ECB             :     /* pageinspect >= 1.2 uses pg_lsn instead of text for the LSN field. */
 2058 andres                    278 GIC           3 :     if (TupleDescAttr(tupdesc, 0)->atttypid == TEXTOID)
                                279                 :     {
 3260 bruce                     280 ECB             :         char        lsnchar[64];
                                281                 : 
  775 peter                     282 UIC           0 :         snprintf(lsnchar, sizeof(lsnchar), "%X/%X", LSN_FORMAT_ARGS(lsn));
 3324 rhaas                     283               0 :         values[0] = CStringGetTextDatum(lsnchar);
 3324 rhaas                     284 EUB             :     }
                                285                 :     else
 3324 rhaas                     286 GIC           3 :         values[0] = LSNGetDatum(lsn);
  272 peter                     287 GNC           3 :     values[1] = UInt16GetDatum(pageheader->pd_checksum);
                                288               3 :     values[2] = UInt16GetDatum(pageheader->pd_flags);
  636 michael                   289 ECB             : 
                                290                 :     /* pageinspect >= 1.10 uses int4 instead of int2 for those fields */
  636 michael                   291 GIC           3 :     switch (TupleDescAttr(tupdesc, 3)->atttypid)
                                292                 :     {
  636 michael                   293 CBC           1 :         case INT2OID:
  636 michael                   294 GIC           1 :             Assert(TupleDescAttr(tupdesc, 4)->atttypid == INT2OID &&
  636 michael                   295 ECB             :                    TupleDescAttr(tupdesc, 5)->atttypid == INT2OID &&
                                296                 :                    TupleDescAttr(tupdesc, 6)->atttypid == INT2OID);
  272 peter                     297 GNC           1 :             values[3] = UInt16GetDatum(pageheader->pd_lower);
                                298               1 :             values[4] = UInt16GetDatum(pageheader->pd_upper);
                                299               1 :             values[5] = UInt16GetDatum(pageheader->pd_special);
  636 michael                   300 CBC           1 :             values[6] = UInt16GetDatum(PageGetPageSize(page));
                                301               1 :             break;
                                302               2 :         case INT4OID:
                                303               2 :             Assert(TupleDescAttr(tupdesc, 4)->atttypid == INT4OID &&
  636 michael                   304 ECB             :                    TupleDescAttr(tupdesc, 5)->atttypid == INT4OID &&
                                305                 :                    TupleDescAttr(tupdesc, 6)->atttypid == INT4OID);
  272 peter                     306 GNC           2 :             values[3] = Int32GetDatum(pageheader->pd_lower);
                                307               2 :             values[4] = Int32GetDatum(pageheader->pd_upper);
                                308               2 :             values[5] = Int32GetDatum(pageheader->pd_special);
  636 michael                   309 CBC           2 :             values[6] = Int32GetDatum(PageGetPageSize(page));
                                310               2 :             break;
  636 michael                   311 LBC           0 :         default:
                                312               0 :             elog(ERROR, "incorrect output types");
  636 michael                   313 EUB             :             break;
                                314                 :     }
                                315                 : 
 5806 bruce                     316 GIC           3 :     values[7] = UInt16GetDatum(PageGetPageLayoutVersion(page));
  272 peter                     317 GNC           3 :     values[8] = TransactionIdGetDatum(pageheader->pd_prune_xid);
 5806 bruce                     318 ECB             : 
 5624                           319                 :     /* Build and return the tuple. */
                                320                 : 
 5806 bruce                     321 GIC           3 :     memset(nulls, 0, sizeof(nulls));
                                322                 : 
 5624 bruce                     323 CBC           3 :     tuple = heap_form_tuple(tupdesc, values, nulls);
 5624 bruce                     324 GIC           3 :     result = HeapTupleGetDatum(tuple);
 5806 bruce                     325 ECB             : 
 5806 bruce                     326 CBC           3 :     PG_RETURN_DATUM(result);
                                327                 : }
 2214 peter_e                   328 ECB             : 
                                329                 : /*
                                330                 :  * page_checksum
                                331                 :  *
                                332                 :  * Compute checksum of a raw page
                                333                 :  */
                                334                 : 
  810 peter                     335 GIC           8 : PG_FUNCTION_INFO_V1(page_checksum_1_9);
 2214 peter_e                   336               7 : PG_FUNCTION_INFO_V1(page_checksum);
 2214 peter_e                   337 ECB             : 
  810 peter                     338                 : static Datum
  810 peter                     339 GIC          23 : page_checksum_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
                                340                 : {
 2214 peter_e                   341 CBC          23 :     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
  810 peter                     342 GIC          23 :     int64       blkno = (ext_version == PAGEINSPECT_V1_8 ? PG_GETARG_UINT32(1) : PG_GETARG_INT64(1));
  389 michael                   343 ECB             :     Page        page;
 2214 peter_e                   344                 : 
 2214 peter_e                   345 GIC          23 :     if (!superuser())
 2214 peter_e                   346 UIC           0 :         ereport(ERROR,
 2214 peter_e                   347 ECB             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 1165 alvherre                  348 EUB             :                  errmsg("must be superuser to use raw page functions")));
                                349                 : 
  810 peter                     350 GIC          23 :     if (blkno < 0 || blkno > MaxBlockNumber)
                                351               1 :         ereport(ERROR,
  810 peter                     352 ECB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                353                 :                  errmsg("invalid block number")));
                                354                 : 
  389 michael                   355 GIC          22 :     page = get_page_from_raw(raw_page);
                                356                 : 
  360 michael                   357 CBC          21 :     if (PageIsNew(page))
  360 michael                   358 GIC           1 :         PG_RETURN_NULL();
  360 michael                   359 ECB             : 
 2153 bruce                     360 CBC          20 :     PG_RETURN_INT16(pg_checksum_page((char *) page, blkno));
                                361                 : }
  810 peter                     362 ECB             : 
                                363                 : Datum
  810 peter                     364 GIC          22 : page_checksum_1_9(PG_FUNCTION_ARGS)
                                365                 : {
  810 peter                     366 CBC          22 :     return page_checksum_internal(fcinfo, PAGEINSPECT_V1_9);
                                367                 : }
  810 peter                     368 ECB             : 
                                369                 : /*
                                370                 :  * Entry point for old extension version
                                371                 :  */
                                372                 : Datum
  810 peter                     373 GIC           1 : page_checksum(PG_FUNCTION_ARGS)
                                374                 : {
  810 peter                     375 CBC           1 :     return page_checksum_internal(fcinfo, PAGEINSPECT_V1_8);
                                376                 : }
        

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