Fix contrib/pageinspect to not create an ABI breakage between 8.3 and 8.4.

The original implementation of the 3-argument form of get_raw_page() risked
core dumps if the 8.3 SQL function definition was mistakenly used with the
8.4 module, which is entirely likely after a dump-and-reload upgrade.  To
protect 8.4 beta testers against upgrade problems, add a check on PG_NARGS.

In passing, fix missed additions to the uninstall script, and polish the
docs a trifle.
This commit is contained in:
Tom Lane 2009-06-08 16:22:44 +00:00
parent 506183e485
commit a1fd650d2b
4 changed files with 67 additions and 17 deletions

View File

@ -1,4 +1,4 @@
/* $PostgreSQL: pgsql/contrib/pageinspect/pageinspect.sql.in,v 1.6 2008/10/06 14:13:17 heikki Exp $ */
/* $PostgreSQL: pgsql/contrib/pageinspect/pageinspect.sql.in,v 1.7 2009/06/08 16:22:44 tgl Exp $ */
-- Adjust this setting to control where the objects get created.
SET search_path = public;
@ -6,15 +6,15 @@ SET search_path = public;
--
-- get_raw_page()
--
CREATE OR REPLACE FUNCTION get_raw_page(text, text, int4)
CREATE OR REPLACE FUNCTION get_raw_page(text, int4)
RETURNS bytea
AS 'MODULE_PATHNAME', 'get_raw_page'
LANGUAGE C STRICT;
CREATE OR REPLACE FUNCTION get_raw_page(text, int4)
CREATE OR REPLACE FUNCTION get_raw_page(text, text, int4)
RETURNS bytea
AS $$ SELECT get_raw_page($1, 'main', $2); $$
LANGUAGE SQL STRICT;
AS 'MODULE_PATHNAME', 'get_raw_page_fork'
LANGUAGE C STRICT;
--
-- page_header()

View File

@ -8,7 +8,7 @@
* Copyright (c) 2007-2009, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/contrib/pageinspect/rawpage.c,v 1.11 2009/03/31 22:54:31 tgl Exp $
* $PostgreSQL: pgsql/contrib/pageinspect/rawpage.c,v 1.12 2009/06/08 16:22:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -29,8 +29,13 @@
PG_MODULE_MAGIC;
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
*
@ -40,15 +45,58 @@ PG_FUNCTION_INFO_V1(get_raw_page);
Datum
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;
Relation rel;
RangeVar *relrv;
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;
char *raw_page_data;
Buffer buf;
@ -57,8 +105,6 @@ get_raw_page(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser to use raw functions"))));
forknum = forkname_to_number(text_to_cstring(forkname));
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
rel = relation_openrv(relrv, AccessShareLock);
@ -105,7 +151,7 @@ get_raw_page(PG_FUNCTION_ARGS)
relation_close(rel, AccessShareLock);
PG_RETURN_BYTEA_P(raw_page);
return raw_page;
}
/*

View File

@ -1,11 +1,13 @@
/* $PostgreSQL: pgsql/contrib/pageinspect/uninstall_pageinspect.sql,v 1.4 2007/11/13 04:24:28 momjian Exp $ */
/* $PostgreSQL: pgsql/contrib/pageinspect/uninstall_pageinspect.sql,v 1.5 2009/06/08 16:22:44 tgl Exp $ */
-- Adjust this setting to control where the objects get dropped.
SET search_path = public;
DROP FUNCTION get_raw_page(text, int4);
DROP FUNCTION get_raw_page(text, text, int4);
DROP FUNCTION page_header(bytea);
DROP FUNCTION heap_page_items(bytea);
DROP FUNCTION bt_metap(text);
DROP FUNCTION bt_page_stats(text, int4);
DROP FUNCTION bt_page_items(text, int4);
DROP FUNCTION fsm_page_contents(bytea);

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/pageinspect.sgml,v 1.5 2008/10/06 14:13:17 heikki Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/pageinspect.sgml,v 1.6 2009/06/08 16:22:44 tgl Exp $ -->
<sect1 id="pageinspect">
<title>pageinspect</title>
@ -27,8 +27,9 @@
<function>get_raw_page</function> reads the specified block of the named
table and returns a copy as a <type>bytea</> value. This allows a
single time-consistent copy of the block to be obtained.
<literal>fork</literal> should be <literal>'main'</literal> for the main
data fork, or <literal>'fsm'</literal> for the FSM.
<replaceable>fork</replaceable> should be <literal>'main'</literal> for
the main data fork, or <literal>'fsm'</literal> for the free space map,
or <literal>'vm'</literal> for the visibility map.
</para>
</listitem>
</varlistentry>
@ -40,8 +41,9 @@
<listitem>
<para>
A shorthand of above, for reading from the main fork. Equal to
<literal>get_raw_page(relname, 0, blkno)</literal>
A shorthand version of <function>get_raw_page</function>, for reading
from the main fork. Equivalent to
<literal>get_raw_page(relname, 'main', blkno)</literal>
</para>
</listitem>
</varlistentry>