mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	pageinspect: Add page_checksum function
Author: Tomas Vondra <tomas.vondra@2ndquadrant.com> Reviewed-by: Ashutosh Sharma <ashu.coek88@gmail.com>
This commit is contained in:
		@@ -49,6 +49,12 @@ SELECT pagesize, version FROM page_header(get_raw_page('test1', 0));
 | 
				
			|||||||
     8192 |       4
 | 
					     8192 |       4
 | 
				
			||||||
(1 row)
 | 
					(1 row)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_test;
 | 
				
			||||||
 | 
					 silly_checksum_test 
 | 
				
			||||||
 | 
					---------------------
 | 
				
			||||||
 | 
					 t
 | 
				
			||||||
 | 
					(1 row)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits)
 | 
					SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits)
 | 
				
			||||||
    FROM heap_page_items(get_raw_page('test1', 0));
 | 
					    FROM heap_page_items(get_raw_page('test1', 0));
 | 
				
			||||||
       tuple_data_split        
 | 
					       tuple_data_split        
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,3 +75,11 @@ CREATE FUNCTION hash_metapage_info(IN page bytea,
 | 
				
			|||||||
    OUT mapp int8[])
 | 
					    OUT mapp int8[])
 | 
				
			||||||
AS 'MODULE_PATHNAME', 'hash_metapage_info'
 | 
					AS 'MODULE_PATHNAME', 'hash_metapage_info'
 | 
				
			||||||
LANGUAGE C STRICT PARALLEL SAFE;
 | 
					LANGUAGE C STRICT PARALLEL SAFE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					-- page_checksum()
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					CREATE FUNCTION page_checksum(IN page bytea, IN blkno int4)
 | 
				
			||||||
 | 
					RETURNS smallint
 | 
				
			||||||
 | 
					AS 'MODULE_PATHNAME', 'page_checksum'
 | 
				
			||||||
 | 
					LANGUAGE C STRICT PARALLEL SAFE;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@
 | 
				
			|||||||
#include "funcapi.h"
 | 
					#include "funcapi.h"
 | 
				
			||||||
#include "miscadmin.h"
 | 
					#include "miscadmin.h"
 | 
				
			||||||
#include "storage/bufmgr.h"
 | 
					#include "storage/bufmgr.h"
 | 
				
			||||||
 | 
					#include "storage/checksum.h"
 | 
				
			||||||
#include "utils/builtins.h"
 | 
					#include "utils/builtins.h"
 | 
				
			||||||
#include "utils/pg_lsn.h"
 | 
					#include "utils/pg_lsn.h"
 | 
				
			||||||
#include "utils/rel.h"
 | 
					#include "utils/rel.h"
 | 
				
			||||||
@@ -280,3 +281,39 @@ page_header(PG_FUNCTION_ARGS)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	PG_RETURN_DATUM(result);
 | 
						PG_RETURN_DATUM(result);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * page_checksum
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Compute checksum of a raw page
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PG_FUNCTION_INFO_V1(page_checksum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Datum
 | 
				
			||||||
 | 
					page_checksum(PG_FUNCTION_ARGS)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bytea	   *raw_page = PG_GETARG_BYTEA_P(0);
 | 
				
			||||||
 | 
						uint32		blkno = PG_GETARG_INT32(1);
 | 
				
			||||||
 | 
						int			raw_page_size;
 | 
				
			||||||
 | 
						PageHeader	page;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!superuser())
 | 
				
			||||||
 | 
							ereport(ERROR,
 | 
				
			||||||
 | 
									(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 | 
				
			||||||
 | 
									 (errmsg("must be superuser to use raw page functions"))));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						raw_page_size = VARSIZE(raw_page) - VARHDRSZ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Check that the supplied page is of the right size.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (raw_page_size != BLCKSZ)
 | 
				
			||||||
 | 
							ereport(ERROR,
 | 
				
			||||||
 | 
									(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 | 
				
			||||||
 | 
									 errmsg("incorrect size of input page (%d bytes)", raw_page_size)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						page = (PageHeader) VARDATA(raw_page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PG_RETURN_INT16(pg_checksum_page((char *)page, blkno));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,8 @@ SELECT get_raw_page('test1', 0) = get_raw_page('test1', 'main', 0);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
SELECT pagesize, version FROM page_header(get_raw_page('test1', 0));
 | 
					SELECT pagesize, version FROM page_header(get_raw_page('test1', 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits)
 | 
					SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits)
 | 
				
			||||||
    FROM heap_page_items(get_raw_page('test1', 0));
 | 
					    FROM heap_page_items(get_raw_page('test1', 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,12 +73,55 @@
 | 
				
			|||||||
test=# SELECT * FROM page_header(get_raw_page('pg_class', 0));
 | 
					test=# SELECT * FROM page_header(get_raw_page('pg_class', 0));
 | 
				
			||||||
    lsn    | checksum | flags  | lower | upper | special | pagesize | version | prune_xid
 | 
					    lsn    | checksum | flags  | lower | upper | special | pagesize | version | prune_xid
 | 
				
			||||||
-----------+----------+--------+-------+-------+---------+----------+---------+-----------
 | 
					-----------+----------+--------+-------+-------+---------+----------+---------+-----------
 | 
				
			||||||
 0/24A1B50 |        1 |      1 |   232 |   368 |    8192 |     8192 |       4 |         0
 | 
					 0/24A1B50 |        0 |      1 |   232 |   368 |    8192 |     8192 |       4 |         0
 | 
				
			||||||
</screen>
 | 
					</screen>
 | 
				
			||||||
      The returned columns correspond to the fields in the
 | 
					      The returned columns correspond to the fields in the
 | 
				
			||||||
      <structname>PageHeaderData</> struct.
 | 
					      <structname>PageHeaderData</> struct.
 | 
				
			||||||
      See <filename>src/include/storage/bufpage.h</> for details.
 | 
					      See <filename>src/include/storage/bufpage.h</> for details.
 | 
				
			||||||
     </para>
 | 
					     </para>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     <para>
 | 
				
			||||||
 | 
					      The <structfield>checksum</structfield> field is the checksum stored in
 | 
				
			||||||
 | 
					      the page, which might be incorrect if the page is somehow corrupted.  If
 | 
				
			||||||
 | 
					      data checksums are not enabled for this instance, then the value stored
 | 
				
			||||||
 | 
					      is meaningless.
 | 
				
			||||||
 | 
					     </para>
 | 
				
			||||||
 | 
					    </listitem>
 | 
				
			||||||
 | 
					   </varlistentry>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   <varlistentry>
 | 
				
			||||||
 | 
					    <term>
 | 
				
			||||||
 | 
					     <function>page_checksum(page bytea, blkno int4) returns smallint</function>
 | 
				
			||||||
 | 
					     <indexterm>
 | 
				
			||||||
 | 
					      <primary>page_checksum</primary>
 | 
				
			||||||
 | 
					     </indexterm>
 | 
				
			||||||
 | 
					    </term>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <listitem>
 | 
				
			||||||
 | 
					     <para>
 | 
				
			||||||
 | 
					      <function>page_checksum</function> computes the checksum for the page, as if
 | 
				
			||||||
 | 
					      it was located at the given block.
 | 
				
			||||||
 | 
					     </para>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     <para>
 | 
				
			||||||
 | 
					      A page image obtained with <function>get_raw_page</function> should be
 | 
				
			||||||
 | 
					      passed as argument.  For example:
 | 
				
			||||||
 | 
					<screen>
 | 
				
			||||||
 | 
					test=# SELECT page_checksum(get_raw_page('pg_class', 0), 0);
 | 
				
			||||||
 | 
					 page_checksum
 | 
				
			||||||
 | 
					---------------
 | 
				
			||||||
 | 
					         13443
 | 
				
			||||||
 | 
					</screen>
 | 
				
			||||||
 | 
					      Note that the checksum depends on the block number, so matching block
 | 
				
			||||||
 | 
					      numbers should be passed (except when doing esoteric debugging).
 | 
				
			||||||
 | 
					     </para>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     <para>
 | 
				
			||||||
 | 
					      The checksum computed with this function can be compared with
 | 
				
			||||||
 | 
					      the <structfield>checksum</structfield> result field of the
 | 
				
			||||||
 | 
					      function <function>page_header</function>.  If data checksums are
 | 
				
			||||||
 | 
					      enabled for this instance, then the two values should be equal.
 | 
				
			||||||
 | 
					     </para>
 | 
				
			||||||
    </listitem>
 | 
					    </listitem>
 | 
				
			||||||
   </varlistentry>
 | 
					   </varlistentry>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user