PostgreSQL Source Code git master
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
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 */
44
47{
49 int64 blkno = PG_GETARG_INT64(1);
50 bytea *raw_page;
51
52 if (blkno < 0 || blkno > MaxBlockNumber)
54 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
55 errmsg("invalid block number")));
56
57 raw_page = get_raw_page_internal(relname, MAIN_FORKNUM, blkno);
58
59 PG_RETURN_BYTEA_P(raw_page);
60}
61
62/*
63 * entry point for old extension version
64 */
66
69{
71 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 if (PG_NARGS() != 2)
81 (errmsg("wrong number of arguments to get_raw_page()"),
82 errhint("Run the updated pageinspect.sql script.")));
83
84 raw_page = get_raw_page_internal(relname, MAIN_FORKNUM, blkno);
85
86 PG_RETURN_BYTEA_P(raw_page);
87}
88
89/*
90 * get_raw_page_fork
91 *
92 * Same, for any fork
93 */
95
98{
100 text *forkname = PG_GETARG_TEXT_PP(1);
101 int64 blkno = PG_GETARG_INT64(2);
102 bytea *raw_page;
103 ForkNumber forknum;
104
105 forknum = forkname_to_number(text_to_cstring(forkname));
106
107 if (blkno < 0 || blkno > MaxBlockNumber)
109 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
110 errmsg("invalid block number")));
111
112 raw_page = get_raw_page_internal(relname, forknum, blkno);
113
114 PG_RETURN_BYTEA_P(raw_page);
115}
116
117/*
118 * Entry point for old extension version
119 */
121
122Datum
124{
126 text *forkname = PG_GETARG_TEXT_PP(1);
127 uint32 blkno = PG_GETARG_UINT32(2);
128 bytea *raw_page;
129 ForkNumber forknum;
130
131 forknum = forkname_to_number(text_to_cstring(forkname));
132
133 raw_page = get_raw_page_internal(relname, forknum, blkno);
134
135 PG_RETURN_BYTEA_P(raw_page);
136}
137
138/*
139 * workhorse
140 */
141static bytea *
143{
144 bytea *raw_page;
145 RangeVar *relrv;
146 Relation rel;
147 char *raw_page_data;
148 Buffer buf;
149
150 if (!superuser())
152 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
153 errmsg("must be superuser to use raw page functions")));
154
156 rel = relation_openrv(relrv, AccessShareLock);
157
158 if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
160 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
161 errmsg("cannot get raw page from relation \"%s\"",
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 */
170 if (RELATION_IS_OTHER_TEMP(rel))
172 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
173 errmsg("cannot access temporary tables of other sessions")));
174
175 if (blkno >= RelationGetNumberOfBlocksInFork(rel, forknum))
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 */
182 raw_page = (bytea *) palloc(BLCKSZ + VARHDRSZ);
183 SET_VARSIZE(raw_page, BLCKSZ + VARHDRSZ);
184 raw_page_data = VARDATA(raw_page);
185
186 /* Take a verbatim copy of the page */
187
188 buf = ReadBufferExtended(rel, forknum, blkno, RBM_NORMAL, NULL);
190
191 memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ);
192
195
197
198 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 */
214Page
216{
217 Page page;
218 int raw_page_size;
219
220 raw_page_size = VARSIZE_ANY_EXHDR(raw_page);
221
222 if (raw_page_size != BLCKSZ)
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 page = palloc(raw_page_size);
230
231 memcpy(page, VARDATA_ANY(raw_page), raw_page_size);
232
233 return page;
234}
235
236
237/*
238 * page_header
239 *
240 * Allows inspection of page header fields of a raw page
241 */
242
244
245Datum
247{
248 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
261 if (!superuser())
263 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
264 errmsg("must be superuser to use raw page functions")));
265
266 page = get_page_from_raw(raw_page);
267 pageheader = (PageHeader) page;
268
269 /* Build a tuple descriptor for our result type */
270 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
271 elog(ERROR, "return type must be a row type");
272
273 /* Extract information from the page header */
274
275 lsn = PageGetLSN(page);
276
277 /* pageinspect >= 1.2 uses pg_lsn instead of text for the LSN field. */
278 if (TupleDescAttr(tupdesc, 0)->atttypid == TEXTOID)
279 {
280 char lsnchar[64];
281
282 snprintf(lsnchar, sizeof(lsnchar), "%X/%X", LSN_FORMAT_ARGS(lsn));
283 values[0] = CStringGetTextDatum(lsnchar);
284 }
285 else
286 values[0] = LSNGetDatum(lsn);
287 values[1] = UInt16GetDatum(pageheader->pd_checksum);
288 values[2] = UInt16GetDatum(pageheader->pd_flags);
289
290 /* pageinspect >= 1.10 uses int4 instead of int2 for those fields */
291 switch (TupleDescAttr(tupdesc, 3)->atttypid)
292 {
293 case INT2OID:
294 Assert(TupleDescAttr(tupdesc, 4)->atttypid == INT2OID &&
295 TupleDescAttr(tupdesc, 5)->atttypid == INT2OID &&
296 TupleDescAttr(tupdesc, 6)->atttypid == INT2OID);
297 values[3] = UInt16GetDatum(pageheader->pd_lower);
298 values[4] = UInt16GetDatum(pageheader->pd_upper);
299 values[5] = UInt16GetDatum(pageheader->pd_special);
301 break;
302 case INT4OID:
303 Assert(TupleDescAttr(tupdesc, 4)->atttypid == INT4OID &&
304 TupleDescAttr(tupdesc, 5)->atttypid == INT4OID &&
305 TupleDescAttr(tupdesc, 6)->atttypid == INT4OID);
306 values[3] = Int32GetDatum(pageheader->pd_lower);
307 values[4] = Int32GetDatum(pageheader->pd_upper);
308 values[5] = Int32GetDatum(pageheader->pd_special);
310 break;
311 default:
312 elog(ERROR, "incorrect output types");
313 break;
314 }
315
317 values[8] = TransactionIdGetDatum(pageheader->pd_prune_xid);
318
319 /* Build and return the tuple. */
320
321 memset(nulls, 0, sizeof(nulls));
322
323 tuple = heap_form_tuple(tupdesc, values, nulls);
324 result = HeapTupleGetDatum(tuple);
325
326 PG_RETURN_DATUM(result);
327}
328
329/*
330 * page_checksum
331 *
332 * Compute checksum of a raw page
333 */
334
337
338static Datum
340{
341 bytea *raw_page = PG_GETARG_BYTEA_P(0);
342 int64 blkno = (ext_version == PAGEINSPECT_V1_8 ? PG_GETARG_UINT32(1) : PG_GETARG_INT64(1));
343 Page page;
344
345 if (!superuser())
347 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
348 errmsg("must be superuser to use raw page functions")));
349
350 if (blkno < 0 || blkno > MaxBlockNumber)
352 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
353 errmsg("invalid block number")));
354
355 page = get_page_from_raw(raw_page);
356
357 if (PageIsNew(page))
359
360 PG_RETURN_INT16(pg_checksum_page((char *) page, blkno));
361}
362
363Datum
365{
367}
368
369/*
370 * Entry point for old extension version
371 */
372Datum
374{
376}
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:3923
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4866
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:5100
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:793
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:189
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:190
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:396
@ RBM_NORMAL
Definition: bufmgr.h:45
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:649
#define Assert(condition)
Definition: c.h:815
int64_t int64
Definition: c.h:485
uint32_t uint32
Definition: c.h:488
uint16 pg_checksum_page(char *page, BlockNumber blkno)
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#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
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:1317
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:238
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:68
Datum page_checksum(PG_FUNCTION_ARGS)
Definition: rawpage.c:373
PG_MODULE_MAGIC
Definition: rawpage.c:32
Datum page_checksum_1_9(PG_FUNCTION_ARGS)
Definition: rawpage.c:364
Datum get_raw_page_fork_1_9(PG_FUNCTION_ARGS)
Definition: rawpage.c:97
static Datum page_checksum_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
Definition: rawpage.c:339
static bytea * get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
Definition: rawpage.c:142
Datum page_header(PG_FUNCTION_ARGS)
Definition: rawpage.c:246
Datum get_raw_page_1_9(PG_FUNCTION_ARGS)
Definition: rawpage.c:46
PG_FUNCTION_INFO_V1(get_raw_page_1_9)
Page get_page_from_raw(bytea *raw_page)
Definition: rawpage.c:215
Datum get_raw_page_fork(PG_FUNCTION_ARGS)
Definition: rawpage.c:123
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:658
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:644
bool superuser(void)
Definition: superuser.c:46
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:153
#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:217
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3374
#define LSN_FORMAT_ARGS(lsn)
Definition: xlogdefs.h:43
uint64 XLogRecPtr
Definition: xlogdefs.h:21