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);
72 gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff, IdxInfo *info) {
82 pred = (char *) palloc(sizeof(char) * level * 4 + 1);
83 MemSet(pred, ' ', level*4);
86 buffer = ReadBuffer(r, blk);
87 page = (Page) BufferGetPage(buffer);
89 maxoff = PageGetMaxOffsetNumber(page);
92 while ( (info->ptr-((char*)info->txt)) + level*4 + 128 >= info->len ) {
93 int dist=info->ptr-((char*)info->txt);
95 info->txt=(text*)repalloc(info->txt, info->len);
96 info->ptr = ((char*)info->txt)+dist;
99 sprintf(info->ptr, "%s%d(l:%d) blk: %d numTuple: %d free: %db(%.2f%%) rightlink:%u (%s)\n",
105 PageGetFreeSpace(page),
106 100.0*(((float)PAGESIZE)-(float)PageGetFreeSpace(page))/((float)PAGESIZE),
107 GistPageGetOpaque(page)->rightlink,
108 ( GistPageGetOpaque(page)->rightlink == InvalidBlockNumber ) ? "InvalidBlockNumber" : "OK" );
109 info->ptr=strchr(info->ptr,'\0');
111 if (!GistPageIsLeaf(page) && ( info->maxlevel<0 || level<info->maxlevel ) )
112 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
113 iid = PageGetItemId(page, i);
114 which = (IndexTuple) PageGetItem(page, iid);
115 cblk = ItemPointerGetBlockNumber(&(which->t_tid));
116 gist_dumptree(r, level + 1, cblk, i, info);
118 ReleaseBuffer(buffer);
122 PG_FUNCTION_INFO_V1(gist_tree);
123 Datum gist_tree(PG_FUNCTION_ARGS);
125 gist_tree(PG_FUNCTION_ARGS) {
126 text *name=PG_GETARG_TEXT_P(0);
127 char *relname=t2c(name);
134 relname_list = stringToQualifiedNameList(relname, "gist_tree");
135 relvar = makeRangeVarFromNameList(relname_list);
136 index = gist_index_open(relvar);
137 PG_FREE_IF_COPY(name,0);
139 info.maxlevel = ( PG_NARGS() > 1 ) ? PG_GETARG_INT32(1) : -1;
141 info.txt=(text*)palloc( info.len );
142 info.ptr=((char*)info.txt)+VARHDRSZ;
144 gist_dumptree(index, 0, GIST_ROOT_BLKNO, 0, &info);
146 gist_index_close(index);
149 VARATT_SIZEP(info.txt)=info.ptr-((char*)info.txt);
150 PG_RETURN_POINTER(info.txt);
161 uint64 leaftuplesize;
166 gist_stattree(Relation r, int level, BlockNumber blk, OffsetNumber coff, IdxStat *info) {
176 pred = (char *) palloc(sizeof(char) * level * 4 + 1);
177 MemSet(pred, ' ', level*4);
178 pred[level*4] = '\0';
180 buffer = ReadBuffer(r, blk);
181 page = (Page) BufferGetPage(buffer);
183 maxoff = PageGetMaxOffsetNumber(page);
186 info->tuplesize+=PAGESIZE-PageGetFreeSpace(page);
187 info->totalsize+=BLCKSZ;
188 info->numtuple+=maxoff;
189 if ( info->level < level )
192 if (GistPageIsLeaf(page)) {
193 info->numleafpages++;
194 info->leaftuplesize+=PAGESIZE-PageGetFreeSpace(page);
195 info->numleaftuple+=maxoff;
197 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
198 iid = PageGetItemId(page, i);
199 which = (IndexTuple) PageGetItem(page, iid);
200 if ( GistTupleIsInvalid(which) )
201 info->numinvalidtuple++;
202 cblk = ItemPointerGetBlockNumber(&(which->t_tid));
203 gist_stattree(r, level + 1, cblk, i, info);
207 ReleaseBuffer(buffer);
211 PG_FUNCTION_INFO_V1(gist_stat);
212 Datum gist_stat(PG_FUNCTION_ARGS);
214 gist_stat(PG_FUNCTION_ARGS) {
215 text *name=PG_GETARG_TEXT_P(0);
216 char *relname=t2c(name);
221 text *out=(text*)palloc(1024);
222 char *ptr=((char*)out)+VARHDRSZ;
225 relname_list = stringToQualifiedNameList(relname, "gist_tree");
226 relvar = makeRangeVarFromNameList(relname_list);
227 index = gist_index_open(relvar);
228 PG_FREE_IF_COPY(name,0);
230 memset(&info, 0, sizeof(IdxStat));
232 gist_stattree(index, 0, GIST_ROOT_BLKNO, 0, &info);
234 gist_index_close(index);
238 "Number of levels: %d\n"
239 "Number of pages: %d\n"
240 "Number of leaf pages: %d\n"
241 "Number of tuples: %d\n"
242 "Number of invalid tuples: %d\n"
243 "Number of leaf tuples: %d\n"
244 "Total size of tuples: "INT64_FORMAT" bytes\n"
245 "Total size of leaf tuples: "INT64_FORMAT" bytes\n"
246 "Total size of index: "INT64_FORMAT" bytes\n",
251 info.numinvalidtuple,
257 ptr=strchr(ptr,'\0');
259 VARATT_SIZEP(out)=ptr-((char*)out);
260 PG_RETURN_POINTER(out);
263 typedef struct GPItem {
281 openGPPage( FuncCallContext *funcctx, BlockNumber blk ) {
283 MemoryContext oldcontext;
284 Relation index = ( (TypeStorage*)(funcctx->user_fctx) )->index;
286 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
287 nitem = (GPItem*)palloc( sizeof(GPItem) );
288 memset(nitem,0,sizeof(GPItem));
290 nitem->buffer = ReadBuffer(index, blk);
291 nitem->page = (Page) BufferGetPage(nitem->buffer);
292 nitem->offset=FirstOffsetNumber;
293 nitem->next = ( (TypeStorage*)(funcctx->user_fctx) )->item;
294 nitem->level = ( nitem->next ) ? nitem->next->level+1 : 1;
295 ( (TypeStorage*)(funcctx->user_fctx) )->item = nitem;
297 MemoryContextSwitchTo(oldcontext);
302 closeGPPage( FuncCallContext *funcctx ) {
303 GPItem *oitem = ( (TypeStorage*)(funcctx->user_fctx) )->item;
305 ( (TypeStorage*)(funcctx->user_fctx) )->item = oitem->next;
307 ReleaseBuffer(oitem->buffer);
309 return ( (TypeStorage*)(funcctx->user_fctx) )->item;
313 setup_firstcall(FuncCallContext *funcctx, text *name) {
314 MemoryContext oldcontext;
316 char *relname=t2c(name);
318 char attname[NAMEDATALEN];
321 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
323 st=(TypeStorage*)palloc( sizeof(TypeStorage) );
324 memset(st,0,sizeof(TypeStorage));
325 st->relname_list = stringToQualifiedNameList(relname, "gist_tree");
326 st->relvar = makeRangeVarFromNameList(st->relname_list);
327 st->index = gist_index_open(st->relvar);
328 funcctx->user_fctx = (void*)st;
330 tupdesc = CreateTemplateTupleDesc(st->index->rd_att->natts+2, false);
331 TupleDescInitEntry(tupdesc, 1, "level", INT4OID, -1, 0);
332 TupleDescInitEntry(tupdesc, 2, "valid", BOOLOID, -1, 0);
333 for (i = 0; i < st->index->rd_att->natts; i++) {
334 sprintf(attname, "z%d", i+2);
339 st->index->rd_att->attrs[i]->atttypid,
340 st->index->rd_att->attrs[i]->atttypmod,
341 st->index->rd_att->attrs[i]->attndims
345 st->dvalues = (Datum *) palloc((tupdesc->natts+2) * sizeof(Datum));
346 st->nulls = (char *) palloc((tupdesc->natts+2) * sizeof(char));
348 funcctx->slot = TupleDescGetSlot(tupdesc);
349 funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
351 MemoryContextSwitchTo(oldcontext);
354 st->item=openGPPage(funcctx, GIST_ROOT_BLKNO);
358 close_call( FuncCallContext *funcctx ) {
359 TypeStorage *st = (TypeStorage*)(funcctx->user_fctx);
361 while( st->item && closeGPPage(funcctx) );
363 pfree( st->dvalues );
366 gist_index_close(st->index);
369 PG_FUNCTION_INFO_V1(gist_print);
370 Datum gist_print(PG_FUNCTION_ARGS);
372 gist_print(PG_FUNCTION_ARGS) {
373 FuncCallContext *funcctx;
375 Datum result=(Datum)0;
382 if (SRF_IS_FIRSTCALL()) {
383 text *name=PG_GETARG_TEXT_P(0);
384 funcctx = SRF_FIRSTCALL_INIT();
385 setup_firstcall(funcctx, name);
386 PG_FREE_IF_COPY(name,0);
389 funcctx = SRF_PERCALL_SETUP();
390 st = (TypeStorage*)(funcctx->user_fctx);
394 SRF_RETURN_DONE(funcctx);
397 while( st->item->offset > PageGetMaxOffsetNumber( st->item->page ) ) {
398 if ( ! closeGPPage(funcctx) ) {
400 SRF_RETURN_DONE(funcctx);
404 iid = PageGetItemId( st->item->page, st->item->offset );
405 ituple = (IndexTuple) PageGetItem(st->item->page, iid);
407 st->dvalues[0] = Int32GetDatum( st->item->level );
409 st->dvalues[1] = BoolGetDatum( (!GistPageIsLeaf(st->item->page) && GistTupleIsInvalid(ituple)) ? false : true );
411 for(i=2; i<funcctx->attinmeta->tupdesc->natts; i++) {
412 if ( !GistPageIsLeaf(st->item->page) && GistTupleIsInvalid(ituple) ) {
413 st->dvalues[i] = (Datum)0;
416 st->dvalues[i] = index_getattr(ituple, i-1, st->index->rd_att, &isnull);
417 st->nulls[i] = ( isnull ) ? 'n' : ' ';
421 htuple = heap_formtuple(funcctx->attinmeta->tupdesc, st->dvalues, st->nulls);
422 result = TupleGetDatum(funcctx->slot, htuple);
423 st->item->offset = OffsetNumberNext(st->item->offset);
424 if ( !GistPageIsLeaf(st->item->page) )
425 openGPPage(funcctx, ItemPointerGetBlockNumber(&(ituple->t_tid)) );
427 SRF_RETURN_NEXT(funcctx, result);