From 896d5ca8038b866c14b28b0edaf6e15b35052da4 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 8 Jun 2009 16:22:44 +0000 Subject: [PATCH] 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. --- contrib/pageinspect/pageinspect.sql.in | 8 +-- contrib/pageinspect/rawpage.c | 56 +++++++++++++++++-- contrib/pageinspect/uninstall_pageinspect.sql | 2 + doc/src/sgml/pageinspect.sgml | 10 ++-- 4 files changed, 63 insertions(+), 13 deletions(-) diff --git a/contrib/pageinspect/pageinspect.sql.in b/contrib/pageinspect/pageinspect.sql.in index e320bec7e2..ca6406a6d3 100644 --- a/contrib/pageinspect/pageinspect.sql.in +++ b/contrib/pageinspect/pageinspect.sql.in @@ -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() diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c index 08d61fab87..55ef637836 100644 --- a/contrib/pageinspect/rawpage.c +++ b/contrib/pageinspect/rawpage.c @@ -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; } /* diff --git a/contrib/pageinspect/uninstall_pageinspect.sql b/contrib/pageinspect/uninstall_pageinspect.sql index f92b20ebe6..362c60449e 100644 --- a/contrib/pageinspect/uninstall_pageinspect.sql +++ b/contrib/pageinspect/uninstall_pageinspect.sql @@ -4,8 +4,10 @@ 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); diff --git a/doc/src/sgml/pageinspect.sgml b/doc/src/sgml/pageinspect.sgml index 8f4094439f..87028091c8 100644 --- a/doc/src/sgml/pageinspect.sgml +++ b/doc/src/sgml/pageinspect.sgml @@ -27,8 +27,9 @@ get_raw_page reads the specified block of the named table and returns a copy as a bytea value. This allows a single time-consistent copy of the block to be obtained. - fork should be 'main' for the main - data fork, or 'fsm' for the FSM. + fork should be 'main' for + the main data fork, or 'fsm' for the free space map, + or 'vm' for the visibility map. @@ -40,8 +41,9 @@ - A shorthand of above, for reading from the main fork. Equal to - get_raw_page(relname, 0, blkno) + A shorthand version of get_raw_page, for reading + from the main fork. Equivalent to + get_raw_page(relname, 'main', blkno) -- 2.39.5