Header And Logo

PostgreSQL
| The world's most advanced open source database.

heapfuncs.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * heapfuncs.c
00004  *    Functions to investigate heap pages
00005  *
00006  * We check the input to these functions for corrupt pointers etc. that
00007  * might cause crashes, but at the same time we try to print out as much
00008  * information as possible, even if it's nonsense. That's because if a
00009  * page is corrupt, we don't know why and how exactly it is corrupt, so we
00010  * let the user judge it.
00011  *
00012  * These functions are restricted to superusers for the fear of introducing
00013  * security holes if the input checking isn't as water-tight as it should be.
00014  * You'd need to be superuser to obtain a raw page image anyway, so
00015  * there's hardly any use case for using these without superuser-rights
00016  * anyway.
00017  *
00018  * Copyright (c) 2007-2013, PostgreSQL Global Development Group
00019  *
00020  * IDENTIFICATION
00021  *    contrib/pageinspect/heapfuncs.c
00022  *
00023  *-------------------------------------------------------------------------
00024  */
00025 
00026 #include "postgres.h"
00027 
00028 #include "access/htup_details.h"
00029 #include "funcapi.h"
00030 #include "utils/builtins.h"
00031 #include "miscadmin.h"
00032 
00033 Datum       heap_page_items(PG_FUNCTION_ARGS);
00034 
00035 
00036 /*
00037  * bits_to_text
00038  *
00039  * Converts a bits8-array of 'len' bits to a human-readable
00040  * c-string representation.
00041  */
00042 static char *
00043 bits_to_text(bits8 *bits, int len)
00044 {
00045     int         i;
00046     char       *str;
00047 
00048     str = palloc(len + 1);
00049 
00050     for (i = 0; i < len; i++)
00051         str[i] = (bits[(i / 8)] & (1 << (i % 8))) ? '1' : '0';
00052 
00053     str[i] = '\0';
00054 
00055     return str;
00056 }
00057 
00058 
00059 /*
00060  * heap_page_items
00061  *
00062  * Allows inspection of line pointers and tuple headers of a heap page.
00063  */
00064 PG_FUNCTION_INFO_V1(heap_page_items);
00065 
00066 typedef struct heap_page_items_state
00067 {
00068     TupleDesc   tupd;
00069     Page        page;
00070     uint16      offset;
00071 } heap_page_items_state;
00072 
00073 Datum
00074 heap_page_items(PG_FUNCTION_ARGS)
00075 {
00076     bytea      *raw_page = PG_GETARG_BYTEA_P(0);
00077     heap_page_items_state *inter_call_data = NULL;
00078     FuncCallContext *fctx;
00079     int         raw_page_size;
00080 
00081     if (!superuser())
00082         ereport(ERROR,
00083                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00084                  (errmsg("must be superuser to use raw page functions"))));
00085 
00086     raw_page_size = VARSIZE(raw_page) - VARHDRSZ;
00087 
00088     if (SRF_IS_FIRSTCALL())
00089     {
00090         TupleDesc   tupdesc;
00091         MemoryContext mctx;
00092 
00093         if (raw_page_size < SizeOfPageHeaderData)
00094             ereport(ERROR,
00095                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00096                   errmsg("input page too small (%d bytes)", raw_page_size)));
00097 
00098         fctx = SRF_FIRSTCALL_INIT();
00099         mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
00100 
00101         inter_call_data = palloc(sizeof(heap_page_items_state));
00102 
00103         /* Build a tuple descriptor for our result type */
00104         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
00105             elog(ERROR, "return type must be a row type");
00106 
00107         inter_call_data->tupd = tupdesc;
00108 
00109         inter_call_data->offset = FirstOffsetNumber;
00110         inter_call_data->page = VARDATA(raw_page);
00111 
00112         fctx->max_calls = PageGetMaxOffsetNumber(inter_call_data->page);
00113         fctx->user_fctx = inter_call_data;
00114 
00115         MemoryContextSwitchTo(mctx);
00116     }
00117 
00118     fctx = SRF_PERCALL_SETUP();
00119     inter_call_data = fctx->user_fctx;
00120 
00121     if (fctx->call_cntr < fctx->max_calls)
00122     {
00123         Page        page = inter_call_data->page;
00124         HeapTuple   resultTuple;
00125         Datum       result;
00126         ItemId      id;
00127         Datum       values[13];
00128         bool        nulls[13];
00129         uint16      lp_offset;
00130         uint16      lp_flags;
00131         uint16      lp_len;
00132 
00133         memset(nulls, 0, sizeof(nulls));
00134 
00135         /* Extract information from the line pointer */
00136 
00137         id = PageGetItemId(page, inter_call_data->offset);
00138 
00139         lp_offset = ItemIdGetOffset(id);
00140         lp_flags = ItemIdGetFlags(id);
00141         lp_len = ItemIdGetLength(id);
00142 
00143         values[0] = UInt16GetDatum(inter_call_data->offset);
00144         values[1] = UInt16GetDatum(lp_offset);
00145         values[2] = UInt16GetDatum(lp_flags);
00146         values[3] = UInt16GetDatum(lp_len);
00147 
00148         /*
00149          * We do just enough validity checking to make sure we don't reference
00150          * data outside the page passed to us. The page could be corrupt in
00151          * many other ways, but at least we won't crash.
00152          */
00153         if (ItemIdHasStorage(id) &&
00154             lp_len >= sizeof(HeapTupleHeader) &&
00155             lp_offset == MAXALIGN(lp_offset) &&
00156             lp_offset + lp_len <= raw_page_size)
00157         {
00158             HeapTupleHeader tuphdr;
00159             int         bits_len;
00160 
00161             /* Extract information from the tuple header */
00162 
00163             tuphdr = (HeapTupleHeader) PageGetItem(page, id);
00164 
00165             values[4] = UInt32GetDatum(HeapTupleHeaderGetXmin(tuphdr));
00166             values[5] = UInt32GetDatum(HeapTupleHeaderGetRawXmax(tuphdr));
00167             values[6] = UInt32GetDatum(HeapTupleHeaderGetRawCommandId(tuphdr)); /* shared with xvac */
00168             values[7] = PointerGetDatum(&tuphdr->t_ctid);
00169             values[8] = UInt32GetDatum(tuphdr->t_infomask2);
00170             values[9] = UInt32GetDatum(tuphdr->t_infomask);
00171             values[10] = UInt8GetDatum(tuphdr->t_hoff);
00172 
00173             /*
00174              * We already checked that the item as is completely within the
00175              * raw page passed to us, with the length given in the line
00176              * pointer.. Let's check that t_hoff doesn't point over lp_len,
00177              * before using it to access t_bits and oid.
00178              */
00179             if (tuphdr->t_hoff >= sizeof(HeapTupleHeader) &&
00180                 tuphdr->t_hoff <= lp_len)
00181             {
00182                 if (tuphdr->t_infomask & HEAP_HASNULL)
00183                 {
00184                     bits_len = tuphdr->t_hoff -
00185                         (((char *) tuphdr->t_bits) -((char *) tuphdr));
00186 
00187                     values[11] = CStringGetTextDatum(
00188                                  bits_to_text(tuphdr->t_bits, bits_len * 8));
00189                 }
00190                 else
00191                     nulls[11] = true;
00192 
00193                 if (tuphdr->t_infomask & HEAP_HASOID)
00194                     values[12] = HeapTupleHeaderGetOid(tuphdr);
00195                 else
00196                     nulls[12] = true;
00197             }
00198             else
00199             {
00200                 nulls[11] = true;
00201                 nulls[12] = true;
00202             }
00203         }
00204         else
00205         {
00206             /*
00207              * The line pointer is not used, or it's invalid. Set the rest of
00208              * the fields to NULL
00209              */
00210             int         i;
00211 
00212             for (i = 4; i <= 12; i++)
00213                 nulls[i] = true;
00214         }
00215 
00216         /* Build and return the result tuple. */
00217         resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
00218         result = HeapTupleGetDatum(resultTuple);
00219 
00220         inter_call_data->offset++;
00221 
00222         SRF_RETURN_NEXT(fctx, result);
00223     }
00224     else
00225         SRF_RETURN_DONE(fctx);
00226 }