Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f18aa1b

Browse files
committed
pageinspect: Change block number arguments to bigint
Block numbers are 32-bit unsigned integers. Therefore, the smallest SQL integer type that they can fit in is bigint. However, in the pageinspect module, most input and output parameters dealing with block numbers were declared as int. The behavior with block numbers larger than a signed 32-bit integer was therefore dubious. Change these arguments to type bigint and add some more explicit error checking on the block range. (Other contrib modules appear to do this correctly already.) Since we are changing argument types of existing functions, in order to not misbehave if the binary is updated before the extension is updated, we need to create new C symbols for the entry points, similar to how it's done in other extensions as well. Reported-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com> Reviewed-by: Alvaro Herrera <alvherre@alvh.no-ip.org> Reviewed-by: Michael Paquier <michael@paquier.xyz> Discussion: https://www.postgresql.org/message-id/flat/d8f6bdd536df403b9b33816e9f7e0b9d@G08CNEXMBPEKD05.g08.fujitsu.local
1 parent ee79a54 commit f18aa1b

18 files changed

+328
-31
lines changed

contrib/pageinspect/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ DATA = pageinspect--1.8--1.9.sql \
2121
pageinspect--1.0--1.1.sql
2222
PGFILEDESC = "pageinspect - functions to inspect contents of database pages"
2323

24-
REGRESS = page btree brin gin gist hash checksum
24+
REGRESS = page btree brin gin gist hash checksum oldextversions
2525

2626
ifdef USE_PGXS
2727
PG_CONFIG = pg_config

contrib/pageinspect/brinfuncs.c

+12-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,18 @@ brin_page_items(PG_FUNCTION_ARGS)
252252
int att = attno - 1;
253253

254254
values[0] = UInt16GetDatum(offset);
255-
values[1] = UInt32GetDatum(dtup->bt_blkno);
255+
switch (TupleDescAttr(tupdesc, 1)->atttypid)
256+
{
257+
case INT8OID:
258+
values[1] = Int64GetDatum((int64) dtup->bt_blkno);
259+
break;
260+
case INT4OID:
261+
/* support for old extension version */
262+
values[1] = UInt32GetDatum(dtup->bt_blkno);
263+
break;
264+
default:
265+
elog(ERROR, "incorrect output types");
266+
}
256267
values[2] = UInt16GetDatum(attno);
257268
values[3] = BoolGetDatum(dtup->bt_columns[att].bv_allnulls);
258269
values[4] = BoolGetDatum(dtup->bt_columns[att].bv_hasnulls);

contrib/pageinspect/btreefuncs.c

+59-17
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@
4141
#include "utils/varlena.h"
4242

4343
PG_FUNCTION_INFO_V1(bt_metap);
44+
PG_FUNCTION_INFO_V1(bt_page_items_1_9);
4445
PG_FUNCTION_INFO_V1(bt_page_items);
4546
PG_FUNCTION_INFO_V1(bt_page_items_bytea);
47+
PG_FUNCTION_INFO_V1(bt_page_stats_1_9);
4648
PG_FUNCTION_INFO_V1(bt_page_stats);
4749

4850
#define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
@@ -160,11 +162,11 @@ GetBTPageStatistics(BlockNumber blkno, Buffer buffer, BTPageStat *stat)
160162
* Usage: SELECT * FROM bt_page_stats('t1_pkey', 1);
161163
* -----------------------------------------------
162164
*/
163-
Datum
164-
bt_page_stats(PG_FUNCTION_ARGS)
165+
static Datum
166+
bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
165167
{
166168
text *relname = PG_GETARG_TEXT_PP(0);
167-
uint32 blkno = PG_GETARG_UINT32(1);
169+
int64 blkno = (ext_version == PAGEINSPECT_V1_8 ? PG_GETARG_UINT32(1) : PG_GETARG_INT64(1));
168170
Buffer buffer;
169171
Relation rel;
170172
RangeVar *relrv;
@@ -197,8 +199,15 @@ bt_page_stats(PG_FUNCTION_ARGS)
197199
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
198200
errmsg("cannot access temporary tables of other sessions")));
199201

202+
if (blkno < 0 || blkno > MaxBlockNumber)
203+
ereport(ERROR,
204+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
205+
errmsg("invalid block number")));
206+
200207
if (blkno == 0)
201-
elog(ERROR, "block 0 is a meta page");
208+
ereport(ERROR,
209+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
210+
errmsg("block 0 is a meta page")));
202211

203212
CHECK_RELATION_BLOCK_RANGE(rel, blkno);
204213

@@ -219,16 +228,16 @@ bt_page_stats(PG_FUNCTION_ARGS)
219228
elog(ERROR, "return type must be a row type");
220229

221230
j = 0;
222-
values[j++] = psprintf("%d", stat.blkno);
231+
values[j++] = psprintf("%u", stat.blkno);
223232
values[j++] = psprintf("%c", stat.type);
224-
values[j++] = psprintf("%d", stat.live_items);
225-
values[j++] = psprintf("%d", stat.dead_items);
226-
values[j++] = psprintf("%d", stat.avg_item_size);
227-
values[j++] = psprintf("%d", stat.page_size);
228-
values[j++] = psprintf("%d", stat.free_size);
229-
values[j++] = psprintf("%d", stat.btpo_prev);
230-
values[j++] = psprintf("%d", stat.btpo_next);
231-
values[j++] = psprintf("%d", (stat.type == 'd') ? stat.btpo.xact : stat.btpo.level);
233+
values[j++] = psprintf("%u", stat.live_items);
234+
values[j++] = psprintf("%u", stat.dead_items);
235+
values[j++] = psprintf("%u", stat.avg_item_size);
236+
values[j++] = psprintf("%u", stat.page_size);
237+
values[j++] = psprintf("%u", stat.free_size);
238+
values[j++] = psprintf("%u", stat.btpo_prev);
239+
values[j++] = psprintf("%u", stat.btpo_next);
240+
values[j++] = psprintf("%u", (stat.type == 'd') ? stat.btpo.xact : stat.btpo.level);
232241
values[j++] = psprintf("%d", stat.btpo_flags);
233242

234243
tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
@@ -239,6 +248,19 @@ bt_page_stats(PG_FUNCTION_ARGS)
239248
PG_RETURN_DATUM(result);
240249
}
241250

251+
Datum
252+
bt_page_stats_1_9(PG_FUNCTION_ARGS)
253+
{
254+
return bt_page_stats_internal(fcinfo, PAGEINSPECT_V1_9);
255+
}
256+
257+
/* entry point for old extension version */
258+
Datum
259+
bt_page_stats(PG_FUNCTION_ARGS)
260+
{
261+
return bt_page_stats_internal(fcinfo, PAGEINSPECT_V1_8);
262+
}
263+
242264

243265
/*
244266
* cross-call data structure for SRF
@@ -405,11 +427,11 @@ bt_page_print_tuples(struct user_args *uargs)
405427
* Usage: SELECT * FROM bt_page_items('t1_pkey', 1);
406428
*-------------------------------------------------------
407429
*/
408-
Datum
409-
bt_page_items(PG_FUNCTION_ARGS)
430+
static Datum
431+
bt_page_items_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
410432
{
411433
text *relname = PG_GETARG_TEXT_PP(0);
412-
uint32 blkno = PG_GETARG_UINT32(1);
434+
int64 blkno = (ext_version == PAGEINSPECT_V1_8 ? PG_GETARG_UINT32(1) : PG_GETARG_INT64(1));
413435
Datum result;
414436
FuncCallContext *fctx;
415437
MemoryContext mctx;
@@ -447,8 +469,15 @@ bt_page_items(PG_FUNCTION_ARGS)
447469
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
448470
errmsg("cannot access temporary tables of other sessions")));
449471

472+
if (blkno < 0 || blkno > MaxBlockNumber)
473+
ereport(ERROR,
474+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
475+
errmsg("invalid block number")));
476+
450477
if (blkno == 0)
451-
elog(ERROR, "block 0 is a meta page");
478+
ereport(ERROR,
479+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
480+
errmsg("block 0 is a meta page")));
452481

453482
CHECK_RELATION_BLOCK_RANGE(rel, blkno);
454483

@@ -506,6 +535,19 @@ bt_page_items(PG_FUNCTION_ARGS)
506535
SRF_RETURN_DONE(fctx);
507536
}
508537

538+
Datum
539+
bt_page_items_1_9(PG_FUNCTION_ARGS)
540+
{
541+
return bt_page_items_internal(fcinfo, PAGEINSPECT_V1_9);
542+
}
543+
544+
/* entry point for old extension version */
545+
Datum
546+
bt_page_items(PG_FUNCTION_ARGS)
547+
{
548+
return bt_page_items_internal(fcinfo, PAGEINSPECT_V1_8);
549+
}
550+
509551
/*-------------------------------------------------------
510552
* bt_page_items_bytea()
511553
*

contrib/pageinspect/expected/btree.out

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ oldest_xact | 0
1414
last_cleanup_num_tuples | -1
1515
allequalimage | t
1616

17+
SELECT * FROM bt_page_stats('test1_a_idx', -1);
18+
ERROR: invalid block number
1719
SELECT * FROM bt_page_stats('test1_a_idx', 0);
1820
ERROR: block 0 is a meta page
1921
SELECT * FROM bt_page_stats('test1_a_idx', 1);
@@ -32,6 +34,8 @@ btpo_flags | 3
3234

3335
SELECT * FROM bt_page_stats('test1_a_idx', 2);
3436
ERROR: block number out of range
37+
SELECT * FROM bt_page_items('test1_a_idx', -1);
38+
ERROR: invalid block number
3539
SELECT * FROM bt_page_items('test1_a_idx', 0);
3640
ERROR: block 0 is a meta page
3741
SELECT * FROM bt_page_items('test1_a_idx', 1);
@@ -48,6 +52,8 @@ tids |
4852

4953
SELECT * FROM bt_page_items('test1_a_idx', 2);
5054
ERROR: block number out of range
55+
SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', -1));
56+
ERROR: invalid block number
5157
SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 0));
5258
ERROR: block is a meta page
5359
SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 1));

contrib/pageinspect/expected/gin.out

+1
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ FROM gin_leafpage_items(get_raw_page('test1_y_idx',
3535
-[ RECORD 1 ]
3636
?column? | t
3737

38+
DROP TABLE test1;

contrib/pageinspect/expected/hash.out

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ hash_page_type | bitmap
2828

2929
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 6));
3030
ERROR: block number 6 is out of range for relation "test_hash_a_idx"
31+
SELECT * FROM hash_bitmap_info('test_hash_a_idx', -1);
32+
ERROR: invalid block number
3133
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 0);
3234
ERROR: invalid overflow block number 0
3335
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 1);
@@ -40,6 +42,8 @@ SELECT * FROM hash_bitmap_info('test_hash_a_idx', 4);
4042
ERROR: invalid overflow block number 4
4143
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 5);
4244
ERROR: invalid overflow block number 5
45+
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 6);
46+
ERROR: block number 6 is out of range for relation "test_hash_a_idx"
4347
SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask,
4448
lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM
4549
hash_metapage_info(get_raw_page('test_hash_a_idx', 0));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
-- test old extension version entry points
2+
DROP EXTENSION pageinspect;
3+
CREATE EXTENSION pageinspect VERSION '1.8';
4+
CREATE TABLE test1 (a int8, b text);
5+
INSERT INTO test1 VALUES (72057594037927937, 'text');
6+
CREATE INDEX test1_a_idx ON test1 USING btree (a);
7+
-- from page.sql
8+
SELECT octet_length(get_raw_page('test1', 0)) AS main_0;
9+
main_0
10+
--------
11+
8192
12+
(1 row)
13+
14+
SELECT octet_length(get_raw_page('test1', 'main', 0)) AS main_0;
15+
main_0
16+
--------
17+
8192
18+
(1 row)
19+
20+
SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_test;
21+
silly_checksum_test
22+
---------------------
23+
t
24+
(1 row)
25+
26+
-- from btree.sql
27+
SELECT * FROM bt_page_stats('test1_a_idx', 1);
28+
blkno | type | live_items | dead_items | avg_item_size | page_size | free_size | btpo_prev | btpo_next | btpo | btpo_flags
29+
-------+------+------------+------------+---------------+-----------+-----------+-----------+-----------+------+------------
30+
1 | l | 1 | 0 | 16 | 8192 | 8128 | 0 | 0 | 0 | 3
31+
(1 row)
32+
33+
SELECT * FROM bt_page_items('test1_a_idx', 1);
34+
itemoffset | ctid | itemlen | nulls | vars | data | dead | htid | tids
35+
------------+-------+---------+-------+------+-------------------------+------+-------+------
36+
1 | (0,1) | 16 | f | f | 01 00 00 00 00 00 00 01 | f | (0,1) |
37+
(1 row)
38+
39+
DROP TABLE test1;
40+
DROP EXTENSION pageinspect;

contrib/pageinspect/expected/page.out

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ SELECT octet_length(get_raw_page('test1', 'vm', 0)) AS vm_0;
3232

3333
SELECT octet_length(get_raw_page('test1', 'vm', 1)) AS vm_1;
3434
ERROR: block number 1 is out of range for relation "test1"
35+
SELECT octet_length(get_raw_page('test1', 'main', -1));
36+
ERROR: invalid block number
3537
SELECT octet_length(get_raw_page('xxx', 'main', 0));
3638
ERROR: relation "xxx" does not exist
3739
SELECT octet_length(get_raw_page('test1', 'xxx', 0));
@@ -55,6 +57,8 @@ SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_
5557
t
5658
(1 row)
5759

60+
SELECT page_checksum(get_raw_page('test1', 0), -1);
61+
ERROR: invalid block number
5862
SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits)
5963
FROM heap_page_items(get_raw_page('test1', 0));
6064
tuple_data_split

contrib/pageinspect/hashfuncs.c

+8-3
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ Datum
390390
hash_bitmap_info(PG_FUNCTION_ARGS)
391391
{
392392
Oid indexRelid = PG_GETARG_OID(0);
393-
uint64 ovflblkno = PG_GETARG_INT64(1);
393+
int64 ovflblkno = PG_GETARG_INT64(1);
394394
HashMetaPage metap;
395395
Buffer metabuf,
396396
mapbuf;
@@ -425,11 +425,16 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
425425
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
426426
errmsg("cannot access temporary tables of other sessions")));
427427

428+
if (ovflblkno < 0 || ovflblkno > MaxBlockNumber)
429+
ereport(ERROR,
430+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
431+
errmsg("invalid block number")));
432+
428433
if (ovflblkno >= RelationGetNumberOfBlocks(indexRel))
429434
ereport(ERROR,
430435
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
431-
errmsg("block number " UINT64_FORMAT " is out of range for relation \"%s\"",
432-
ovflblkno, RelationGetRelationName(indexRel))));
436+
errmsg("block number %lld is out of range for relation \"%s\"",
437+
(long long int) ovflblkno, RelationGetRelationName(indexRel))));
433438

434439
/* Read the metapage so we can determine which bitmap page to use */
435440
metabuf = _hash_getbuf(indexRel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);

contrib/pageinspect/pageinspect--1.8--1.9.sql

+77
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,80 @@ CREATE FUNCTION gist_page_items(IN page bytea,
3939
RETURNS SETOF record
4040
AS 'MODULE_PATHNAME', 'gist_page_items'
4141
LANGUAGE C STRICT PARALLEL SAFE;
42+
43+
--
44+
-- get_raw_page()
45+
--
46+
DROP FUNCTION get_raw_page(text, int4);
47+
CREATE FUNCTION get_raw_page(text, int8)
48+
RETURNS bytea
49+
AS 'MODULE_PATHNAME', 'get_raw_page_1_9'
50+
LANGUAGE C STRICT PARALLEL SAFE;
51+
52+
DROP FUNCTION get_raw_page(text, text, int4);
53+
CREATE FUNCTION get_raw_page(text, text, int8)
54+
RETURNS bytea
55+
AS 'MODULE_PATHNAME', 'get_raw_page_fork_1_9'
56+
LANGUAGE C STRICT PARALLEL SAFE;
57+
58+
--
59+
-- page_checksum()
60+
--
61+
DROP FUNCTION page_checksum(IN page bytea, IN blkno int4);
62+
CREATE FUNCTION page_checksum(IN page bytea, IN blkno int8)
63+
RETURNS smallint
64+
AS 'MODULE_PATHNAME', 'page_checksum_1_9'
65+
LANGUAGE C STRICT PARALLEL SAFE;
66+
67+
--
68+
-- bt_page_stats()
69+
--
70+
DROP FUNCTION bt_page_stats(text, int4);
71+
CREATE FUNCTION bt_page_stats(IN relname text, IN blkno int8,
72+
OUT blkno int8,
73+
OUT type "char",
74+
OUT live_items int4,
75+
OUT dead_items int4,
76+
OUT avg_item_size int4,
77+
OUT page_size int4,
78+
OUT free_size int4,
79+
OUT btpo_prev int8,
80+
OUT btpo_next int8,
81+
OUT btpo int4,
82+
OUT btpo_flags int4)
83+
AS 'MODULE_PATHNAME', 'bt_page_stats_1_9'
84+
LANGUAGE C STRICT PARALLEL SAFE;
85+
86+
--
87+
-- bt_page_items()
88+
--
89+
DROP FUNCTION bt_page_items(text, int4);
90+
CREATE FUNCTION bt_page_items(IN relname text, IN blkno int8,
91+
OUT itemoffset smallint,
92+
OUT ctid tid,
93+
OUT itemlen smallint,
94+
OUT nulls bool,
95+
OUT vars bool,
96+
OUT data text,
97+
OUT dead boolean,
98+
OUT htid tid,
99+
OUT tids tid[])
100+
RETURNS SETOF record
101+
AS 'MODULE_PATHNAME', 'bt_page_items_1_9'
102+
LANGUAGE C STRICT PARALLEL SAFE;
103+
104+
--
105+
-- brin_page_items()
106+
--
107+
DROP FUNCTION brin_page_items(IN page bytea, IN index_oid regclass);
108+
CREATE FUNCTION brin_page_items(IN page bytea, IN index_oid regclass,
109+
OUT itemoffset int,
110+
OUT blknum int8,
111+
OUT attnum int,
112+
OUT allnulls bool,
113+
OUT hasnulls bool,
114+
OUT placeholder bool,
115+
OUT value text)
116+
RETURNS SETOF record
117+
AS 'MODULE_PATHNAME', 'brin_page_items'
118+
LANGUAGE C STRICT PARALLEL SAFE;

0 commit comments

Comments
 (0)