Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit193f5f9

Browse files
committed
pageinspect: Add bt_page_items function with bytea argument
Author: Tomas Vondra <tomas.vondra@2ndquadrant.com>Reviewed-by: Ashutosh Sharma <ashu.coek88@gmail.com>
1 parent5ebeb57 commit193f5f9

File tree

6 files changed

+211
-51
lines changed

6 files changed

+211
-51
lines changed

‎contrib/pageinspect/btreefuncs.c

Lines changed: 147 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
PG_FUNCTION_INFO_V1(bt_metap);
4343
PG_FUNCTION_INFO_V1(bt_page_items);
44+
PG_FUNCTION_INFO_V1(bt_page_items_bytea);
4445
PG_FUNCTION_INFO_V1(bt_page_stats);
4546

4647
#defineIS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
@@ -235,14 +236,6 @@ bt_page_stats(PG_FUNCTION_ARGS)
235236
PG_RETURN_DATUM(result);
236237
}
237238

238-
/*-------------------------------------------------------
239-
* bt_page_items()
240-
*
241-
* Get IndexTupleData set in a btree page
242-
*
243-
* Usage: SELECT * FROM bt_page_items('t1_pkey', 1);
244-
*-------------------------------------------------------
245-
*/
246239

247240
/*
248241
* cross-call data structure for SRF
@@ -253,14 +246,72 @@ struct user_args
253246
OffsetNumberoffset;
254247
};
255248

249+
/*-------------------------------------------------------
250+
* bt_page_print_tuples()
251+
*
252+
* Form a tuple describing index tuple at a given offset
253+
* ------------------------------------------------------
254+
*/
255+
staticDatum
256+
bt_page_print_tuples(FuncCallContext*fctx,Pagepage,OffsetNumberoffset)
257+
{
258+
char*values[6];
259+
HeapTupletuple;
260+
ItemIdid;
261+
IndexTupleitup;
262+
intj;
263+
intoff;
264+
intdlen;
265+
char*dump;
266+
char*ptr;
267+
268+
id=PageGetItemId(page,offset);
269+
270+
if (!ItemIdIsValid(id))
271+
elog(ERROR,"invalid ItemId");
272+
273+
itup= (IndexTuple)PageGetItem(page,id);
274+
275+
j=0;
276+
values[j++]=psprintf("%d",offset);
277+
values[j++]=psprintf("(%u,%u)",
278+
ItemPointerGetBlockNumberNoCheck(&itup->t_tid),
279+
ItemPointerGetOffsetNumberNoCheck(&itup->t_tid));
280+
values[j++]=psprintf("%d", (int)IndexTupleSize(itup));
281+
values[j++]=psprintf("%c",IndexTupleHasNulls(itup) ?'t' :'f');
282+
values[j++]=psprintf("%c",IndexTupleHasVarwidths(itup) ?'t' :'f');
283+
284+
ptr= (char*)itup+IndexInfoFindDataOffset(itup->t_info);
285+
dlen=IndexTupleSize(itup)-IndexInfoFindDataOffset(itup->t_info);
286+
dump=palloc0(dlen*3+1);
287+
values[j]=dump;
288+
for (off=0;off<dlen;off++)
289+
{
290+
if (off>0)
291+
*dump++=' ';
292+
sprintf(dump,"%02x",*(ptr+off)&0xff);
293+
dump+=2;
294+
}
295+
296+
tuple=BuildTupleFromCStrings(fctx->attinmeta,values);
297+
298+
returnHeapTupleGetDatum(tuple);
299+
}
300+
301+
/*-------------------------------------------------------
302+
* bt_page_items()
303+
*
304+
* Get IndexTupleData set in a btree page
305+
*
306+
* Usage: SELECT * FROM bt_page_items('t1_pkey', 1);
307+
*-------------------------------------------------------
308+
*/
256309
Datum
257310
bt_page_items(PG_FUNCTION_ARGS)
258311
{
259312
text*relname=PG_GETARG_TEXT_PP(0);
260313
uint32blkno=PG_GETARG_UINT32(1);
261314
Datumresult;
262-
char*values[6];
263-
HeapTupletuple;
264315
FuncCallContext*fctx;
265316
MemoryContextmctx;
266317
structuser_args*uargs;
@@ -345,47 +396,8 @@ bt_page_items(PG_FUNCTION_ARGS)
345396

346397
if (fctx->call_cntr<fctx->max_calls)
347398
{
348-
ItemIdid;
349-
IndexTupleitup;
350-
intj;
351-
intoff;
352-
intdlen;
353-
char*dump;
354-
char*ptr;
355-
356-
id=PageGetItemId(uargs->page,uargs->offset);
357-
358-
if (!ItemIdIsValid(id))
359-
elog(ERROR,"invalid ItemId");
360-
361-
itup= (IndexTuple)PageGetItem(uargs->page,id);
362-
363-
j=0;
364-
values[j++]=psprintf("%d",uargs->offset);
365-
values[j++]=psprintf("(%u,%u)",
366-
ItemPointerGetBlockNumberNoCheck(&itup->t_tid),
367-
ItemPointerGetOffsetNumberNoCheck(&itup->t_tid));
368-
values[j++]=psprintf("%d", (int)IndexTupleSize(itup));
369-
values[j++]=psprintf("%c",IndexTupleHasNulls(itup) ?'t' :'f');
370-
values[j++]=psprintf("%c",IndexTupleHasVarwidths(itup) ?'t' :'f');
371-
372-
ptr= (char*)itup+IndexInfoFindDataOffset(itup->t_info);
373-
dlen=IndexTupleSize(itup)-IndexInfoFindDataOffset(itup->t_info);
374-
dump=palloc0(dlen*3+1);
375-
values[j]=dump;
376-
for (off=0;off<dlen;off++)
377-
{
378-
if (off>0)
379-
*dump++=' ';
380-
sprintf(dump,"%02x",*(ptr+off)&0xff);
381-
dump+=2;
382-
}
383-
384-
tuple=BuildTupleFromCStrings(fctx->attinmeta,values);
385-
result=HeapTupleGetDatum(tuple);
386-
387-
uargs->offset=uargs->offset+1;
388-
399+
result=bt_page_print_tuples(fctx,uargs->page,uargs->offset);
400+
uargs->offset++;
389401
SRF_RETURN_NEXT(fctx,result);
390402
}
391403
else
@@ -396,6 +408,90 @@ bt_page_items(PG_FUNCTION_ARGS)
396408
}
397409
}
398410

411+
/*-------------------------------------------------------
412+
* bt_page_items_bytea()
413+
*
414+
* Get IndexTupleData set in a btree page
415+
*
416+
* Usage: SELECT * FROM bt_page_items(get_raw_page('t1_pkey', 1));
417+
*-------------------------------------------------------
418+
*/
419+
420+
Datum
421+
bt_page_items_bytea(PG_FUNCTION_ARGS)
422+
{
423+
bytea*raw_page=PG_GETARG_BYTEA_P(0);
424+
Datumresult;
425+
FuncCallContext*fctx;
426+
structuser_args*uargs;
427+
intraw_page_size;
428+
429+
if (!superuser())
430+
ereport(ERROR,
431+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
432+
(errmsg("must be superuser to use pageinspect functions"))));
433+
434+
if (SRF_IS_FIRSTCALL())
435+
{
436+
BTPageOpaqueopaque;
437+
MemoryContextmctx;
438+
TupleDesctupleDesc;
439+
440+
raw_page_size=VARSIZE(raw_page)-VARHDRSZ;
441+
442+
if (raw_page_size<SizeOfPageHeaderData)
443+
ereport(ERROR,
444+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
445+
errmsg("input page too small (%d bytes)",raw_page_size)));
446+
447+
fctx=SRF_FIRSTCALL_INIT();
448+
mctx=MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
449+
450+
uargs=palloc(sizeof(structuser_args));
451+
452+
uargs->page=VARDATA(raw_page);
453+
454+
uargs->offset=FirstOffsetNumber;
455+
456+
opaque= (BTPageOpaque)PageGetSpecialPointer(uargs->page);
457+
458+
if (P_ISMETA(opaque))
459+
ereport(ERROR,
460+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
461+
errmsg("block is a meta page")));
462+
463+
if (P_ISDELETED(opaque))
464+
elog(NOTICE,"page is deleted");
465+
466+
fctx->max_calls=PageGetMaxOffsetNumber(uargs->page);
467+
468+
/* Build a tuple descriptor for our result type */
469+
if (get_call_result_type(fcinfo,NULL,&tupleDesc)!=TYPEFUNC_COMPOSITE)
470+
elog(ERROR,"return type must be a row type");
471+
472+
fctx->attinmeta=TupleDescGetAttInMetadata(tupleDesc);
473+
474+
fctx->user_fctx=uargs;
475+
476+
MemoryContextSwitchTo(mctx);
477+
}
478+
479+
fctx=SRF_PERCALL_SETUP();
480+
uargs=fctx->user_fctx;
481+
482+
if (fctx->call_cntr<fctx->max_calls)
483+
{
484+
result=bt_page_print_tuples(fctx,uargs->page,uargs->offset);
485+
uargs->offset++;
486+
SRF_RETURN_NEXT(fctx,result);
487+
}
488+
else
489+
{
490+
pfree(uargs);
491+
SRF_RETURN_DONE(fctx);
492+
}
493+
}
494+
399495

400496
/* ------------------------------------------------
401497
* bt_metap()

‎contrib/pageinspect/expected/btree.out

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,17 @@ data | 01 00 00 00 00 00 00 01
4242

4343
SELECT * FROM bt_page_items('test1_a_idx', 2);
4444
ERROR: block number out of range
45+
SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 0));
46+
ERROR: block is a meta page
47+
SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 1));
48+
-[ RECORD 1 ]-----------------------
49+
itemoffset | 1
50+
ctid | (0,1)
51+
itemlen | 16
52+
nulls | f
53+
vars | f
54+
data | 01 00 00 00 00 00 00 01
55+
56+
SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 2));
57+
ERROR: block number 2 is out of range for relation "test1_a_idx"
4558
DROP TABLE test1;

‎contrib/pageinspect/pageinspect--1.5--1.6.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,17 @@ CREATE FUNCTION page_checksum(IN page bytea, IN blkno int4)
8383
RETURNSsmallint
8484
AS'MODULE_PATHNAME','page_checksum'
8585
LANGUAGE C STRICT PARALLEL SAFE;
86+
87+
--
88+
-- bt_page_items_bytea()
89+
--
90+
CREATEFUNCTIONbt_page_items(IN pagebytea,
91+
OUT itemoffsetsmallint,
92+
OUT ctid tid,
93+
OUT itemlensmallint,
94+
OUT nulls bool,
95+
OUT vars bool,
96+
OUT datatext)
97+
RETURNS SETOF record
98+
AS'MODULE_PATHNAME','bt_page_items_bytea'
99+
LANGUAGE C STRICT PARALLEL SAFE;

‎contrib/pageinspect/sql/btree.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ SELECT * FROM bt_page_items('test1_a_idx', 0);
1414
SELECT*FROM bt_page_items('test1_a_idx',1);
1515
SELECT*FROM bt_page_items('test1_a_idx',2);
1616

17+
SELECT*FROM bt_page_items(get_raw_page('test1_a_idx',0));
18+
SELECT*FROM bt_page_items(get_raw_page('test1_a_idx',1));
19+
SELECT*FROM bt_page_items(get_raw_page('test1_a_idx',2));
20+
1721
DROPTABLE test1;

‎doc/src/sgml/pageinspect.sgml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,38 @@ test=# SELECT * FROM bt_page_items('pg_cast_oid_index', 1);
333333
</para>
334334
</listitem>
335335
</varlistentry>
336+
337+
<varlistentry>
338+
<term>
339+
<function>bt_page_items(page bytea) returns setof record</function>
340+
<indexterm>
341+
<primary>bt_page_items</primary>
342+
</indexterm>
343+
</term>
344+
345+
<listitem>
346+
<para>
347+
It is also possible to pass a page to <function>bt_page_items</function>
348+
as a <type>bytea</> value. A page image obtained
349+
with <function>get_raw_page</function> should be passed as argument. So
350+
the last example could also be rewritten like this:
351+
<screen>
352+
test=# SELECT * FROM bt_page_items(get_raw_page('pg_cast_oid_index', 1));
353+
itemoffset | ctid | itemlen | nulls | vars | data
354+
------------+---------+---------+-------+------+-------------
355+
1 | (0,1) | 12 | f | f | 23 27 00 00
356+
2 | (0,2) | 12 | f | f | 24 27 00 00
357+
3 | (0,3) | 12 | f | f | 25 27 00 00
358+
4 | (0,4) | 12 | f | f | 26 27 00 00
359+
5 | (0,5) | 12 | f | f | 27 27 00 00
360+
6 | (0,6) | 12 | f | f | 28 27 00 00
361+
7 | (0,7) | 12 | f | f | 29 27 00 00
362+
8 | (0,8) | 12 | f | f | 2a 27 00 00
363+
</screen>
364+
All the other details are the same as explained in the previous item.
365+
</para>
366+
</listitem>
367+
</varlistentry>
336368
</variablelist>
337369
</sect2>
338370

‎src/include/access/nbtree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ typedef struct BTMetaPageData
176176
#defineP_ISLEAF(opaque)((opaque)->btpo_flags & BTP_LEAF)
177177
#defineP_ISROOT(opaque)((opaque)->btpo_flags & BTP_ROOT)
178178
#defineP_ISDELETED(opaque)((opaque)->btpo_flags & BTP_DELETED)
179+
#defineP_ISMETA(opaque)((opaque)->btpo_flags & BTP_META)
179180
#defineP_ISHALFDEAD(opaque)((opaque)->btpo_flags & BTP_HALF_DEAD)
180181
#defineP_IGNORE(opaque)((opaque)->btpo_flags & (BTP_DELETED|BTP_HALF_DEAD))
181182
#defineP_HAS_GARBAGE(opaque)((opaque)->btpo_flags & BTP_HAS_GARBAGE)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp