00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "postgres.h"
00017
00018 #include "access/htup_details.h"
00019 #include "catalog/catalog.h"
00020 #include "catalog/namespace.h"
00021 #include "funcapi.h"
00022 #include "miscadmin.h"
00023 #include "storage/bufmgr.h"
00024 #include "utils/builtins.h"
00025 #include "utils/rel.h"
00026
00027 PG_MODULE_MAGIC;
00028
00029 Datum get_raw_page(PG_FUNCTION_ARGS);
00030 Datum get_raw_page_fork(PG_FUNCTION_ARGS);
00031 Datum page_header(PG_FUNCTION_ARGS);
00032
00033 static bytea *get_raw_page_internal(text *relname, ForkNumber forknum,
00034 BlockNumber blkno);
00035
00036
00037
00038
00039
00040
00041
00042 PG_FUNCTION_INFO_V1(get_raw_page);
00043
00044 Datum
00045 get_raw_page(PG_FUNCTION_ARGS)
00046 {
00047 text *relname = PG_GETARG_TEXT_P(0);
00048 uint32 blkno = PG_GETARG_UINT32(1);
00049 bytea *raw_page;
00050
00051
00052
00053
00054
00055
00056 if (PG_NARGS() != 2)
00057 ereport(ERROR,
00058 (errmsg("wrong number of arguments to get_raw_page()"),
00059 errhint("Run the updated pageinspect.sql script.")));
00060
00061 raw_page = get_raw_page_internal(relname, MAIN_FORKNUM, blkno);
00062
00063 PG_RETURN_BYTEA_P(raw_page);
00064 }
00065
00066
00067
00068
00069
00070
00071 PG_FUNCTION_INFO_V1(get_raw_page_fork);
00072
00073 Datum
00074 get_raw_page_fork(PG_FUNCTION_ARGS)
00075 {
00076 text *relname = PG_GETARG_TEXT_P(0);
00077 text *forkname = PG_GETARG_TEXT_P(1);
00078 uint32 blkno = PG_GETARG_UINT32(2);
00079 bytea *raw_page;
00080 ForkNumber forknum;
00081
00082 forknum = forkname_to_number(text_to_cstring(forkname));
00083
00084 raw_page = get_raw_page_internal(relname, forknum, blkno);
00085
00086 PG_RETURN_BYTEA_P(raw_page);
00087 }
00088
00089
00090
00091
00092 static bytea *
00093 get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
00094 {
00095 bytea *raw_page;
00096 RangeVar *relrv;
00097 Relation rel;
00098 char *raw_page_data;
00099 Buffer buf;
00100
00101 if (!superuser())
00102 ereport(ERROR,
00103 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00104 (errmsg("must be superuser to use raw functions"))));
00105
00106 relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
00107 rel = relation_openrv(relrv, AccessShareLock);
00108
00109
00110 if (rel->rd_rel->relkind == RELKIND_VIEW)
00111 ereport(ERROR,
00112 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00113 errmsg("cannot get raw page from view \"%s\"",
00114 RelationGetRelationName(rel))));
00115 if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
00116 ereport(ERROR,
00117 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00118 errmsg("cannot get raw page from composite type \"%s\"",
00119 RelationGetRelationName(rel))));
00120 if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
00121 ereport(ERROR,
00122 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00123 errmsg("cannot get raw page from foreign table \"%s\"",
00124 RelationGetRelationName(rel))));
00125
00126
00127
00128
00129
00130
00131 if (RELATION_IS_OTHER_TEMP(rel))
00132 ereport(ERROR,
00133 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00134 errmsg("cannot access temporary tables of other sessions")));
00135
00136 if (blkno >= RelationGetNumberOfBlocks(rel))
00137 elog(ERROR, "block number %u is out of range for relation \"%s\"",
00138 blkno, RelationGetRelationName(rel));
00139
00140
00141 raw_page = (bytea *) palloc(BLCKSZ + VARHDRSZ);
00142 SET_VARSIZE(raw_page, BLCKSZ + VARHDRSZ);
00143 raw_page_data = VARDATA(raw_page);
00144
00145
00146
00147 buf = ReadBufferExtended(rel, forknum, blkno, RBM_NORMAL, NULL);
00148 LockBuffer(buf, BUFFER_LOCK_SHARE);
00149
00150 memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ);
00151
00152 LockBuffer(buf, BUFFER_LOCK_UNLOCK);
00153 ReleaseBuffer(buf);
00154
00155 relation_close(rel, AccessShareLock);
00156
00157 return raw_page;
00158 }
00159
00160
00161
00162
00163
00164
00165
00166 PG_FUNCTION_INFO_V1(page_header);
00167
00168 Datum
00169 page_header(PG_FUNCTION_ARGS)
00170 {
00171 bytea *raw_page = PG_GETARG_BYTEA_P(0);
00172 int raw_page_size;
00173
00174 TupleDesc tupdesc;
00175
00176 Datum result;
00177 HeapTuple tuple;
00178 Datum values[9];
00179 bool nulls[9];
00180
00181 PageHeader page;
00182 XLogRecPtr lsn;
00183 char lsnchar[64];
00184
00185 if (!superuser())
00186 ereport(ERROR,
00187 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00188 (errmsg("must be superuser to use raw page functions"))));
00189
00190 raw_page_size = VARSIZE(raw_page) - VARHDRSZ;
00191
00192
00193
00194
00195
00196 if (raw_page_size < sizeof(PageHeaderData))
00197 ereport(ERROR,
00198 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00199 errmsg("input page too small (%d bytes)", raw_page_size)));
00200
00201 page = (PageHeader) VARDATA(raw_page);
00202
00203
00204 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
00205 elog(ERROR, "return type must be a row type");
00206
00207
00208
00209 lsn = PageGetLSN(page);
00210 snprintf(lsnchar, sizeof(lsnchar), "%X/%X",
00211 (uint32) (lsn >> 32), (uint32) lsn);
00212
00213 values[0] = CStringGetTextDatum(lsnchar);
00214 values[1] = UInt16GetDatum(page->pd_checksum);
00215 values[2] = UInt16GetDatum(page->pd_flags);
00216 values[3] = UInt16GetDatum(page->pd_lower);
00217 values[4] = UInt16GetDatum(page->pd_upper);
00218 values[5] = UInt16GetDatum(page->pd_special);
00219 values[6] = UInt16GetDatum(PageGetPageSize(page));
00220 values[7] = UInt16GetDatum(PageGetPageLayoutVersion(page));
00221 values[8] = TransactionIdGetDatum(page->pd_prune_xid);
00222
00223
00224
00225 memset(nulls, 0, sizeof(nulls));
00226
00227 tuple = heap_form_tuple(tupdesc, values, nulls);
00228 result = HeapTupleGetDatum(tuple);
00229
00230 PG_RETURN_DATUM(result);
00231 }