v11 support
[gevel.git] / gevel.c
diff --git a/gevel.c b/gevel.c
index 6a62b85..ff5e5c4 100644 (file)
--- a/gevel.c
+++ b/gevel.c
 #endif
 #include "access/heapam.h"
 #include "catalog/index.h"
+#if PG_VERSION_NUM >= 90600
+#include <catalog/pg_am.h>
+#endif
 #include "miscadmin.h"
 #include "storage/lmgr.h"
 #include "catalog/namespace.h"
 #if PG_VERSION_NUM >= 80300
 #include <tsearch/ts_utils.h>
 #endif
+#if PG_VERSION_NUM >= 100000
+#include <utils/regproc.h>
+#include <utils/varlena.h>
+#endif
 #include <utils/tqual.h>
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
 #include <access/relscan.h>
 
 
-#define PAGESIZE       (BLCKSZ - MAXALIGN(sizeof(PageHeaderData) + sizeof(ItemIdData)))
+#define PAGESIZE       (BLCKSZ - MAXALIGN(sizeof(PageHeaderData) + sizeof(ItemIdData)))
 
 #ifndef PG_NARGS
 #define PG_NARGS() (fcinfo->nargs)
 #endif
 
 #if PG_VERSION_NUM >= 90600
-#define        ISNULL          true
+#define        ISNULL          true
 #define ISNOTNULL      false
 #define heap_formtuple heap_form_tuple
 #else
@@ -64,7 +71,7 @@ typedef struct {
        int maxlevel;
        text    *txt;
        char    *ptr;
-       int     len;
+       int             len;
 } IdxInfo;
 
 static Relation checkOpenedRelation(Relation r, Oid PgAmOid);
@@ -142,7 +149,7 @@ gin_index_close(Relation rel) {
 
 static Relation
 checkOpenedRelation(Relation r, Oid PgAmOid) {
-       if ( r->rd_am == NULL )
+       if ( r->rd_index == NULL )
                elog(ERROR, "Relation %s.%s is not an index",
                                        get_namespace_name(RelationGetNamespace(r)),
                                        RelationGetRelationName(r)
@@ -239,12 +246,12 @@ gist_tree(PG_FUNCTION_ARGS) {
 }
 
 typedef struct {
-       int     level;
-       int     numpages;
-       int     numleafpages;
-       int     numtuple;
-       int     numinvalidtuple;
-       int     numleaftuple;
+       int             level;
+       int             numpages;
+       int             numleafpages;
+       int             numtuple;
+       int             numinvalidtuple;
+       int             numleaftuple;
        uint64  tuplesize;
        uint64  leaftuplesize;
        uint64  totalsize;
@@ -401,6 +408,12 @@ closeGPPage( FuncCallContext *funcctx ) {
        return ( (TypeStorage*)(funcctx->user_fctx) )->item;
 }
 
+#if PG_VERSION_NUM >= 110000
+#define TS_GET_TYPEVAL(s, i, v)        (s)->index->rd_att->attrs[(i)].v
+#else
+#define TS_GET_TYPEVAL(s, i, v)        (s)->index->rd_att->attrs[(i)]->v
+#endif
+
 static void
 setup_firstcall(FuncCallContext  *funcctx, text *name) {
        MemoryContext     oldcontext;
@@ -428,14 +441,14 @@ setup_firstcall(FuncCallContext  *funcctx, text *name) {
                        tupdesc,
                        i+3,
                        attname,
-                       st->index->rd_att->attrs[i]->atttypid,
-                       st->index->rd_att->attrs[i]->atttypmod,
-                       st->index->rd_att->attrs[i]->attndims
+                       TS_GET_TYPEVAL(st, i, atttypid),
+                       TS_GET_TYPEVAL(st, i, atttypmod),
+                       TS_GET_TYPEVAL(st, i, attndims)
                );
        }
 
        st->dvalues = (Datum *) palloc((tupdesc->natts+2) * sizeof(Datum));
-       st->nulls = (char *) palloc((tupdesc->natts+2) * sizeof(*st->nulls));
+       st->nulls = palloc((tupdesc->natts+2) * sizeof(*st->nulls));
 
        funcctx->slot = TupleDescGetSlot(tupdesc);
        funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
@@ -531,7 +544,11 @@ typedef struct GinStatState {
        GinNullCategory category;
 #endif
        Datum                   dvalues[2];
+#if PG_VERSION_NUM >= 110000
+       bool                    nulls[2];
+#else
        char                    nulls[2];
+#endif
 } GinStatState;
 
 static bool
@@ -589,14 +606,14 @@ refindPosition(GinStatState *st)
        }
 
        for(;;) {
-               int                     cmp;
+               int                             cmp;
 #if PG_VERSION_NUM >= 90100
                GinNullCategory category;
 #elif PG_VERSION_NUM < 80400
                bool                    isnull = false;
 #endif
                Datum                   datum;
-               IndexTuple              itup;
+               IndexTuple              itup;
 
                if (moveRightIfItNeeded(st)==false)
                        return false;
@@ -625,7 +642,7 @@ refindPosition(GinStatState *st)
 #endif
                if ( cmp == 0 )
                {
-                       if ( !st->index->rd_att->attrs[st->attnum]->attbyval )
+                       if ( st->curval && !TS_GET_TYPEVAL(st, st->attnum, attbyval) )
                                pfree( (void*) st->curval );
                        return true;
                }
@@ -663,9 +680,9 @@ gin_setup_firstcall(FuncCallContext  *funcctx, text *name, int attnum) {
 
        tupdesc = CreateTemplateTupleDesc(2, false);
        TupleDescInitEntry(tupdesc, 1, "value",
-                       st->index->rd_att->attrs[st->attnum]->atttypid,
-                       st->index->rd_att->attrs[st->attnum]->atttypmod,
-                       st->index->rd_att->attrs[st->attnum]->attndims);
+                       TS_GET_TYPEVAL(st, st->attnum, atttypid),
+                       TS_GET_TYPEVAL(st, st->attnum, atttypmod),
+                       TS_GET_TYPEVAL(st, st->attnum, attndims));
        TupleDescInitEntry(tupdesc, 2, "nrow", INT4OID, -1, 0);
 
        memset( st->nulls, ISNOTNULL, 2*sizeof(*st->nulls) );
@@ -682,22 +699,32 @@ gin_setup_firstcall(FuncCallContext  *funcctx, text *name, int attnum) {
 
 static void
 processTuple( FuncCallContext  *funcctx,  GinStatState *st, IndexTuple itup ) {
-       MemoryContext           oldcontext;
-#if PG_VERSION_NUM < 80400
+       MemoryContext           oldcontext;
+#if PG_VERSION_NUM >= 90100
+       Datum                           key;
+#elif PG_VERSION_NUM < 80400
        bool                            isnull;
 #endif
 
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+#if PG_VERSION_NUM >= 90100
+       key = gintuple_get_key(&st->ginstate, itup, &st->category);
+
+       if (st->category != GIN_CAT_NORM_KEY)
+               st->curval = (Datum)0;
+       else
+#endif
        st->curval = datumCopy(
 #if PG_VERSION_NUM >= 90100
-                                       gintuple_get_key(&st->ginstate, itup, &st->category),
+                                       key,
 #elif PG_VERSION_NUM >= 80400
                                        gin_index_getattr(&st->ginstate, itup),
 #else
                                        index_getattr(itup, FirstOffsetNumber, st->ginstate.tupdesc, &isnull),
 #endif
-                                       st->index->rd_att->attrs[st->attnum]->attbyval,
-                                       st->index->rd_att->attrs[st->attnum]->attlen );
+                                       TS_GET_TYPEVAL(st, st->attnum, attbyval),
+                                       TS_GET_TYPEVAL(st, st->attnum, attlen));
        MemoryContextSwitchTo(oldcontext);
 
        st->dvalues[0] = st->curval;
@@ -716,32 +743,37 @@ processTuple( FuncCallContext  *funcctx,  GinStatState *st, IndexTuple itup ) {
                ItemPointer             list;
 #else
                GinPostingTreeScan *gdi;
-               Buffer          entrybuffer;
+               Buffer                  entrybuffer;
 #endif
                Page        page;
                uint32          predictNumber;
 
                LockBuffer(st->buffer, GIN_UNLOCK);
 #if PG_VERSION_NUM >= 90400
-               stack = ginScanBeginPostingTree(&btree, st->index, rootblkno);
+               stack = ginScanBeginPostingTree(&btree, st->index, rootblkno
+#if PG_VERSION_NUM >= 90600
+                                                                               , NULL
+#endif
+                                                                               );
                page = BufferGetPage(stack->buffer);
                ItemPointerSetMin(&minItem);
                list = GinDataLeafPageGetItems(page, &nlist, minItem);
                pfree(list);
                predictNumber = stack->predictNumber;
+               st->dvalues[1] = Int32GetDatum( predictNumber * nlist );
 #elif PG_VERSION_NUM >= 90100
                gdi = ginPrepareScanPostingTree(st->index, rootblkno, TRUE);
                entrybuffer = ginScanBeginPostingTree(gdi);
                page = BufferGetPage(entrybuffer);
                predictNumber = gdi->stack->predictNumber;
+               st->dvalues[1] = Int32GetDatum( predictNumber * GinPageGetOpaque(page)->maxoff );
 #else
                gdi = prepareScanPostingTree(st->index, rootblkno, TRUE);
                entrybuffer = scanBeginPostingTree(gdi);
                page = BufferGetPage(entrybuffer);
                predictNumber = gdi->stack->predictNumber;
-#endif
-
                st->dvalues[1] = Int32GetDatum( predictNumber * GinPageGetOpaque(page)->maxoff );
+#endif
 
 #if PG_VERSION_NUM < 90400
                LockBuffer(entrybuffer, GIN_UNLOCK);
@@ -817,14 +849,18 @@ 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;
+       text                    *name=PG_GETARG_TEXT_P(0);
+       Relation                index;
        IndexScanDesc   scan;
        int64                   count = 0;
-       char                    *relname=t2c(name);
+       char                    *relname=t2c(name);
        ScanKeyData             key;
 #if PG_VERSION_NUM >= 80400
-       TIDBitmap               *bitmap = tbm_create(work_mem * 1024L);
+       TIDBitmap               *bitmap = tbm_create(work_mem * 1024L
+#if PG_VERSION_NUM >= 100000
+                                                                                , NULL
+#endif
+                                                                                );
 #else
 #define        MAXTIDS         1024
        ItemPointerData tids[MAXTIDS];
@@ -840,8 +876,8 @@ gin_count_estimate(PG_FUNCTION_ARGS) {
                elog(ERROR, "Column type is not a tsvector");
        }
 
-       key.sk_flags    = 0;
-       key.sk_attno    = 1;
+       key.sk_flags = 0;
+       key.sk_attno = 1;
        key.sk_strategy = TSearchStrategyNumber;
        key.sk_subtype  = 0;
        key.sk_argument = PG_GETARG_DATUM(1);
@@ -1021,8 +1057,8 @@ spgist_stat(PG_FUNCTION_ARGS)
                         usedSpace / 1024.0,
                         usedInnerSpace / 1024.0,
                         usedLeafSpace / 1024.0,
-                        (((double) bufferSize) * ((double) totalPages) - usedSpace) / 1024,
-                        100.0 * (usedSpace / (((double) bufferSize) * ((double) totalPages))),
+                        (((double) bufferSize) * ((double) totalPages) - usedSpace) / 1024,
+                        100.0 * (usedSpace / (((double) bufferSize) * ((double) totalPages))),
                         leafTuples, innerTuples, nAllTheSame,
                         nLeafPlaceholder, nInnerPlaceholder,
                         nLeafRedirect, nInnerRedirect);
@@ -1034,16 +1070,20 @@ spgist_stat(PG_FUNCTION_ARGS)
 #if PG_VERSION_NUM >= 90200
 
 typedef struct SPGistPrintStackElem {
-       ItemPointerData         iptr;
+       ItemPointerData         iptr;
        int16                           nlabel;
        int                                     level;
 } SPGistPrintStackElem;
 
 typedef struct SPGistPrint {
        SpGistState     state;
-       Relation        index;
-       Datum           dvalues[7 /* see CreateTemplateTupleDesc call */];
-       char            nulls[7 /* see CreateTemplateTupleDesc call */];
+       Relation        index;
+       Datum           dvalues[8 /* see CreateTemplateTupleDesc call */];
+#if PG_VERSION_NUM >= 110000
+       bool                    nulls[8];
+#else
+       char                    nulls[8];
+#endif
        List            *stack;
 } SPGistPrint;
 
@@ -1087,8 +1127,8 @@ spgist_print(PG_FUNCTION_ARGS)
        MemoryContext                   oldcontext;
 
        if (SRF_IS_FIRSTCALL()) {
-               text                    *name=PG_GETARG_TEXT_P(0);
-               RangeVar                *relvar;
+               text                    *name=PG_GETARG_TEXT_P(0);
+               RangeVar                *relvar;
                Relation                index;
                ItemPointerData ipd;
                TupleDesc               tupdesc;
@@ -1108,16 +1148,17 @@ spgist_print(PG_FUNCTION_ARGS)
                prst->index = index;
                initSpGistState(&prst->state, index);
 
-               tupdesc = CreateTemplateTupleDesc(3 /* types */ + 1 /* level */ + 1 /* nlabel */ +  2 /* tids */, false);
+               tupdesc = CreateTemplateTupleDesc(3 /* types */ + 1 /* level */ + 1 /* nlabel */ +  2 /* tids */ + 1, false);
                TupleDescInitEntry(tupdesc, 1, "tid", TIDOID, -1, 0);
-               TupleDescInitEntry(tupdesc, 2, "node", INT4OID, -1, 0);
-               TupleDescInitEntry(tupdesc, 3, "level", INT4OID, -1, 0);
-               TupleDescInitEntry(tupdesc, 4, "tid_pointer", TIDOID, -1, 0);
-               TupleDescInitEntry(tupdesc, 5, "prefix",
+               TupleDescInitEntry(tupdesc, 2, "allthesame", BOOLOID, -1, 0);
+               TupleDescInitEntry(tupdesc, 3, "node", INT4OID, -1, 0);
+               TupleDescInitEntry(tupdesc, 4, "level", INT4OID, -1, 0);
+               TupleDescInitEntry(tupdesc, 5, "tid_pointer", TIDOID, -1, 0);
+               TupleDescInitEntry(tupdesc, 6, "prefix",
                                (prst->state.attPrefixType.type == VOIDOID) ? INT4OID : prst->state.attPrefixType.type, -1, 0);
-               TupleDescInitEntry(tupdesc, 6, "label",
+               TupleDescInitEntry(tupdesc, 7, "label",
                                (prst->state.attLabelType.type == VOIDOID) ? INT4OID : prst->state.attLabelType.type, -1, 0);
-               TupleDescInitEntry(tupdesc, 7, "leaf",
+               TupleDescInitEntry(tupdesc, 8, "leaf",
                                (prst->state.attType.type == VOIDOID) ? INT4OID : prst->state.attType.type, -1, 0);
 
                funcctx->slot = TupleDescGetSlot(tupdesc);
@@ -1186,17 +1227,18 @@ next:
                                prst->dvalues[0] = PointerGetDatum(tid);
                                prst->nulls[0] = ISNOTNULL;
                                prst->nulls[1] = ISNULL;
-                               prst->dvalues[2]  = s->level;
-                               prst->nulls[2] = ISNOTNULL;
-                               prst->nulls[3] = ISNULL;
+                               prst->nulls[2] = ISNULL;
+                               prst->dvalues[3]  = s->level;
+                               prst->nulls[3] = ISNOTNULL;
                                prst->nulls[4] = ISNULL;
                                prst->nulls[5] = ISNULL;
-                               prst->dvalues[6]  = datumCopy(SGLTDATUM(leafTuple, &prst->state),
+                               prst->nulls[6] = ISNULL;
+                               prst->dvalues[7]  = datumCopy(SGLTDATUM(leafTuple, &prst->state),
                                                                                        prst->state.attType.attbyval, prst->state.attType.attlen);
-                               prst->nulls[6] = ISNOTNULL;
+                               prst->nulls[7] = ISNOTNULL;
                } else {
                        SpGistInnerTuple        innerTuple = (SpGistInnerTuple)dtuple;
-                       int                             i;
+                       int                                     i;
                        SpGistNodeTuple         node;
 
                        SGITITERATE(innerTuple, i, node) {
@@ -1216,27 +1258,29 @@ next:
                        *tid = s->iptr;
                        prst->dvalues[0] = PointerGetDatum(tid);
                        prst->nulls[0] = ISNOTNULL;
-                       prst->dvalues[1] = Int32GetDatum(s->nlabel);
+                       prst->dvalues[1] = innerTuple->allTheSame;
                        prst->nulls[1] = ISNOTNULL;
-                       prst->dvalues[2]  = s->level;
+                       prst->dvalues[2] = Int32GetDatum(s->nlabel);
                        prst->nulls[2] = ISNOTNULL;
+                       prst->dvalues[3]  = s->level;
+                       prst->nulls[3] = ISNOTNULL;
                        tid = palloc(sizeof(ItemPointerData));
                        *tid = node->t_tid;
-                       prst->dvalues[3] = PointerGetDatum(tid);
-                       prst->nulls[3] = ISNOTNULL;
+                       prst->dvalues[4] = PointerGetDatum(tid);
+                       prst->nulls[5] = ISNOTNULL;
                        if (innerTuple->prefixSize > 0) {
-                               prst->dvalues[4]  = datumCopy(SGITDATUM(innerTuple, &prst->state),
+                               prst->dvalues[5]  = datumCopy(SGITDATUM(innerTuple, &prst->state),
                                                                                        prst->state.attPrefixType.attbyval, prst->state.attPrefixType.attlen);
-                               prst->nulls[4] = ISNOTNULL;
+                               prst->nulls[5] = ISNOTNULL;
                        } else
-                               prst->nulls[4] = ISNULL;
+                               prst->nulls[5] = ISNULL;
                        if (!IndexTupleHasNulls(node)) {
-                               prst->dvalues[5]  = datumCopy(SGNTDATUM(node, &prst->state),
+                               prst->dvalues[6]  = datumCopy(SGNTDATUM(node, &prst->state),
                                                                                        prst->state.attLabelType.attbyval, prst->state.attLabelType.attlen);
-                               prst->nulls[5] = ISNOTNULL;
+                               prst->nulls[6] = ISNOTNULL;
                        } else
-                               prst->nulls[5] = ISNULL;
-                       prst->nulls[6] = ISNULL;
+                               prst->nulls[6] = ISNULL;
+                       prst->nulls[7] = ISNULL;
 
                        pushSPGistPrint(funcctx, prst, &node->t_tid, s->level + 1);
                        s->nlabel = i + 1;
@@ -1274,6 +1318,10 @@ gin_statpage(PG_FUNCTION_ARGS)
        BlockNumber blkno;
        char            res[1024];
        uint32          totalPages,
+#if PG_VERSION_NUM >= 100000
+                               deletedPages = 0,
+                               emptyDataPages = 0,
+#endif
                                entryPages = 0,
                                dataPages = 0,
                                dataInnerPages = 0,
@@ -1316,19 +1364,35 @@ gin_statpage(PG_FUNCTION_ARGS)
                page = BufferGetPage(buffer);
                header = (PageHeader)page;
 
+#if PG_VERSION_NUM >= 100000
+               if (GinPageIsDeleted(page))
+               {
+                       deletedPages++;
+               }
+               else
+#endif
                if (GinPageIsData(page))
                {
                        dataPages++;
                        if (GinPageIsLeaf(page))
                        {
-                               ItemPointerData minItem;
+                               ItemPointerData minItem, *ptr;
                                int nlist;
 
+
                                dataLeafPages++;
                                dataLeafFreeSpace += header->pd_upper - header->pd_lower;
                                ItemPointerSetMin(&minItem);
-                               pfree(GinDataLeafPageGetItems(page, &nlist, minItem));
-                               dataLeafIptrsCount += nlist;
+
+                               ptr = GinDataLeafPageGetItems(page, &nlist, minItem);
+
+                               if (ptr)
+                               {
+                                       pfree(ptr);
+                                       dataLeafIptrsCount += nlist;
+                               }
+                               else
+                                       emptyDataPages++;
                        }
                        else
                        {
@@ -1384,6 +1448,10 @@ gin_statpage(PG_FUNCTION_ARGS)
 
        snprintf(res, sizeof(res),
                         "totalPages:            %u\n"
+#if PG_VERSION_NUM >= 100000
+                        "deletedPages:          %u\n"
+                        "emptyDataPages:        %u\n"
+#endif
                         "dataPages:             %u\n"
                         "dataInnerPages:        %u\n"
                         "dataLeafPages:         %u\n"
@@ -1403,6 +1471,10 @@ gin_statpage(PG_FUNCTION_ARGS)
                         "entryAttrSize:         " INT64_FORMAT "\n"
                         ,
                         totalPages,
+#if PG_VERSION_NUM >= 100000
+                        deletedPages,
+                        emptyDataPages,
+#endif
                         dataPages,
                         dataInnerPages,
                         dataLeafPages,