spgist_stat
[gevel.git] / gevel.c
diff --git a/gevel.c b/gevel.c
index 16e18d3..ef8f3d9 100644 (file)
--- a/gevel.c
+++ b/gevel.c
@@ -2,9 +2,16 @@
 
 #include "access/genam.h"
 #include "access/gin.h"
+#if PG_VERSION_NUM >= 90100
+#include "access/gin_private.h"
+#endif
 #include "access/gist.h"
 #include "access/gist_private.h"
 #include "access/gistscan.h"
+#if PG_VERSION_NUM >= 90200
+#include "access/spgist_private.h"
+#include "access/spgist.h"
+#endif
 #include "access/heapam.h"
 #include "catalog/index.h"
 #include "miscadmin.h"
@@ -55,7 +62,11 @@ PG_MODULE_MAGIC;
 
 static Relation
 gist_index_open(RangeVar *relvar) {
+#if PG_VERSION_NUM <= 90100 
        Oid relOid = RangeVarGetRelid(relvar, false);
+#else
+       Oid relOid = RangeVarGetRelid(relvar, NoLock, false);
+#endif
        return checkOpenedRelation(
                                index_open(relOid, AccessExclusiveLock), GIST_AM_OID);
 }
@@ -64,7 +75,11 @@ gist_index_open(RangeVar *relvar) {
 
 static Relation
 gin_index_open(RangeVar *relvar) {
+#if PG_VERSION_NUM <= 90100 
        Oid relOid = RangeVarGetRelid(relvar, false);
+#else
+       Oid relOid = RangeVarGetRelid(relvar, NoLock, false);
+#endif
        return checkOpenedRelation(
                                index_open(relOid, AccessShareLock), GIN_AM_OID);
 }
@@ -156,13 +171,13 @@ gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff, IdxInfo
                info->ptr = ((char*)info->txt)+dist;
        }
 
-       sprintf(info->ptr, "%s%d(l:%d) blk: %d numTuple: %d free: %db(%.2f%%) rightlink:%u (%s)\n", 
+       sprintf(info->ptr, "%s%d(l:%d) blk: %u numTuple: %d free: %db(%.2f%%) rightlink:%u (%s)\n", 
                pred,
                coff, 
                level, 
-               (int) blk,
+               blk,
                (int) maxoff, 
-               PageGetFreeSpace(page),  
+               (int) PageGetFreeSpace(page),  
                100.0*(((float)PAGESIZE)-(float)PageGetFreeSpace(page))/((float)PAGESIZE),
                GistPageGetOpaque(page)->rightlink,
                ( GistPageGetOpaque(page)->rightlink == InvalidBlockNumber ) ? "InvalidBlockNumber" : "OK" );
@@ -494,6 +509,9 @@ typedef struct GinStatState {
        Buffer                  buffer;
        OffsetNumber    offset;
        Datum                   curval;
+#if PG_VERSION_NUM >= 90100
+       GinNullCategory category;
+#endif
        Datum                   dvalues[2];
        char                    nulls[2];
 } GinStatState;
@@ -553,18 +571,25 @@ refindPosition(GinStatState *st)
        }
 
        for(;;) {
-               int     cmp;
-#if PG_VERSION_NUM < 80400
-               bool    isnull;
+               int                     cmp;
+#if PG_VERSION_NUM >= 90100
+               GinNullCategory category;
+#elif PG_VERSION_NUM < 80400
+               bool                    isnull = false;
 #endif
-               Datum   datum;
-               IndexTuple itup;
+               Datum                   datum;
+               IndexTuple              itup;
 
                if (moveRightIfItNeeded(st)==false)
                        return false;
 
                itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, st->offset));
-#if PG_VERSION_NUM >= 80400
+#if PG_VERSION_NUM >= 90100
+               datum = gintuple_get_key(&st->ginstate, itup, &category); 
+               cmp = ginCompareAttEntries(&st->ginstate,
+                                                                       st->attnum + 1, st->curval, st->category,
+                                                                       gintuple_get_attrnum(&st->ginstate, itup), datum, category);
+#elif PG_VERSION_NUM >= 80400
                datum = gin_index_getattr(&st->ginstate, itup);
 
                cmp = compareAttEntries(&st->ginstate,
@@ -646,7 +671,9 @@ processTuple( FuncCallContext  *funcctx,  GinStatState *st, IndexTuple itup ) {
 
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
        st->curval = datumCopy(
-#if PG_VERSION_NUM >= 80400
+#if PG_VERSION_NUM >= 90100
+                                       gintuple_get_key(&st->ginstate, itup, &st->category),
+#elif PG_VERSION_NUM >= 80400
                                        gin_index_getattr(&st->ginstate, itup),
 #else
                                        index_getattr(itup, FirstOffsetNumber, st->ginstate.tupdesc, &isnull),
@@ -656,7 +683,11 @@ processTuple( FuncCallContext  *funcctx,  GinStatState *st, IndexTuple itup ) {
        MemoryContextSwitchTo(oldcontext);
 
        st->dvalues[0] = st->curval;
-
+#if PG_VERSION_NUM >= 90100
+       /* do no distiguish various null category */
+       st->nulls[0] = (st->category == GIN_CAT_NORM_KEY) ? ' ' : 'n';
+#endif
+               
        if ( GinIsPostingTree(itup) ) {
                BlockNumber     rootblkno = GinGetPostingTree(itup);
                GinPostingTreeScan *gdi;
@@ -664,8 +695,13 @@ processTuple( FuncCallContext  *funcctx,  GinStatState *st, IndexTuple itup ) {
                Page        page;
 
                LockBuffer(st->buffer, GIN_UNLOCK);
+#if PG_VERSION_NUM >= 90100
+               gdi = ginPrepareScanPostingTree(st->index, rootblkno, TRUE);
+               entrybuffer = ginScanBeginPostingTree(gdi);
+#else
                gdi = prepareScanPostingTree(st->index, rootblkno, TRUE);
                entrybuffer = scanBeginPostingTree(gdi);
+#endif
 
                page = BufferGetPage(entrybuffer);
                st->dvalues[1] = Int32GetDatum( gdi->stack->predictNumber * GinPageGetOpaque(page)->maxoff );
@@ -770,7 +806,13 @@ gin_count_estimate(PG_FUNCTION_ARGS) {
 
        fmgr_info( F_TS_MATCH_VQ , &key.sk_func );
 
-#if PG_VERSION_NUM >= 80400
+#if PG_VERSION_NUM >= 90100
+       scan = index_beginscan_bitmap(index, SnapshotNow, 1);
+       index_rescan(scan, &key, 1, NULL, 0);
+
+       count = index_getbitmap(scan, bitmap);
+       tbm_free(bitmap);
+#elif PG_VERSION_NUM >= 80400
        scan = index_beginscan_bitmap(index, SnapshotNow, 1, &key);
 
        count = index_getbitmap(scan, bitmap);
@@ -797,3 +839,139 @@ gin_count_estimate(PG_FUNCTION_ARGS) {
        PG_RETURN_INT64(0);
 }
 #endif
+
+PG_FUNCTION_INFO_V1(spgist_stat);
+Datum spgist_stat(PG_FUNCTION_ARGS);
+Datum
+spgist_stat(PG_FUNCTION_ARGS)
+{
+#if PG_VERSION_NUM < 90200
+       elog(NOTICE, "Function is not working under PgSQL < 9.2");
+
+       PG_RETURN_TEXT_P(CStringGetTextDatum("???"));
+#else
+       text       *name = PG_GETARG_TEXT_P(0);
+       RangeVar   *relvar;
+       Relation        index;
+       BlockNumber blkno;
+       BlockNumber totalPages = 0,
+                               innerPages = 0,
+                               leafPages = 0,
+                               emptyPages = 0,
+                               deletedPages = 0;
+       double    usedSpace = 0.0;
+       char            res[1024];
+       int              bufferSize = -1;
+       int64      innerTuples = 0,
+                               leafTuples = 0,
+                               nAllTheSame = 0,
+                               nLeafPlaceholder = 0,
+                               nInnerPlaceholder = 0,
+                               nLeafRedirect = 0,
+                               nInnerRedirect = 0;
+
+#define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
+#define IS_SPGIST(r) ((r)->rd_rel->relam == SPGIST_AM_OID)
+
+       relvar = makeRangeVarFromNameList(textToQualifiedNameList(name));
+       index = relation_openrv(relvar, AccessExclusiveLock);
+
+       if (!IS_INDEX(index) || !IS_SPGIST(index))
+               elog(ERROR, "relation \"%s\" is not an SPGiST index",
+                        RelationGetRelationName(index));
+
+       totalPages = RelationGetNumberOfBlocks(index);
+
+       for (blkno = SPGIST_HEAD_BLKNO; blkno < totalPages; blkno++)
+       {
+               Buffer    buffer;
+               Page            page;
+               int              pageFree;
+
+               buffer = ReadBuffer(index, blkno);
+               LockBuffer(buffer, BUFFER_LOCK_SHARE);
+
+               page = BufferGetPage(buffer);
+
+               if (PageIsNew(page) || SpGistPageIsDeleted(page))
+               {
+                       deletedPages++;
+                       UnlockReleaseBuffer(buffer);
+                       continue;
+               }
+
+               if (SpGistPageIsLeaf(page))
+               {
+                       leafPages++;
+                       leafTuples += PageGetMaxOffsetNumber(page);
+                       nLeafPlaceholder += SpGistPageGetOpaque(page)->nPlaceholder;
+                       nLeafRedirect += SpGistPageGetOpaque(page)->nRedirection;
+               }
+               else
+               {
+                       int      i,
+                                       max;
+
+                       innerPages++;
+                       max = PageGetMaxOffsetNumber(page);
+                       innerTuples += max;
+                       nInnerPlaceholder += SpGistPageGetOpaque(page)->nPlaceholder;
+                       nInnerRedirect += SpGistPageGetOpaque(page)->nRedirection;
+                       for (i = FirstOffsetNumber; i <= max; i++)
+                       {
+                               SpGistInnerTuple it;
+
+                               it = (SpGistInnerTuple) PageGetItem(page,
+                                                                                                       PageGetItemId(page, i));
+                               if (it->allTheSame)
+                                       nAllTheSame++;
+                       }
+               }
+
+               if (bufferSize < 0)
+                       bufferSize = BufferGetPageSize(buffer)
+                               - MAXALIGN(sizeof(SpGistPageOpaqueData))
+                               - SizeOfPageHeaderData;
+
+               pageFree = PageGetExactFreeSpace(page);
+
+               usedSpace += bufferSize - pageFree;
+
+               if (pageFree == bufferSize)
+                       emptyPages++;
+
+               UnlockReleaseBuffer(buffer);
+       }
+
+       index_close(index, AccessExclusiveLock);
+
+       totalPages--;                      /* discount metapage */
+
+       snprintf(res, sizeof(res),
+                        "totalPages:        %u\n"
+                        "deletedPages:      %u\n"
+                        "innerPages:        %u\n"
+                        "leafPages:         %u\n"
+                        "emptyPages:        %u\n"
+                        "usedSpace:         %.2f kbytes\n"
+                        "freeSpace:         %.2f kbytes\n"
+                        "fillRatio:         %.2f%%\n"
+                        "leafTuples:        " INT64_FORMAT "\n"
+                        "innerTuples:       " INT64_FORMAT "\n"
+                        "innerAllTheSame:   " INT64_FORMAT "\n"
+                        "leafPlaceholders:  " INT64_FORMAT "\n"
+                        "innerPlaceholders: " INT64_FORMAT "\n"
+                        "leafRedirects:     " INT64_FORMAT "\n"
+                        "innerRedirects:    " INT64_FORMAT,
+                        totalPages, deletedPages, innerPages, leafPages, emptyPages,
+                        usedSpace / 1024.0,
+                        (((double) bufferSize) * ((double) totalPages) - usedSpace) / 1024,
+                        100.0 * (usedSpace / (((double) bufferSize) * ((double) totalPages))),
+                        leafTuples, innerTuples, nAllTheSame,
+                        nLeafPlaceholder, nInnerPlaceholder,
+                        nLeafRedirect, nInnerRedirect);
+
+       PG_RETURN_TEXT_P(CStringGetTextDatum(res));
+#endif
+}
+