]> granicus.if.org Git - postgresql/blobdiff - contrib/pageinspect/rawpage.c
Update copyrights for 2013
[postgresql] / contrib / pageinspect / rawpage.c
index 80632be9fb55b9b61a1d65e369fdbef0b14ae458..222e043368b11d76bb0ff9d68610117027e26351 100644 (file)
@@ -5,29 +5,34 @@
  *
  * Access-method specific inspection functions are in separate files.
  *
- * Copyright (c) 2007, PostgreSQL Global Development Group
+ * Copyright (c) 2007-2013, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/contrib/pageinspect/rawpage.c,v 1.2 2007/09/21 21:25:42 tgl Exp $
+ *       contrib/pageinspect/rawpage.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
-#include "fmgr.h"
-#include "funcapi.h"
-#include "access/heapam.h"
-#include "access/transam.h"
+#include "access/htup_details.h"
+#include "catalog/catalog.h"
 #include "catalog/namespace.h"
-#include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "funcapi.h"
 #include "miscadmin.h"
+#include "storage/bufmgr.h"
+#include "utils/builtins.h"
+#include "utils/rel.h"
 
 PG_MODULE_MAGIC;
 
-Datum get_raw_page(PG_FUNCTION_ARGS);
-Datum page_header(PG_FUNCTION_ARGS);
+Datum          get_raw_page(PG_FUNCTION_ARGS);
+Datum          get_raw_page_fork(PG_FUNCTION_ARGS);
+Datum          page_header(PG_FUNCTION_ARGS);
+
+static bytea *get_raw_page_internal(text *relname, ForkNumber forknum,
+                                         BlockNumber blkno);
+
 
 /*
  * get_raw_page
@@ -41,11 +46,56 @@ get_raw_page(PG_FUNCTION_ARGS)
 {
        text       *relname = PG_GETARG_TEXT_P(0);
        uint32          blkno = PG_GETARG_UINT32(1);
+       bytea      *raw_page;
+
+       /*
+        * We don't normally bother to check the number of arguments to a C
+        * function, but here it's needed for safety because early 8.4 beta
+        * releases mistakenly redefined get_raw_page() as taking three arguments.
+        */
+       if (PG_NARGS() != 2)
+               ereport(ERROR,
+                               (errmsg("wrong number of arguments to get_raw_page()"),
+                                errhint("Run the updated pageinspect.sql script.")));
+
+       raw_page = get_raw_page_internal(relname, MAIN_FORKNUM, blkno);
+
+       PG_RETURN_BYTEA_P(raw_page);
+}
+
+/*
+ * get_raw_page_fork
+ *
+ * Same, for any fork
+ */
+PG_FUNCTION_INFO_V1(get_raw_page_fork);
+
+Datum
+get_raw_page_fork(PG_FUNCTION_ARGS)
+{
+       text       *relname = PG_GETARG_TEXT_P(0);
+       text       *forkname = PG_GETARG_TEXT_P(1);
+       uint32          blkno = PG_GETARG_UINT32(2);
+       bytea      *raw_page;
+       ForkNumber      forknum;
+
+       forknum = forkname_to_number(text_to_cstring(forkname));
+
+       raw_page = get_raw_page_internal(relname, forknum, blkno);
 
+       PG_RETURN_BYTEA_P(raw_page);
+}
+
+/*
+ * workhorse
+ */
+static bytea *
+get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
+{
+       bytea      *raw_page;
+       RangeVar   *relrv;
        Relation        rel;
-       RangeVar        *relrv;
-       bytea           *raw_page;
-       char            *raw_page_data;
+       char       *raw_page_data;
        Buffer          buf;
 
        if (!superuser())
@@ -61,12 +111,27 @@ get_raw_page(PG_FUNCTION_ARGS)
                ereport(ERROR,
                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                 errmsg("cannot get raw page from view \"%s\"",
-                                                       RelationGetRelationName(rel))));
+                                               RelationGetRelationName(rel))));
        if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
                ereport(ERROR,
                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                 errmsg("cannot get raw page from composite type \"%s\"",
-                                                       RelationGetRelationName(rel))));
+                                               RelationGetRelationName(rel))));
+       if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+               ereport(ERROR,
+                               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                                errmsg("cannot get raw page from foreign table \"%s\"",
+                                               RelationGetRelationName(rel))));
+
+       /*
+        * Reject attempts to read non-local temporary relations; we would be
+        * likely to get wrong data since we have no visibility into the owning
+        * session's local buffers.
+        */
+       if (RELATION_IS_OTHER_TEMP(rel))
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("cannot access temporary tables of other sessions")));
 
        if (blkno >= RelationGetNumberOfBlocks(rel))
                elog(ERROR, "block number %u is out of range for relation \"%s\"",
@@ -79,7 +144,7 @@ get_raw_page(PG_FUNCTION_ARGS)
 
        /* Take a verbatim copy of the page */
 
-       buf = ReadBuffer(rel, blkno);
+       buf = ReadBufferExtended(rel, forknum, blkno, RBM_NORMAL, NULL);
        LockBuffer(buf, BUFFER_LOCK_SHARE);
 
        memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ);
@@ -89,7 +154,7 @@ get_raw_page(PG_FUNCTION_ARGS)
 
        relation_close(rel, AccessShareLock);
 
-       PG_RETURN_BYTEA_P(raw_page);
+       return raw_page;
 }
 
 /*
@@ -125,13 +190,13 @@ page_header(PG_FUNCTION_ARGS)
        raw_page_size = VARSIZE(raw_page) - VARHDRSZ;
 
        /*
-        * Check that enough data was supplied, so that we don't try to access 
-        * fields outside the supplied buffer. 
+        * Check that enough data was supplied, so that we don't try to access
+        * fields outside the supplied buffer.
         */
-       if(raw_page_size < sizeof(PageHeaderData))
-               ereport(ERROR, 
-                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                         errmsg("input page too small (%d bytes)", raw_page_size)));
+       if (raw_page_size < sizeof(PageHeaderData))
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                errmsg("input page too small (%d bytes)", raw_page_size)));
 
        page = (PageHeader) VARDATA(raw_page);
 
@@ -142,9 +207,10 @@ page_header(PG_FUNCTION_ARGS)
        /* Extract information from the page header */
 
        lsn = PageGetLSN(page);
-       snprintf(lsnchar, sizeof(lsnchar), "%X/%X", lsn.xlogid, lsn.xrecoff);
+       snprintf(lsnchar, sizeof(lsnchar), "%X/%X",
+                        (uint32) (lsn >> 32), (uint32) lsn);
 
-       values[0] = DirectFunctionCall1(textin, CStringGetDatum(lsnchar));
+       values[0] = CStringGetTextDatum(lsnchar);
        values[1] = UInt16GetDatum(PageGetTLI(page));
        values[2] = UInt16GetDatum(page->pd_flags);
        values[3] = UInt16GetDatum(page->pd_lower);
@@ -154,12 +220,12 @@ page_header(PG_FUNCTION_ARGS)
        values[7] = UInt16GetDatum(PageGetPageLayoutVersion(page));
        values[8] = TransactionIdGetDatum(page->pd_prune_xid);
 
-    /* Build and return the tuple. */
+       /* Build and return the tuple. */
 
        memset(nulls, 0, sizeof(nulls));
 
-    tuple = heap_form_tuple(tupdesc, values, nulls);
-    result = HeapTupleGetDatum(tuple);
+       tuple = heap_form_tuple(tupdesc, values, nulls);
+       result = HeapTupleGetDatum(tuple);
 
        PG_RETURN_DATUM(result);
 }