#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)))
typedef struct GinStatState {
Relation index;
GinState ginstate;
+ OffsetNumber attnum;
Buffer buffer;
OffsetNumber offset;
for(;;) {
int cmp;
+#if PG_VERSION_NUM < 80400
bool isnull;
+#endif
Datum datum;
IndexTuple itup;
return false;
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, st->offset));
+#if 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
));
+#endif
if ( cmp == 0 )
{
- if ( !st->ginstate.tupdesc->attrs[0]->attbyval )
- pfree( st->curval );
+ if ( !st->index->rd_att->attrs[st->attnum]->attbyval )
+ pfree( (void*) st->curval );
return true;
}
}
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);
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) );
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 >= 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 (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);
}
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 );
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 >= 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