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

Commit756ab29

Browse files
committed
Add functions to 'pageinspect' to inspect GiST indexes.
Author: Andrey Borodin and meDiscussion:https://www.postgresql.org/message-id/3E4F9093-A1B5-4DF8-A292-0B48692E3954%40yandex-team.ru
1 parentdf10ac6 commit756ab29

File tree

7 files changed

+527
-3
lines changed

7 files changed

+527
-3
lines changed

‎contrib/pageinspect/Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,21 @@ OBJS = \
77
btreefuncs.o\
88
fsmfuncs.o\
99
ginfuncs.o\
10+
gistfuncs.o\
1011
hashfuncs.o\
1112
heapfuncs.o\
1213
rawpage.o
1314

1415
EXTENSION = pageinspect
15-
DATA = pageinspect--1.7--1.8.sql pageinspect--1.6--1.7.sql\
16+
DATA = pageinspect--1.8--1.9.sql\
17+
pageinspect--1.7--1.8.sql pageinspect--1.6--1.7.sql\
1618
pageinspect--1.5.sql pageinspect--1.5--1.6.sql\
1719
pageinspect--1.4--1.5.sql pageinspect--1.3--1.4.sql\
1820
pageinspect--1.2--1.3.sql pageinspect--1.1--1.2.sql\
1921
pageinspect--1.0--1.1.sql
2022
PGFILEDESC = "pageinspect - functions to inspect contents of database pages"
2123

22-
REGRESS = page btree brin gin hash checksum
24+
REGRESS = page btree brin gingisthash checksum
2325

2426
ifdefUSE_PGXS
2527
PG_CONFIG = pg_config

‎contrib/pageinspect/expected/gist.out

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
CREATE TABLE test_gist AS SELECT point(i,i) p, i::text t FROM
2+
generate_series(1,1000) i;
3+
CREATE INDEX test_gist_idx ON test_gist USING gist (p);
4+
-- Page 0 is the root, the rest are leaf pages
5+
SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 0));
6+
lsn | nsn | rightlink | flags
7+
-----+-----+------------+-------
8+
0/1 | 0/0 | 4294967295 | {}
9+
(1 row)
10+
11+
SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 1));
12+
lsn | nsn | rightlink | flags
13+
-----+-----+------------+--------
14+
0/1 | 0/0 | 4294967295 | {leaf}
15+
(1 row)
16+
17+
SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2));
18+
lsn | nsn | rightlink | flags
19+
-----+-----+-----------+--------
20+
0/1 | 0/0 | 1 | {leaf}
21+
(1 row)
22+
23+
SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx');
24+
itemoffset | ctid | itemlen | keys
25+
------------+-----------+---------+-------------------
26+
1 | (1,65535) | 40 | (p)=((166,166))
27+
2 | (2,65535) | 40 | (p)=((332,332))
28+
3 | (3,65535) | 40 | (p)=((498,498))
29+
4 | (4,65535) | 40 | (p)=((664,664))
30+
5 | (5,65535) | 40 | (p)=((830,830))
31+
6 | (6,65535) | 40 | (p)=((996,996))
32+
7 | (7,65535) | 40 | (p)=((1000,1000))
33+
(7 rows)
34+
35+
SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 1), 'test_gist_idx') LIMIT 5;
36+
itemoffset | ctid | itemlen | keys
37+
------------+-------+---------+-------------
38+
1 | (0,1) | 40 | (p)=((1,1))
39+
2 | (0,2) | 40 | (p)=((2,2))
40+
3 | (0,3) | 40 | (p)=((3,3))
41+
4 | (0,4) | 40 | (p)=((4,4))
42+
5 | (0,5) | 40 | (p)=((5,5))
43+
(5 rows)
44+
45+
SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 2), 'test_gist_idx') LIMIT 5;
46+
itemoffset | ctid | itemlen | keys
47+
------------+--------+---------+-----------------
48+
1 | (1,10) | 40 | (p)=((167,167))
49+
2 | (1,11) | 40 | (p)=((168,168))
50+
3 | (1,12) | 40 | (p)=((169,169))
51+
4 | (1,13) | 40 | (p)=((170,170))
52+
5 | (1,14) | 40 | (p)=((171,171))
53+
(5 rows)
54+
55+
SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0));
56+
itemoffset | ctid | itemlen | key_data
57+
------------+-----------+---------+------------------------------------------------------------------------------------
58+
1 | (1,65535) | 40 | \x00000100ffff28000000000000c064400000000000c06440000000000000f03f000000000000f03f
59+
2 | (2,65535) | 40 | \x00000200ffff28000000000000c074400000000000c074400000000000e064400000000000e06440
60+
3 | (3,65535) | 40 | \x00000300ffff28000000000000207f400000000000207f400000000000d074400000000000d07440
61+
4 | (4,65535) | 40 | \x00000400ffff28000000000000c084400000000000c084400000000000307f400000000000307f40
62+
5 | (5,65535) | 40 | \x00000500ffff28000000000000f089400000000000f089400000000000c884400000000000c88440
63+
6 | (6,65535) | 40 | \x00000600ffff28000000000000208f400000000000208f400000000000f889400000000000f88940
64+
7 | (7,65535) | 40 | \x00000700ffff28000000000000408f400000000000408f400000000000288f400000000000288f40
65+
(7 rows)
66+
67+
SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 1)) LIMIT 5;
68+
itemoffset | ctid | itemlen | key_data
69+
------------+-------+---------+------------------------------------------------------------------------------------
70+
1 | (0,1) | 40 | \x0000000001002800000000000000f03f000000000000f03f000000000000f03f000000000000f03f
71+
2 | (0,2) | 40 | \x00000000020028000000000000000040000000000000004000000000000000400000000000000040
72+
3 | (0,3) | 40 | \x00000000030028000000000000000840000000000000084000000000000008400000000000000840
73+
4 | (0,4) | 40 | \x00000000040028000000000000001040000000000000104000000000000010400000000000001040
74+
5 | (0,5) | 40 | \x00000000050028000000000000001440000000000000144000000000000014400000000000001440
75+
(5 rows)
76+
77+
SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 2)) LIMIT 5;
78+
itemoffset | ctid | itemlen | key_data
79+
------------+--------+---------+------------------------------------------------------------------------------------
80+
1 | (1,10) | 40 | \x000001000a0028000000000000e064400000000000e064400000000000e064400000000000e06440
81+
2 | (1,11) | 40 | \x000001000b0028000000000000006540000000000000654000000000000065400000000000006540
82+
3 | (1,12) | 40 | \x000001000c0028000000000000206540000000000020654000000000002065400000000000206540
83+
4 | (1,13) | 40 | \x000001000d0028000000000000406540000000000040654000000000004065400000000000406540
84+
5 | (1,14) | 40 | \x000001000e0028000000000000606540000000000060654000000000006065400000000000606540
85+
(5 rows)
86+
87+
DROP TABLE test_gist;

‎contrib/pageinspect/gistfuncs.c

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
/*
2+
* gistfuncs.c
3+
*Functions to investigate the content of GiST indexes
4+
*
5+
* Copyright (c) 2014-2020, PostgreSQL Global Development Group
6+
*
7+
* IDENTIFICATION
8+
*contrib/pageinspect/gistfuncs.c
9+
*/
10+
#include"postgres.h"
11+
12+
#include"access/gist.h"
13+
#include"access/gist_private.h"
14+
#include"access/htup.h"
15+
#include"access/relation.h"
16+
#include"catalog/namespace.h"
17+
#include"funcapi.h"
18+
#include"miscadmin.h"
19+
#include"pageinspect.h"
20+
#include"storage/itemptr.h"
21+
#include"utils/array.h"
22+
#include"utils/builtins.h"
23+
#include"utils/rel.h"
24+
#include"utils/pg_lsn.h"
25+
#include"utils/varlena.h"
26+
27+
PG_FUNCTION_INFO_V1(gist_page_opaque_info);
28+
PG_FUNCTION_INFO_V1(gist_page_items);
29+
PG_FUNCTION_INFO_V1(gist_page_items_bytea);
30+
31+
#defineItemPointerGetDatum(X) PointerGetDatum(X)
32+
33+
34+
Datum
35+
gist_page_opaque_info(PG_FUNCTION_ARGS)
36+
{
37+
bytea*raw_page=PG_GETARG_BYTEA_P(0);
38+
TupleDesctupdesc;
39+
Pagepage;
40+
GISTPageOpaqueopaq;
41+
HeapTupleresultTuple;
42+
Datumvalues[4];
43+
boolnulls[4];
44+
Datumflags[16];
45+
intnflags=0;
46+
uint16flagbits;
47+
48+
if (!superuser())
49+
ereport(ERROR,
50+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
51+
errmsg("must be superuser to use raw page functions")));
52+
53+
page=get_page_from_raw(raw_page);
54+
55+
opaq= (GISTPageOpaque)PageGetSpecialPointer(page);
56+
57+
/* Build a tuple descriptor for our result type */
58+
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
59+
elog(ERROR,"return type must be a row type");
60+
61+
/* Convert the flags bitmask to an array of human-readable names */
62+
flagbits=opaq->flags;
63+
if (flagbits&F_LEAF)
64+
flags[nflags++]=CStringGetTextDatum("leaf");
65+
if (flagbits&F_DELETED)
66+
flags[nflags++]=CStringGetTextDatum("deleted");
67+
if (flagbits&F_TUPLES_DELETED)
68+
flags[nflags++]=CStringGetTextDatum("tuples_deleted");
69+
if (flagbits&F_FOLLOW_RIGHT)
70+
flags[nflags++]=CStringGetTextDatum("follow_right");
71+
if (flagbits&F_HAS_GARBAGE)
72+
flags[nflags++]=CStringGetTextDatum("has_garbage");
73+
flagbits &= ~(F_LEAF |F_DELETED |F_TUPLES_DELETED |F_FOLLOW_RIGHT |F_HAS_GARBAGE);
74+
if (flagbits)
75+
{
76+
/* any flags we don't recognize are printed in hex */
77+
flags[nflags++]=DirectFunctionCall1(to_hex32,Int32GetDatum(flagbits));
78+
}
79+
80+
memset(nulls,0,sizeof(nulls));
81+
82+
values[0]=LSNGetDatum(PageGetLSN(page));
83+
values[1]=LSNGetDatum(GistPageGetNSN(page));
84+
values[2]=Int64GetDatum(opaq->rightlink);
85+
values[3]=PointerGetDatum(construct_array(flags,nflags,
86+
TEXTOID,
87+
-1, false,TYPALIGN_INT));
88+
89+
/* Build and return the result tuple. */
90+
resultTuple=heap_form_tuple(tupdesc,values,nulls);
91+
92+
returnHeapTupleGetDatum(resultTuple);
93+
}
94+
95+
typedefstructgist_page_items_state
96+
{
97+
Pagepage;
98+
TupleDesctupd;
99+
OffsetNumberoffset;
100+
Relationrel;
101+
}gist_page_items_state;
102+
103+
Datum
104+
gist_page_items_bytea(PG_FUNCTION_ARGS)
105+
{
106+
bytea*raw_page=PG_GETARG_BYTEA_P(0);
107+
FuncCallContext*fctx;
108+
gist_page_items_state*inter_call_data;
109+
110+
if (!superuser())
111+
ereport(ERROR,
112+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
113+
errmsg("must be superuser to use raw page functions")));
114+
115+
if (SRF_IS_FIRSTCALL())
116+
{
117+
TupleDesctupdesc;
118+
MemoryContextmctx;
119+
Pagepage;
120+
121+
fctx=SRF_FIRSTCALL_INIT();
122+
mctx=MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
123+
124+
page=get_page_from_raw(raw_page);
125+
126+
inter_call_data=palloc(sizeof(gist_page_items_state));
127+
128+
/* Build a tuple descriptor for our result type */
129+
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
130+
elog(ERROR,"return type must be a row type");
131+
132+
if (GistPageIsDeleted(page))
133+
elog(NOTICE,"page is deleted");
134+
135+
inter_call_data->page=page;
136+
inter_call_data->tupd=tupdesc;
137+
inter_call_data->offset=FirstOffsetNumber;
138+
139+
fctx->max_calls=PageGetMaxOffsetNumber(page);
140+
fctx->user_fctx=inter_call_data;
141+
142+
MemoryContextSwitchTo(mctx);
143+
}
144+
145+
fctx=SRF_PERCALL_SETUP();
146+
inter_call_data=fctx->user_fctx;
147+
148+
if (fctx->call_cntr<fctx->max_calls)
149+
{
150+
Pagepage=inter_call_data->page;
151+
OffsetNumberoffset=inter_call_data->offset;
152+
HeapTupleresultTuple;
153+
Datumresult;
154+
Datumvalues[4];
155+
boolnulls[4];
156+
ItemIdid;
157+
IndexTupleitup;
158+
bytea*tuple_bytea;
159+
inttuple_len;
160+
161+
id=PageGetItemId(page,offset);
162+
163+
if (!ItemIdIsValid(id))
164+
elog(ERROR,"invalid ItemId");
165+
166+
itup= (IndexTuple)PageGetItem(page,id);
167+
tuple_len=IndexTupleSize(itup);
168+
169+
memset(nulls,0,sizeof(nulls));
170+
171+
values[0]=DatumGetInt16(offset);
172+
values[1]=ItemPointerGetDatum(&itup->t_tid);
173+
values[2]=Int32GetDatum((int)IndexTupleSize(itup));
174+
175+
tuple_bytea= (bytea*)palloc(tuple_len+VARHDRSZ);
176+
SET_VARSIZE(tuple_bytea,tuple_len+VARHDRSZ);
177+
memcpy(VARDATA(tuple_bytea),itup,tuple_len);
178+
values[3]=PointerGetDatum(tuple_bytea);
179+
180+
/* Build and return the result tuple. */
181+
resultTuple=heap_form_tuple(inter_call_data->tupd,values,nulls);
182+
result=HeapTupleGetDatum(resultTuple);
183+
184+
inter_call_data->offset++;
185+
SRF_RETURN_NEXT(fctx,result);
186+
}
187+
188+
SRF_RETURN_DONE(fctx);
189+
}
190+
191+
Datum
192+
gist_page_items(PG_FUNCTION_ARGS)
193+
{
194+
bytea*raw_page=PG_GETARG_BYTEA_P(0);
195+
OidindexRelid=PG_GETARG_OID(1);
196+
FuncCallContext*fctx;
197+
gist_page_items_state*inter_call_data;
198+
199+
if (!superuser())
200+
ereport(ERROR,
201+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
202+
errmsg("must be superuser to use raw page functions")));
203+
204+
if (SRF_IS_FIRSTCALL())
205+
{
206+
RelationindexRel;
207+
TupleDesctupdesc;
208+
MemoryContextmctx;
209+
Pagepage;
210+
211+
fctx=SRF_FIRSTCALL_INIT();
212+
mctx=MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
213+
214+
page=get_page_from_raw(raw_page);
215+
216+
inter_call_data=palloc(sizeof(gist_page_items_state));
217+
218+
/* Open the relation */
219+
indexRel=index_open(indexRelid,AccessShareLock);
220+
221+
/* Build a tuple descriptor for our result type */
222+
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
223+
elog(ERROR,"return type must be a row type");
224+
225+
if (GistPageIsDeleted(page))
226+
elog(NOTICE,"page is deleted");
227+
228+
inter_call_data->page=page;
229+
inter_call_data->tupd=tupdesc;
230+
inter_call_data->offset=FirstOffsetNumber;
231+
inter_call_data->rel=indexRel;
232+
233+
fctx->max_calls=PageGetMaxOffsetNumber(page);
234+
fctx->user_fctx=inter_call_data;
235+
236+
MemoryContextSwitchTo(mctx);
237+
}
238+
239+
fctx=SRF_PERCALL_SETUP();
240+
inter_call_data=fctx->user_fctx;
241+
242+
if (fctx->call_cntr<fctx->max_calls)
243+
{
244+
Pagepage=inter_call_data->page;
245+
OffsetNumberoffset=inter_call_data->offset;
246+
HeapTupleresultTuple;
247+
Datumresult;
248+
Datumvalues[4];
249+
boolnulls[4];
250+
ItemIdid;
251+
IndexTupleitup;
252+
Datumitup_values[INDEX_MAX_KEYS];
253+
boolitup_isnull[INDEX_MAX_KEYS];
254+
char*key_desc;
255+
256+
id=PageGetItemId(page,offset);
257+
258+
if (!ItemIdIsValid(id))
259+
elog(ERROR,"invalid ItemId");
260+
261+
itup= (IndexTuple)PageGetItem(page,id);
262+
263+
index_deform_tuple(itup,RelationGetDescr(inter_call_data->rel),
264+
itup_values,itup_isnull);
265+
266+
key_desc=BuildIndexValueDescription(inter_call_data->rel,itup_values,
267+
itup_isnull);
268+
269+
memset(nulls,0,sizeof(nulls));
270+
271+
values[0]=DatumGetInt16(offset);
272+
values[1]=ItemPointerGetDatum(&itup->t_tid);
273+
values[2]=Int32GetDatum((int)IndexTupleSize(itup));
274+
values[3]=CStringGetTextDatum(key_desc);
275+
276+
/* Build and return the result tuple. */
277+
resultTuple=heap_form_tuple(inter_call_data->tupd,values,nulls);
278+
result=HeapTupleGetDatum(resultTuple);
279+
280+
inter_call_data->offset++;
281+
SRF_RETURN_NEXT(fctx,result);
282+
}
283+
284+
relation_close(inter_call_data->rel,AccessShareLock);
285+
286+
SRF_RETURN_DONE(fctx);
287+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp