]> granicus.if.org Git - postgresql/blob - contrib/pageinspect/rawpage.c
Rewrite the FSM. Instead of relying on a fixed-size shared memory segment, the
[postgresql] / contrib / pageinspect / rawpage.c
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-2008, PostgreSQL Global Development Group
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/contrib/pageinspect/rawpage.c,v 1.7 2008/09/30 10:52:09 heikki Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "postgres.h"
17
18 #include "access/heapam.h"
19 #include "access/transam.h"
20 #include "catalog/namespace.h"
21 #include "catalog/pg_type.h"
22 #include "fmgr.h"
23 #include "funcapi.h"
24 #include "miscadmin.h"
25 #include "storage/bufmgr.h"
26 #include "utils/builtins.h"
27
28 PG_MODULE_MAGIC;
29
30 Datum           get_raw_page(PG_FUNCTION_ARGS);
31 Datum           page_header(PG_FUNCTION_ARGS);
32
33 /*
34  * get_raw_page
35  *
36  * Returns a copy of a page from shared buffers as a bytea
37  */
38 PG_FUNCTION_INFO_V1(get_raw_page);
39
40 Datum
41 get_raw_page(PG_FUNCTION_ARGS)
42 {
43         text       *relname = PG_GETARG_TEXT_P(0);
44         uint32          forknum = PG_GETARG_UINT32(1);
45         uint32          blkno = PG_GETARG_UINT32(2);
46
47         Relation        rel;
48         RangeVar   *relrv;
49         bytea      *raw_page;
50         char       *raw_page_data;
51         Buffer          buf;
52
53         if (!superuser())
54                 ereport(ERROR,
55                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
56                                  (errmsg("must be superuser to use raw functions"))));
57
58         if (forknum > MAX_FORKNUM)
59                 ereport(ERROR,
60                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
61                                  errmsg("invalid fork number")));
62
63         relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
64         rel = relation_openrv(relrv, AccessShareLock);
65
66         /* Check that this relation has storage */
67         if (rel->rd_rel->relkind == RELKIND_VIEW)
68                 ereport(ERROR,
69                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
70                                  errmsg("cannot get raw page from view \"%s\"",
71                                                 RelationGetRelationName(rel))));
72         if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
73                 ereport(ERROR,
74                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
75                                  errmsg("cannot get raw page from composite type \"%s\"",
76                                                 RelationGetRelationName(rel))));
77
78         if (blkno >= RelationGetNumberOfBlocks(rel))
79                 elog(ERROR, "block number %u is out of range for relation \"%s\"",
80                          blkno, RelationGetRelationName(rel));
81
82         /* Initialize buffer to copy to */
83         raw_page = (bytea *) palloc(BLCKSZ + VARHDRSZ);
84         SET_VARSIZE(raw_page, BLCKSZ + VARHDRSZ);
85         raw_page_data = VARDATA(raw_page);
86
87         /* Take a verbatim copy of the page */
88
89         buf = ReadBufferWithFork(rel, forknum, blkno);
90         LockBuffer(buf, BUFFER_LOCK_SHARE);
91
92         memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ);
93
94         LockBuffer(buf, BUFFER_LOCK_UNLOCK);
95         ReleaseBuffer(buf);
96
97         relation_close(rel, AccessShareLock);
98
99         PG_RETURN_BYTEA_P(raw_page);
100 }
101
102 /*
103  * page_header
104  *
105  * Allows inspection of page header fields of a raw page
106  */
107
108 PG_FUNCTION_INFO_V1(page_header);
109
110 Datum
111 page_header(PG_FUNCTION_ARGS)
112 {
113         bytea      *raw_page = PG_GETARG_BYTEA_P(0);
114         int                     raw_page_size;
115
116         TupleDesc       tupdesc;
117
118         Datum           result;
119         HeapTuple       tuple;
120         Datum           values[9];
121         bool            nulls[9];
122
123         PageHeader      page;
124         XLogRecPtr      lsn;
125         char            lsnchar[64];
126
127         if (!superuser())
128                 ereport(ERROR,
129                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
130                                  (errmsg("must be superuser to use raw page functions"))));
131
132         raw_page_size = VARSIZE(raw_page) - VARHDRSZ;
133
134         /*
135          * Check that enough data was supplied, so that we don't try to access
136          * fields outside the supplied buffer.
137          */
138         if (raw_page_size < sizeof(PageHeaderData))
139                 ereport(ERROR,
140                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
141                                  errmsg("input page too small (%d bytes)", raw_page_size)));
142
143         page = (PageHeader) VARDATA(raw_page);
144
145         /* Build a tuple descriptor for our result type */
146         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
147                 elog(ERROR, "return type must be a row type");
148
149         /* Extract information from the page header */
150
151         lsn = PageGetLSN(page);
152         snprintf(lsnchar, sizeof(lsnchar), "%X/%X", lsn.xlogid, lsn.xrecoff);
153
154         values[0] = CStringGetTextDatum(lsnchar);
155         values[1] = UInt16GetDatum(PageGetTLI(page));
156         values[2] = UInt16GetDatum(page->pd_flags);
157         values[3] = UInt16GetDatum(page->pd_lower);
158         values[4] = UInt16GetDatum(page->pd_upper);
159         values[5] = UInt16GetDatum(page->pd_special);
160         values[6] = UInt16GetDatum(PageGetPageSize(page));
161         values[7] = UInt16GetDatum(PageGetPageLayoutVersion(page));
162         values[8] = TransactionIdGetDatum(page->pd_prune_xid);
163
164         /* Build and return the tuple. */
165
166         memset(nulls, 0, sizeof(nulls));
167
168         tuple = heap_form_tuple(tupdesc, values, nulls);
169         result = HeapTupleGetDatum(tuple);
170
171         PG_RETURN_DATUM(result);
172 }