PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
rawpage.c
Go to the documentation of this file.
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-2025, 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
33 .name = "pageinspect",
34 .version = PG_VERSION
35);
36
38 BlockNumber blkno);
39
40
41/*
42 * get_raw_page
43 *
44 * Returns a copy of a page from shared buffers as a bytea
45 */
47
50{
52 int64 blkno = PG_GETARG_INT64(1);
53 bytea *raw_page;
54
55 if (blkno < 0 || blkno > MaxBlockNumber)
57 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
58 errmsg("invalid block number")));
59
60 raw_page = get_raw_page_internal(relname, MAIN_FORKNUM, blkno);
61
62 PG_RETURN_BYTEA_P(raw_page);
63}
64
65/*
66 * entry point for old extension version
67 */
69
72{
74 uint32 blkno = PG_GETARG_UINT32(1);
75 bytea *raw_page;
76
77 /*
78 * We don't normally bother to check the number of arguments to a C
79 * function, but here it's needed for safety because early 8.4 beta
80 * releases mistakenly redefined get_raw_page() as taking three arguments.
81 */
82 if (PG_NARGS() != 2)
84 (errmsg("wrong number of arguments to get_raw_page()"),
85 errhint("Run the updated pageinspect.sql script.")));
86
87 raw_page = get_raw_page_internal(relname, MAIN_FORKNUM, blkno);
88
89 PG_RETURN_BYTEA_P(raw_page);
90}
91
92/*
93 * get_raw_page_fork
94 *
95 * Same, for any fork
96 */
98
101{
103 text *forkname = PG_GETARG_TEXT_PP(1);
104 int64 blkno = PG_GETARG_INT64(2);
105 bytea *raw_page;
106 ForkNumber forknum;
107
108 forknum = forkname_to_number(text_to_cstring(forkname));
109
110 if (blkno < 0 || blkno > MaxBlockNumber)
112 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
113 errmsg("invalid block number")));
114
115 raw_page = get_raw_page_internal(relname, forknum, blkno);
116
117 PG_RETURN_BYTEA_P(raw_page);
118}
119
120/*
121 * Entry point for old extension version
122 */
124
125Datum
127{
129 text *forkname = PG_GETARG_TEXT_PP(1);
130 uint32 blkno = PG_GETARG_UINT32(2);
131 bytea *raw_page;
132 ForkNumber forknum;
133
134 forknum = forkname_to_number(text_to_cstring(forkname));
135
136 raw_page = get_raw_page_internal(relname, forknum, blkno);
137
138 PG_RETURN_BYTEA_P(raw_page);
139}
140
141/*
142 * workhorse
143 */
144static bytea *
146{
147 bytea *raw_page;
148 RangeVar *relrv;
149 Relation rel;
150 char *raw_page_data;
151 Buffer buf;
152
153 if (!superuser())
155 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
156 errmsg("must be superuser to use raw page functions")));
157
159 rel = relation_openrv(relrv, AccessShareLock);
160
161 if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
163 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
164 errmsg("cannot get raw page from relation \"%s\"",
167
168 /*
169 * Reject attempts to read non-local temporary relations; we would be
170 * likely to get wrong data since we have no visibility into the owning
171 * session's local buffers.
172 */
173 if (RELATION_IS_OTHER_TEMP(rel))
175 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
176 errmsg("cannot access temporary tables of other sessions")));
177
178 if (blkno >= RelationGetNumberOfBlocksInFork(rel, forknum))
180 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
181 errmsg("block number %u is out of range for relation \"%s\"",
182 blkno, RelationGetRelationName(rel))));
183
184 /* Initialize buffer to copy to */
185 raw_page = (bytea *) palloc(BLCKSZ + VARHDRSZ);
186 SET_VARSIZE(raw_page, BLCKSZ + VARHDRSZ);
187 raw_page_data = VARDATA(raw_page);
188
189 /* Take a verbatim copy of the page */
190
191 buf = ReadBufferExtended(rel, forknum, blkno, RBM_NORMAL, NULL);
193
194 memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ);
195
198
200
201 return raw_page;
202}
203
204
205/*
206 * get_page_from_raw
207 *
208 * Get a palloc'd, maxalign'ed page image from the result of get_raw_page()
209 *
210 * On machines with MAXALIGN = 8, the payload of a bytea is not maxaligned,
211 * since it will start 4 bytes into a palloc'd value. On alignment-picky
212 * machines, this will cause failures in accesses to 8-byte-wide values
213 * within the page. We don't need to worry if accessing only 4-byte or
214 * smaller fields, but when examining a struct that contains 8-byte fields,
215 * use this function for safety.
216 */
217Page
219{
220 Page page;
221 int raw_page_size;
222
223 raw_page_size = VARSIZE_ANY_EXHDR(raw_page);
224
225 if (raw_page_size != BLCKSZ)
227 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
228 errmsg("invalid page size"),
229 errdetail("Expected %d bytes, got %d.",
230 BLCKSZ, raw_page_size)));
231
232 page = palloc(raw_page_size);
233
234 memcpy(page, VARDATA_ANY(raw_page), raw_page_size);
235
236 return page;
237}
238
239
240/*
241 * page_header
242 *
243 * Allows inspection of page header fields of a raw page
244 */
245
247
248Datum
250{
251 bytea *raw_page = PG_GETARG_BYTEA_P(0);
252
253 TupleDesc tupdesc;
254
255 Datum result;
256 HeapTuple tuple;
257 Datum values[9];
258 bool nulls[9];
259
260 Page page;
261 PageHeader pageheader;
262 XLogRecPtr lsn;
263
264 if (!superuser())
266 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
267 errmsg("must be superuser to use raw page functions")));
268
269 page = get_page_from_raw(raw_page);
270 pageheader = (PageHeader) page;
271
272 /* Build a tuple descriptor for our result type */
273 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
274 elog(ERROR, "return type must be a row type");
275
276 /* Extract information from the page header */
277
278 lsn = PageGetLSN(page);
279
280 /* pageinspect >= 1.2 uses pg_lsn instead of text for the LSN field. */
281 if (TupleDescAttr(tupdesc, 0)->atttypid == TEXTOID)
282 {
283 char lsnchar[64];
284
285 snprintf(lsnchar, sizeof(lsnchar), "%X/%X", LSN_FORMAT_ARGS(lsn));
286 values[0] = CStringGetTextDatum(lsnchar);
287 }
288 else
289 values[0] = LSNGetDatum(lsn);
290 values[1] = UInt16GetDatum(pageheader->pd_checksum);
291 values[2] = UInt16GetDatum(pageheader->pd_flags);
292
293 /* pageinspect >= 1.10 uses int4 instead of int2 for those fields */
294 switch (TupleDescAttr(tupdesc, 3)->atttypid)
295 {
296 case INT2OID:
297 Assert(TupleDescAttr(tupdesc, 4)->atttypid == INT2OID &&
298 TupleDescAttr(tupdesc, 5)->atttypid == INT2OID &&
299 TupleDescAttr(tupdesc, 6)->atttypid == INT2OID);
300 values[3] = UInt16GetDatum(pageheader->pd_lower);
301 values[4] = UInt16GetDatum(pageheader->pd_upper);
302 values[5] = UInt16GetDatum(pageheader->pd_special);
304 break;
305 case INT4OID:
306 Assert(TupleDescAttr(tupdesc, 4)->atttypid == INT4OID &&
307 TupleDescAttr(tupdesc, 5)->atttypid == INT4OID &&
308 TupleDescAttr(tupdesc, 6)->atttypid == INT4OID);
309 values[3] = Int32GetDatum(pageheader->pd_lower);
310 values[4] = Int32GetDatum(pageheader->pd_upper);
311 values[5] = Int32GetDatum(pageheader->pd_special);
313 break;
314 default:
315 elog(ERROR, "incorrect output types");
316 break;
317 }
318
320 values[8] = TransactionIdGetDatum(pageheader->pd_prune_xid);
321
322 /* Build and return the tuple. */
323
324 memset(nulls, 0, sizeof(nulls));
325
326 tuple = heap_form_tuple(tupdesc, values, nulls);
327 result = HeapTupleGetDatum(tuple);
328
329 PG_RETURN_DATUM(result);
330}
331
332/*
333 * page_checksum
334 *
335 * Compute checksum of a raw page
336 */
337
340
341static Datum
343{
344 bytea *raw_page = PG_GETARG_BYTEA_P(0);
345 int64 blkno = (ext_version == PAGEINSPECT_V1_8 ? PG_GETARG_UINT32(1) : PG_GETARG_INT64(1));
346 Page page;
347
348 if (!superuser())
350 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
351 errmsg("must be superuser to use raw page functions")));
352
353 if (blkno < 0 || blkno > MaxBlockNumber)
355 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
356 errmsg("invalid block number")));
357
358 page = get_page_from_raw(raw_page);
359
360 if (PageIsNew(page))
362
363 PG_RETURN_INT16(pg_checksum_page(page, blkno));
364}
365
366Datum
368{
370}
371
372/*
373 * Entry point for old extension version
374 */
375Datum
377{
379}
uint32 BlockNumber
Definition: block.h:31
#define MaxBlockNumber
Definition: block.h:35
static Datum values[MAXATTR]
Definition: bootstrap.c:151
int Buffer
Definition: buf.h:23
BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
Definition: bufmgr.c:4361
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:5303
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:5537
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:798
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:196
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:197
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:414
@ RBM_NORMAL
Definition: bufmgr.h:46
PageHeaderData * PageHeader
Definition: bufpage.h:174
static Size PageGetPageSize(const PageData *page)
Definition: bufpage.h:277
static bool PageIsNew(const PageData *page)
Definition: bufpage.h:234
static uint8 PageGetPageLayoutVersion(const PageData *page)
Definition: bufpage.h:287
PageData * Page
Definition: bufpage.h:82
static XLogRecPtr PageGetLSN(const PageData *page)
Definition: bufpage.h:386
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define VARHDRSZ
Definition: c.h:663
int64_t int64
Definition: c.h:499
uint32_t uint32
Definition: c.h:502
uint16 pg_checksum_page(char *page, BlockNumber blkno)
int errdetail(const char *fmt,...)
Definition: elog.c:1204
int errhint(const char *fmt,...)
Definition: elog.c:1318
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define PG_GETARG_UINT32(n)
Definition: fmgr.h:270
#define PG_NARGS()
Definition: fmgr.h:203
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_INT16(x)
Definition: fmgr.h:356
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_GETARG_BYTEA_P(n)
Definition: fmgr.h:335
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
#define AccessShareLock
Definition: lockdefs.h:36
void * palloc(Size size)
Definition: mcxt.c:1940
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3554
pageinspect_version
Definition: pageinspect.h:22
@ PAGEINSPECT_V1_9
Definition: pageinspect.h:24
@ PAGEINSPECT_V1_8
Definition: pageinspect.h:23
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
NameData relname
Definition: pg_class.h:38
static Datum LSNGetDatum(XLogRecPtr X)
Definition: pg_lsn.h:28
static char * buf
Definition: pg_test_fsync.c:72
#define snprintf
Definition: port.h:239
static Datum TransactionIdGetDatum(TransactionId X)
Definition: postgres.h:277
uintptr_t Datum
Definition: postgres.h:69
static Datum UInt16GetDatum(uint16 X)
Definition: postgres.h:197
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
Datum get_raw_page(PG_FUNCTION_ARGS)
Definition: rawpage.c:71
Datum page_checksum(PG_FUNCTION_ARGS)
Definition: rawpage.c:376
Datum page_checksum_1_9(PG_FUNCTION_ARGS)
Definition: rawpage.c:367
PG_MODULE_MAGIC_EXT(.name="pageinspect",.version=PG_VERSION)
Datum get_raw_page_fork_1_9(PG_FUNCTION_ARGS)
Definition: rawpage.c:100
static Datum page_checksum_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
Definition: rawpage.c:342
static bytea * get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
Definition: rawpage.c:145
Datum page_header(PG_FUNCTION_ARGS)
Definition: rawpage.c:249
Datum get_raw_page_1_9(PG_FUNCTION_ARGS)
Definition: rawpage.c:49
PG_FUNCTION_INFO_V1(get_raw_page_1_9)
Page get_page_from_raw(bytea *raw_page)
Definition: rawpage.c:218
Datum get_raw_page_fork(PG_FUNCTION_ARGS)
Definition: rawpage.c:126
#define RelationGetRelationName(relation)
Definition: rel.h:550
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:669
ForkNumber forkname_to_number(const char *forkName)
Definition: relpath.c:50
ForkNumber
Definition: relpath.h:56
@ MAIN_FORKNUM
Definition: relpath.h:58
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: relation.c:137
LocationIndex pd_special
Definition: bufpage.h:168
LocationIndex pd_upper
Definition: bufpage.h:167
uint16 pd_flags
Definition: bufpage.h:165
uint16 pd_checksum
Definition: bufpage.h:164
LocationIndex pd_lower
Definition: bufpage.h:166
TransactionId pd_prune_xid
Definition: bufpage.h:170
Form_pg_class rd_rel
Definition: rel.h:111
Definition: c.h:658
bool superuser(void)
Definition: superuser.c:46
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
#define VARDATA(PTR)
Definition: varatt.h:278
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
char * text_to_cstring(const text *t)
Definition: varlena.c:225
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3467
const char * name
#define LSN_FORMAT_ARGS(lsn)
Definition: xlogdefs.h:43
uint64 XLogRecPtr
Definition: xlogdefs.h:21