3 #include "access/genam.h"
4 #include "access/gist.h"
5 #include "access/gist_private.h"
6 #include "access/gistscan.h"
7 #include "access/heapam.h"
8 #include "catalog/index.h"
10 #include "storage/lmgr.h"
11 #include "catalog/namespace.h"
12 #include "utils/builtins.h"
15 #include <access/heapam.h>
16 #include <catalog/pg_type.h>
18 #define PAGESIZE (BLCKSZ - MAXALIGN(sizeof(PageHeaderData) + sizeof(ItemIdData)))
21 #define PG_NARGS() (fcinfo->nargs)
26 char *out=palloc( VARSIZE(in) );
27 memcpy(out, VARDATA(in), VARSIZE(in)-VARHDRSZ);
28 out[ VARSIZE(in)-VARHDRSZ ] ='\0';
40 #ifdef PG_MODULE_MAGIC
46 gist_index_open(RangeVar *relvar) {
47 Oid relOid = RangeVarGetRelid(relvar, false);
48 return index_open(relOid, AccessExclusiveLock);
51 #define gist_index_close(r) index_close((r), AccessExclusiveLock)
56 gist_index_open(RangeVar *relvar) {
57 Relation rel = index_openrv(relvar);
59 LockRelation(rel, AccessExclusiveLock);
64 gist_index_close(Relation rel) {
65 UnlockRelation(rel, AccessExclusiveLock);
71 #if PG_VERSION_NUM >= 80300
72 #define stringToQualifiedNameList(x,y) stringToQualifiedNameList(x)
75 #if PG_VERSION_NUM < 80300
76 #define SET_VARSIZE(p,l) VARATT_SIZEP(p)=(l)
80 gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff, IdxInfo *info) {
90 pred = (char *) palloc(sizeof(char) * level * 4 + 1);
91 MemSet(pred, ' ', level*4);
94 buffer = ReadBuffer(r, blk);
95 page = (Page) BufferGetPage(buffer);
97 maxoff = PageGetMaxOffsetNumber(page);
100 while ( (info->ptr-((char*)info->txt)) + level*4 + 128 >= info->len ) {
101 int dist=info->ptr-((char*)info->txt);
103 info->txt=(text*)repalloc(info->txt, info->len);
104 info->ptr = ((char*)info->txt)+dist;
107 sprintf(info->ptr, "%s%d(l:%d) blk: %d numTuple: %d free: %db(%.2f%%) rightlink:%u (%s)\n",
113 PageGetFreeSpace(page),
114 100.0*(((float)PAGESIZE)-(float)PageGetFreeSpace(page))/((float)PAGESIZE),
115 GistPageGetOpaque(page)->rightlink,
116 ( GistPageGetOpaque(page)->rightlink == InvalidBlockNumber ) ? "InvalidBlockNumber" : "OK" );
117 info->ptr=strchr(info->ptr,'\0');
119 if (!GistPageIsLeaf(page) && ( info->maxlevel<0 || level<info->maxlevel ) )
120 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
121 iid = PageGetItemId(page, i);
122 which = (IndexTuple) PageGetItem(page, iid);
123 cblk = ItemPointerGetBlockNumber(&(which->t_tid));
124 gist_dumptree(r, level + 1, cblk, i, info);
126 ReleaseBuffer(buffer);
130 PG_FUNCTION_INFO_V1(gist_tree);
131 Datum gist_tree(PG_FUNCTION_ARGS);
133 gist_tree(PG_FUNCTION_ARGS) {
134 text *name=PG_GETARG_TEXT_P(0);
135 char *relname=t2c(name);
141 relname_list = stringToQualifiedNameList(relname, "gist_tree");
142 relvar = makeRangeVarFromNameList(relname_list);
143 index = gist_index_open(relvar);
144 PG_FREE_IF_COPY(name,0);
146 info.maxlevel = ( PG_NARGS() > 1 ) ? PG_GETARG_INT32(1) : -1;
148 info.txt=(text*)palloc( info.len );
149 info.ptr=((char*)info.txt)+VARHDRSZ;
151 gist_dumptree(index, 0, GIST_ROOT_BLKNO, 0, &info);
153 gist_index_close(index);
156 SET_VARSIZE(info.txt, info.ptr-((char*)info.txt));
157 PG_RETURN_POINTER(info.txt);
168 uint64 leaftuplesize;
173 gist_stattree(Relation r, int level, BlockNumber blk, OffsetNumber coff, IdxStat *info) {
183 pred = (char *) palloc(sizeof(char) * level * 4 + 1);
184 MemSet(pred, ' ', level*4);
185 pred[level*4] = '\0';
187 buffer = ReadBuffer(r, blk);
188 page = (Page) BufferGetPage(buffer);
190 maxoff = PageGetMaxOffsetNumber(page);
193 info->tuplesize+=PAGESIZE-PageGetFreeSpace(page);
194 info->totalsize+=BLCKSZ;
195 info->numtuple+=maxoff;
196 if ( info->level < level )
199 if (GistPageIsLeaf(page)) {
200 info->numleafpages++;
201 info->leaftuplesize+=PAGESIZE-PageGetFreeSpace(page);
202 info->numleaftuple+=maxoff;
204 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
205 iid = PageGetItemId(page, i);
206 which = (IndexTuple) PageGetItem(page, iid);
207 if ( GistTupleIsInvalid(which) )
208 info->numinvalidtuple++;
209 cblk = ItemPointerGetBlockNumber(&(which->t_tid));
210 gist_stattree(r, level + 1, cblk, i, info);
214 ReleaseBuffer(buffer);
218 PG_FUNCTION_INFO_V1(gist_stat);
219 Datum gist_stat(PG_FUNCTION_ARGS);
221 gist_stat(PG_FUNCTION_ARGS) {
222 text *name=PG_GETARG_TEXT_P(0);
223 char *relname=t2c(name);
228 text *out=(text*)palloc(1024);
229 char *ptr=((char*)out)+VARHDRSZ;
232 relname_list = stringToQualifiedNameList(relname, "gist_tree");
233 relvar = makeRangeVarFromNameList(relname_list);
234 index = gist_index_open(relvar);
235 PG_FREE_IF_COPY(name,0);
237 memset(&info, 0, sizeof(IdxStat));
239 gist_stattree(index, 0, GIST_ROOT_BLKNO, 0, &info);
241 gist_index_close(index);
245 "Number of levels: %d\n"
246 "Number of pages: %d\n"
247 "Number of leaf pages: %d\n"
248 "Number of tuples: %d\n"
249 "Number of invalid tuples: %d\n"
250 "Number of leaf tuples: %d\n"
251 "Total size of tuples: "INT64_FORMAT" bytes\n"
252 "Total size of leaf tuples: "INT64_FORMAT" bytes\n"
253 "Total size of index: "INT64_FORMAT" bytes\n",
258 info.numinvalidtuple,
264 ptr=strchr(ptr,'\0');
266 SET_VARSIZE(out, ptr-((char*)out));
267 PG_RETURN_POINTER(out);
270 typedef struct GPItem {
288 openGPPage( FuncCallContext *funcctx, BlockNumber blk ) {
290 MemoryContext oldcontext;
291 Relation index = ( (TypeStorage*)(funcctx->user_fctx) )->index;
293 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
294 nitem = (GPItem*)palloc( sizeof(GPItem) );
295 memset(nitem,0,sizeof(GPItem));
297 nitem->buffer = ReadBuffer(index, blk);
298 nitem->page = (Page) BufferGetPage(nitem->buffer);
299 nitem->offset=FirstOffsetNumber;
300 nitem->next = ( (TypeStorage*)(funcctx->user_fctx) )->item;
301 nitem->level = ( nitem->next ) ? nitem->next->level+1 : 1;
302 ( (TypeStorage*)(funcctx->user_fctx) )->item = nitem;
304 MemoryContextSwitchTo(oldcontext);
309 closeGPPage( FuncCallContext *funcctx ) {
310 GPItem *oitem = ( (TypeStorage*)(funcctx->user_fctx) )->item;
312 ( (TypeStorage*)(funcctx->user_fctx) )->item = oitem->next;
314 ReleaseBuffer(oitem->buffer);
316 return ( (TypeStorage*)(funcctx->user_fctx) )->item;
320 setup_firstcall(FuncCallContext *funcctx, text *name) {
321 MemoryContext oldcontext;
323 char *relname=t2c(name);
325 char attname[NAMEDATALEN];
328 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
330 st=(TypeStorage*)palloc( sizeof(TypeStorage) );
331 memset(st,0,sizeof(TypeStorage));
332 st->relname_list = stringToQualifiedNameList(relname, "gist_tree");
333 st->relvar = makeRangeVarFromNameList(st->relname_list);
334 st->index = gist_index_open(st->relvar);
335 funcctx->user_fctx = (void*)st;
337 tupdesc = CreateTemplateTupleDesc(st->index->rd_att->natts+2, false);
338 TupleDescInitEntry(tupdesc, 1, "level", INT4OID, -1, 0);
339 TupleDescInitEntry(tupdesc, 2, "valid", BOOLOID, -1, 0);
340 for (i = 0; i < st->index->rd_att->natts; i++) {
341 sprintf(attname, "z%d", i+2);
346 st->index->rd_att->attrs[i]->atttypid,
347 st->index->rd_att->attrs[i]->atttypmod,
348 st->index->rd_att->attrs[i]->attndims
352 st->dvalues = (Datum *) palloc((tupdesc->natts+2) * sizeof(Datum));
353 st->nulls = (char *) palloc((tupdesc->natts+2) * sizeof(char));
355 funcctx->slot = TupleDescGetSlot(tupdesc);
356 funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
358 MemoryContextSwitchTo(oldcontext);
361 st->item=openGPPage(funcctx, GIST_ROOT_BLKNO);
365 close_call( FuncCallContext *funcctx ) {
366 TypeStorage *st = (TypeStorage*)(funcctx->user_fctx);
368 while( st->item && closeGPPage(funcctx) );
370 pfree( st->dvalues );
373 gist_index_close(st->index);
376 PG_FUNCTION_INFO_V1(gist_print);
377 Datum gist_print(PG_FUNCTION_ARGS);
379 gist_print(PG_FUNCTION_ARGS) {
380 FuncCallContext *funcctx;
382 Datum result=(Datum)0;
389 if (SRF_IS_FIRSTCALL()) {
390 text *name=PG_GETARG_TEXT_P(0);
391 funcctx = SRF_FIRSTCALL_INIT();
392 setup_firstcall(funcctx, name);
393 PG_FREE_IF_COPY(name,0);
396 funcctx = SRF_PERCALL_SETUP();
397 st = (TypeStorage*)(funcctx->user_fctx);
401 SRF_RETURN_DONE(funcctx);
404 while( st->item->offset > PageGetMaxOffsetNumber( st->item->page ) ) {
405 if ( ! closeGPPage(funcctx) ) {
407 SRF_RETURN_DONE(funcctx);
411 iid = PageGetItemId( st->item->page, st->item->offset );
412 ituple = (IndexTuple) PageGetItem(st->item->page, iid);
414 st->dvalues[0] = Int32GetDatum( st->item->level );
416 st->dvalues[1] = BoolGetDatum( (!GistPageIsLeaf(st->item->page) && GistTupleIsInvalid(ituple)) ? false : true );
418 for(i=2; i<funcctx->attinmeta->tupdesc->natts; i++) {
419 if ( !GistPageIsLeaf(st->item->page) && GistTupleIsInvalid(ituple) ) {
420 st->dvalues[i] = (Datum)0;
423 st->dvalues[i] = index_getattr(ituple, i-1, st->index->rd_att, &isnull);
424 st->nulls[i] = ( isnull ) ? 'n' : ' ';
428 htuple = heap_formtuple(funcctx->attinmeta->tupdesc, st->dvalues, st->nulls);
429 result = TupleGetDatum(funcctx->slot, htuple);
430 st->item->offset = OffsetNumberNext(st->item->offset);
431 if ( !GistPageIsLeaf(st->item->page) )
432 openGPPage(funcctx, ItemPointerGetBlockNumber(&(ituple->t_tid)) );
434 SRF_RETURN_NEXT(funcctx, result);