support for 9.1
[gevel.git] / gevel.c
diff --git a/gevel.c b/gevel.c
index 6018003..269ece9 100644 (file)
--- a/gevel.c
+++ b/gevel.c
@@ -2,6 +2,9 @@
 
 #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"
 #include "miscadmin.h"
 #include "storage/lmgr.h"
 #include "catalog/namespace.h"
+#if PG_VERSION_NUM >= 80300
+#include <tsearch/ts_utils.h>
+#endif
+#include <utils/tqual.h>
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
 #include "utils/datum.h"
+#include "utils/fmgroids.h"
 #include <fmgr.h>
 #include <funcapi.h>
 #include <access/heapam.h>
 #include <catalog/pg_type.h>
+#include <access/relscan.h>
+
 
 #define PAGESIZE       (BLCKSZ - MAXALIGN(sizeof(PageHeaderData) + sizeof(ItemIdData)))
 
@@ -149,13 +159,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" );
@@ -482,10 +492,14 @@ gist_print(PG_FUNCTION_ARGS) {
 typedef struct GinStatState {
        Relation                index;
        GinState                ginstate;
+       OffsetNumber    attnum;
 
        Buffer                  buffer;
        OffsetNumber    offset;
        Datum                   curval;
+#if PG_VERSION_NUM >= 90100
+       GinNullCategory category;
+#endif
        Datum                   dvalues[2];
        char                    nulls[2];
 } GinStatState;
@@ -545,24 +559,46 @@ refindPosition(GinStatState *st)
        }
 
        for(;;) {
-               int     cmp;
-               bool    isnull;
-               Datum   datum;
-               IndexTuple itup;
+               int                     cmp;
+#if PG_VERSION_NUM >= 90100
+               GinNullCategory category;
+#elif PG_VERSION_NUM < 80400
+               bool                    isnull = false;
+#endif
+               Datum                   datum;
+               IndexTuple              itup;
 
                if (moveRightIfItNeeded(st)==false)
                        return false;
 
                itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, st->offset));
+#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,
+                                                                       st->attnum + 1, st->curval,
+                                                                       gintuple_get_attrnum(&st->ginstate, itup), datum);
+#else
                datum = index_getattr(itup, FirstOffsetNumber, st->ginstate.tupdesc, &isnull);
+
                cmp = DatumGetInt32(
                                FunctionCall2(
                                                &st->ginstate.compareFn,
                                                st->curval,
                                                datum
                                        ));
-               if ( cmp == 0 ) 
+#endif
+               if ( cmp == 0 )
+               {
+                       if ( !st->index->rd_att->attrs[st->attnum]->attbyval )
+                               pfree( (void*) st->curval );
                        return true;
+               }
 
                st->offset++;
        }
@@ -571,7 +607,7 @@ refindPosition(GinStatState *st)
 }
 
 static void
-gin_setup_firstcall(FuncCallContext  *funcctx, text *name) {
+gin_setup_firstcall(FuncCallContext  *funcctx, text *name, int attnum) {
        MemoryContext     oldcontext;
        GinStatState     *st;
        char *relname=t2c(name);
@@ -582,16 +618,24 @@ gin_setup_firstcall(FuncCallContext  *funcctx, text *name) {
        st=(GinStatState*)palloc( sizeof(GinStatState) );
        memset(st,0,sizeof(GinStatState));
        st->index = gin_index_open(
-                makeRangeVarFromNameList(stringToQualifiedNameList(relname, "gist_tree")));
+                makeRangeVarFromNameList(stringToQualifiedNameList(relname, "gin_stat")));
        initGinState( &st->ginstate, st->index );
 
+#if PG_VERSION_NUM >= 80400
+       if (attnum < 0 || attnum >= st->index->rd_att->natts)
+               elog(ERROR,"Wrong column's number");
+       st->attnum = attnum;
+#else
+       st->attnum = 0;
+#endif
+
        funcctx->user_fctx = (void*)st;
 
        tupdesc = CreateTemplateTupleDesc(2, false);
        TupleDescInitEntry(tupdesc, 1, "value", 
-                       st->index->rd_att->attrs[0]->atttypid, 
-                       st->index->rd_att->attrs[0]->atttypmod,
-                       st->index->rd_att->attrs[0]->attndims);
+                       st->index->rd_att->attrs[st->attnum]->atttypid, 
+                       st->index->rd_att->attrs[st->attnum]->atttypmod,
+                       st->index->rd_att->attrs[st->attnum]->attndims);
        TupleDescInitEntry(tupdesc, 2, "nrow", INT4OID, -1, 0);
 
        memset( st->nulls, ' ', 2*sizeof(char) );
@@ -609,19 +653,29 @@ gin_setup_firstcall(FuncCallContext  *funcctx, text *name) {
 static void
 processTuple( FuncCallContext  *funcctx,  GinStatState *st, IndexTuple itup ) {
        MemoryContext           oldcontext;
-       Datum                           datum;
+#if PG_VERSION_NUM < 80400
        bool                            isnull;
+#endif
 
-       datum = index_getattr(itup, FirstOffsetNumber, st->ginstate.tupdesc, &isnull);
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
        st->curval = datumCopy(
+#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),
-                                       st->ginstate.tupdesc->attrs[0]->attbyval,
-                                       st->ginstate.tupdesc->attrs[0]->attlen );
+#endif
+                                       st->index->rd_att->attrs[st->attnum]->attbyval,
+                                       st->index->rd_att->attrs[st->attnum]->attlen );
        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;
@@ -629,8 +683,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 );
@@ -658,7 +717,7 @@ gin_stat(PG_FUNCTION_ARGS) {
        if (SRF_IS_FIRSTCALL()) {
                text    *name=PG_GETARG_TEXT_P(0);
                funcctx = SRF_FIRSTCALL_INIT();
-               gin_setup_firstcall(funcctx, name);
+               gin_setup_firstcall(funcctx, name, (PG_NARGS()==2) ? PG_GETARG_INT32(1) : 0 );
                PG_FREE_IF_COPY(name,0);
        }
 
@@ -672,17 +731,24 @@ gin_stat(PG_FUNCTION_ARGS) {
                SRF_RETURN_DONE(funcctx);
        }
 
-       st->offset++;
+       for(;;) {
+               st->offset++;
        
-       if (moveRightIfItNeeded(st)==false) { 
-               UnlockReleaseBuffer( st->buffer );
-               gin_index_close(st->index);
+               if (moveRightIfItNeeded(st)==false) { 
+                       UnlockReleaseBuffer( st->buffer );
+                       gin_index_close(st->index);
 
-               SRF_RETURN_DONE(funcctx);
-       }
+                       SRF_RETURN_DONE(funcctx);
+               }
 
-       page = BufferGetPage(st->buffer);
-       ituple = (IndexTuple) PageGetItem(page, PageGetItemId(page, st->offset)); 
+               page = BufferGetPage(st->buffer);
+               ituple = (IndexTuple) PageGetItem(page, PageGetItemId(page, st->offset)); 
+
+#if PG_VERSION_NUM >= 80400
+               if (st->attnum + 1 == gintuple_get_attrnum(&st->ginstate, ituple))
+#endif
+                       break;
+       }
 
        processTuple( funcctx,  st, ituple );
        
@@ -692,3 +758,72 @@ gin_stat(PG_FUNCTION_ARGS) {
        SRF_RETURN_NEXT(funcctx, result);
 }
 
+PG_FUNCTION_INFO_V1(gin_count_estimate);
+Datum gin_count_estimate(PG_FUNCTION_ARGS);
+#if PG_VERSION_NUM >= 80300
+Datum
+gin_count_estimate(PG_FUNCTION_ARGS) {
+       text                    *name=PG_GETARG_TEXT_P(0);
+       Relation                index;
+       IndexScanDesc   scan;
+       int64                   count = 0;
+       char                    *relname=t2c(name);
+       ScanKeyData             key;
+#if PG_VERSION_NUM >= 80400
+       TIDBitmap               *bitmap = tbm_create(work_mem * 1024L);
+#else
+#define        MAXTIDS         1024
+       ItemPointerData tids[MAXTIDS];
+       int32                   returned_tids;
+       bool                    more;
+#endif
+
+       index = gin_index_open(
+                makeRangeVarFromNameList(stringToQualifiedNameList(relname, "gin_count_estimate")));
+
+       if ( index->rd_opcintype[0] != TSVECTOROID ) {
+               gin_index_close(index);
+               elog(ERROR, "Column type is not a tsvector");
+       }
+
+       key.sk_flags    = 0;
+       key.sk_attno    = 1;
+       key.sk_strategy = TSearchStrategyNumber;
+       key.sk_subtype  = 0;
+       key.sk_argument = PG_GETARG_DATUM(1);
+
+       fmgr_info( F_TS_MATCH_VQ , &key.sk_func );
+
+#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);
+       tbm_free(bitmap);
+#else
+       scan = index_beginscan_multi(index, SnapshotNow, 1, &key);
+
+       do {
+               more = index_getmulti(scan, tids, MAXTIDS, &returned_tids);
+               count += returned_tids;
+       } while(more);
+#endif
+
+       index_endscan( scan );
+       gin_index_close(index);
+
+       PG_RETURN_INT64(count);
+}
+#else
+Datum
+gin_count_estimate(PG_FUNCTION_ARGS) {
+       elog(NOTICE, "Function is not working under PgSQL < 8.3");
+
+       PG_RETURN_INT64(0);
+}
+#endif