diff --git a/contrib/intarray/Makefile b/contrib/intarray/Makefile index 7cb06da2ac..b7249a8b7c 100644 --- a/contrib/intarray/Makefile +++ b/contrib/intarray/Makefile @@ -1,10 +1,11 @@ -# $Header: /cvsroot/pgsql/contrib/intarray/Makefile,v 1.8 2001/09/06 10:49:29 petere Exp $ +# $Header: /cvsroot/pgsql/contrib/intarray/Makefile,v 1.9 2003/06/11 18:44:14 momjian Exp $ subdir = contrib/intarray top_builddir = ../.. include $(top_builddir)/src/Makefile.global -MODULES = _int +MODULE_big = _int +OBJS = _int_bool.o _int_gist.o _int_op.o _int_tool.o _intbig_gist.o DATA_built = _int.sql DOCS = README.intarray REGRESS = _int diff --git a/contrib/intarray/_int.c b/contrib/intarray/_int.c deleted file mode 100644 index eb42e41216..0000000000 --- a/contrib/intarray/_int.c +++ /dev/null @@ -1,2693 +0,0 @@ -/****************************************************************************** - This file contains routines that can be bound to a Postgres backend and - called by the backend in the process of processing queries. The calling - format for these routines is dictated by Postgres architecture. -******************************************************************************/ - -/* -#define BS_DEBUG -#define GIST_DEBUG -#define GIST_QUERY_DEBUG -*/ - -#include "postgres.h" - -#include - -#include "access/gist.h" -#include "access/itup.h" -#include "access/rtree.h" -#include "catalog/pg_type.h" -#include "utils/elog.h" -#include "utils/palloc.h" -#include "utils/array.h" -#include "utils/builtins.h" -#include "storage/bufpage.h" -#include "lib/stringinfo.h" - -/* number ranges for compression */ -#define MAXNUMRANGE 100 - -#define max(a,b) ((a) > (b) ? (a) : (b)) -#define min(a,b) ((a) <= (b) ? (a) : (b)) -#define abs(a) ((a) < (0) ? -(a) : (a)) - -/* dimension of array */ -#define NDIM 1 - -/* - * flags for gist__int_ops, use ArrayType->flags - * which is unused (see array.h) - */ -#define LEAFKEY (1<<31) -#define ISLEAFKEY(x) ( ((ArrayType*)(x))->flags & LEAFKEY ) - -/* useful macros for accessing int4 arrays */ -#define ARRPTR(x) ( (int4 *) ARR_DATA_PTR(x) ) -#define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x)) - -#define ARRISVOID(x) ( (x) ? ( ( ARR_NDIM(x) == NDIM ) ? ( ( ARRNELEMS( x ) ) ? 0 : 1 ) : ( ( ARR_NDIM(x) ) ? (elog(ERROR,"Array is not one-dimensional: %d dimensions",ARRNELEMS( x )),1) : 0 ) ) : 0 ) - -#define SORT(x) \ - do { \ - if ( ARRNELEMS( x ) > 1 ) \ - isort( ARRPTR( x ), ARRNELEMS( x ) ); \ - } while(0) - -#define PREPAREARR(x) \ - do { \ - if ( ARRNELEMS( x ) > 1 ) \ - if ( isort( ARRPTR( x ), ARRNELEMS( x ) ) ) \ - x = _int_unique( x ); \ - } while(0) - -/* "wish" function */ -#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) ) - - -/* bigint defines */ -#define BITBYTE 8 -#define SIGLENINT 64 /* >122 => key will toast, so very slow!!! */ -#define SIGLEN ( sizeof(int)*SIGLENINT ) -#define SIGLENBIT (SIGLEN*BITBYTE) - -typedef char BITVEC[SIGLEN]; -typedef char *BITVECP; - -#define SIGPTR(x) ( (BITVECP) ARR_DATA_PTR(x) ) - - -#define LOOPBYTE(a) \ - for(i=0;i> (i)) & 0x01 ) -#define CLRBIT(x,i) GETBYTE(x,i) &= ~( 0x01 << ( (i) % BITBYTE ) ) -#define SETBIT(x,i) GETBYTE(x,i) |= ( 0x01 << ( (i) % BITBYTE ) ) -#define GETBIT(x,i) ( (GETBYTE(x,i) >> ( (i) % BITBYTE )) & 0x01 ) -#define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT) -#define HASH(sign, val) SETBIT((sign), HASHVAL(val)) - - -#ifdef GIST_DEBUG -static void -printarr(ArrayType *a, int num) -{ - StringInfoData bbb; - char *cur; - int l; - int *d; - - d = ARRPTR(a); - initStringInfo(&bbb); - for (l = 0; l < min(num, ARRNELEMS(a)); l++) - appendStringInfo(&bbb, "%d ", d[l]); - elog(DEBUG4, "\t\t%s", bbb.data); - pfree(bbb.data); -} -static void -printbitvec(BITVEC bv) -{ - int i; - char str[SIGLENBIT + 1]; - - str[SIGLENBIT] = '\0'; - LOOPBIT(str[i] = (GETBIT(bv, i)) ? '1' : '0'); - - elog(DEBUG4, "BV: %s", str); -} -#endif - -/* -** types for functions -*/ -typedef ArrayType *(*formarray) (ArrayType *, ArrayType *); -typedef void (*formfloat) (ArrayType *, float *); - -/* -** useful function -*/ -static bool isort(int4 *a, const int len); -static ArrayType *new_intArrayType(int num); -static ArrayType *copy_intArrayType(ArrayType *a); -static ArrayType *resize_intArrayType(ArrayType *a, int num); -static int internal_size(int *a, int len); -static ArrayType *_int_unique(ArrayType *a); - -/* common GiST function*/ -static GIST_SPLITVEC *_int_common_picksplit(bytea *entryvec, - GIST_SPLITVEC *v, - formarray unionf, - formarray interf, - formfloat sizef, - float coef); -static float *_int_common_penalty(GISTENTRY *origentry, - GISTENTRY *newentry, - float *result, - formarray unionf, - formfloat sizef); -static ArrayType *_int_common_union(bytea *entryvec, - int *sizep, - formarray unionf); - -/* -** GiST support methods -*/ -PG_FUNCTION_INFO_V1(g_int_consistent); -PG_FUNCTION_INFO_V1(g_int_compress); -PG_FUNCTION_INFO_V1(g_int_decompress); -PG_FUNCTION_INFO_V1(g_int_penalty); -PG_FUNCTION_INFO_V1(g_int_picksplit); -PG_FUNCTION_INFO_V1(g_int_union); -PG_FUNCTION_INFO_V1(g_int_same); - -Datum g_int_consistent(PG_FUNCTION_ARGS); -Datum g_int_compress(PG_FUNCTION_ARGS); -Datum g_int_decompress(PG_FUNCTION_ARGS); -Datum g_int_penalty(PG_FUNCTION_ARGS); -Datum g_int_picksplit(PG_FUNCTION_ARGS); -Datum g_int_union(PG_FUNCTION_ARGS); -Datum g_int_same(PG_FUNCTION_ARGS); - - -/* -** R-tree support functions -*/ -static bool inner_int_contains(ArrayType *a, ArrayType *b); -static bool inner_int_overlap(ArrayType *a, ArrayType *b); -static ArrayType *inner_int_union(ArrayType *a, ArrayType *b); -static ArrayType *inner_int_inter(ArrayType *a, ArrayType *b); -static void rt__int_size(ArrayType *a, float *sz); - -PG_FUNCTION_INFO_V1(_int_different); -PG_FUNCTION_INFO_V1(_int_same); -PG_FUNCTION_INFO_V1(_int_contains); -PG_FUNCTION_INFO_V1(_int_contained); -PG_FUNCTION_INFO_V1(_int_overlap); -PG_FUNCTION_INFO_V1(_int_union); -PG_FUNCTION_INFO_V1(_int_inter); - -Datum _int_different(PG_FUNCTION_ARGS); -Datum _int_same(PG_FUNCTION_ARGS); -Datum _int_contains(PG_FUNCTION_ARGS); -Datum _int_contained(PG_FUNCTION_ARGS); -Datum _int_overlap(PG_FUNCTION_ARGS); -Datum _int_union(PG_FUNCTION_ARGS); -Datum _int_inter(PG_FUNCTION_ARGS); - -/* -** _intbig methods -*/ -PG_FUNCTION_INFO_V1(g_intbig_consistent); -PG_FUNCTION_INFO_V1(g_intbig_compress); -PG_FUNCTION_INFO_V1(g_intbig_decompress); -PG_FUNCTION_INFO_V1(g_intbig_penalty); -PG_FUNCTION_INFO_V1(g_intbig_picksplit); -PG_FUNCTION_INFO_V1(g_intbig_union); -PG_FUNCTION_INFO_V1(g_intbig_same); - -Datum g_intbig_consistent(PG_FUNCTION_ARGS); -Datum g_intbig_compress(PG_FUNCTION_ARGS); -Datum g_intbig_decompress(PG_FUNCTION_ARGS); -Datum g_intbig_penalty(PG_FUNCTION_ARGS); -Datum g_intbig_picksplit(PG_FUNCTION_ARGS); -Datum g_intbig_union(PG_FUNCTION_ARGS); -Datum g_intbig_same(PG_FUNCTION_ARGS); - -static bool _intbig_contains(ArrayType *a, ArrayType *b); -static bool _intbig_overlap(ArrayType *a, ArrayType *b); -static ArrayType *_intbig_union(ArrayType *a, ArrayType *b); - -static ArrayType *_intbig_inter(ArrayType *a, ArrayType *b); -static void rt__intbig_size(ArrayType *a, float *sz); - - - -/***************************************************************************** - * Boolean Search - *****************************************************************************/ - -#define BooleanSearchStrategy 20 - -/* - * item in polish notation with back link - * to left operand - */ -typedef struct ITEM -{ - int2 type; - int2 left; - int4 val; -} ITEM; - -typedef struct -{ - int4 len; - int4 size; - char data[1]; -} QUERYTYPE; - -#define HDRSIZEQT ( 2*sizeof(int4) ) -#define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) ) -#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT ) - -PG_FUNCTION_INFO_V1(bqarr_in); -PG_FUNCTION_INFO_V1(bqarr_out); -Datum bqarr_in(PG_FUNCTION_ARGS); -Datum bqarr_out(PG_FUNCTION_ARGS); - -PG_FUNCTION_INFO_V1(boolop); -Datum boolop(PG_FUNCTION_ARGS); - -PG_FUNCTION_INFO_V1(rboolop); -Datum rboolop(PG_FUNCTION_ARGS); - -PG_FUNCTION_INFO_V1(querytree); -Datum querytree(PG_FUNCTION_ARGS); - -static bool signconsistent(QUERYTYPE * query, BITVEC sign, bool leaf); -static bool execconsistent(QUERYTYPE * query, ArrayType *array, bool leaf); - -/***************************************************************************** - * GiST functions - *****************************************************************************/ - -/* -** The GiST Consistent method for _intments -** Should return false if for all data items x below entry, -** the predicate x op query == FALSE, where op is the oper -** corresponding to strategy in the pg_amop table. -*/ -Datum -g_int_consistent(PG_FUNCTION_ARGS) -{ - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); - ArrayType *query = (ArrayType *) PG_GETARG_POINTER(1); - StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); - bool retval; - - if (strategy == BooleanSearchStrategy) - PG_RETURN_BOOL(execconsistent((QUERYTYPE *) query, - (ArrayType *) DatumGetPointer(entry->key), - ISLEAFKEY((ArrayType *) DatumGetPointer(entry->key)))); - - /* XXX are we sure it's safe to scribble on the query object here? */ - /* XXX what about toasted input? */ - /* sort query for fast search, key is already sorted */ - if (ARRISVOID(query)) - PG_RETURN_BOOL(false); - PREPAREARR(query); - - switch (strategy) - { - case RTOverlapStrategyNumber: - retval = inner_int_overlap((ArrayType *) DatumGetPointer(entry->key), - query); - break; - case RTSameStrategyNumber: - if (GIST_LEAF(entry)) - DirectFunctionCall3( - g_int_same, - entry->key, - PointerGetDatum(query), - PointerGetDatum(&retval) - ); - else - retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key), - query); - break; - case RTContainsStrategyNumber: - retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key), - query); - break; - case RTContainedByStrategyNumber: - if (GIST_LEAF(entry)) - retval = inner_int_contains(query, - (ArrayType *) DatumGetPointer(entry->key)); - else - retval = inner_int_overlap((ArrayType *) DatumGetPointer(entry->key), - query); - break; - default: - retval = FALSE; - } - PG_RETURN_BOOL(retval); -} - -Datum -g_int_union(PG_FUNCTION_ARGS) -{ - PG_RETURN_POINTER(_int_common_union( - (bytea *) PG_GETARG_POINTER(0), - (int *) PG_GETARG_POINTER(1), - inner_int_union - )); -} - -/* -** GiST Compress and Decompress methods -*/ -Datum -g_int_compress(PG_FUNCTION_ARGS) -{ - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); - GISTENTRY *retval; - ArrayType *r; - int len; - int *dr; - int i, - min, - cand; - - if (entry->leafkey) - { - r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key); - PREPAREARR(r); - r->flags |= LEAFKEY; - retval = palloc(sizeof(GISTENTRY)); - gistentryinit(*retval, PointerGetDatum(r), - entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE); - - PG_RETURN_POINTER(retval); - } - - r = (ArrayType *) PG_DETOAST_DATUM(entry->key); - if (ISLEAFKEY(r) || ARRISVOID(r)) - { - if (r != (ArrayType *) DatumGetPointer(entry->key)) - pfree(r); - PG_RETURN_POINTER(entry); - } - - if ((len = ARRNELEMS(r)) >= 2 * MAXNUMRANGE) - { /* compress */ - if (r == (ArrayType *) DatumGetPointer(entry->key)) - r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key); - r = resize_intArrayType(r, 2 * (len)); - - dr = ARRPTR(r); - - for (i = len - 1; i >= 0; i--) - dr[2 * i] = dr[2 * i + 1] = dr[i]; - - len *= 2; - cand = 1; - while (len > MAXNUMRANGE * 2) - { - min = 0x7fffffff; - for (i = 2; i < len; i += 2) - if (min > (dr[i] - dr[i - 1])) - { - min = (dr[i] - dr[i - 1]); - cand = i; - } - memmove((void *) &dr[cand - 1], (void *) &dr[cand + 1], (len - cand - 1) * sizeof(int)); - len -= 2; - } - r = resize_intArrayType(r, len); - retval = palloc(sizeof(GISTENTRY)); - gistentryinit(*retval, PointerGetDatum(r), - entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE); - PG_RETURN_POINTER(retval); - } - else - PG_RETURN_POINTER(entry); - - PG_RETURN_POINTER(entry); -} - -Datum -g_int_decompress(PG_FUNCTION_ARGS) -{ - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); - GISTENTRY *retval; - ArrayType *r; - int *dr, - lenr; - ArrayType *in; - int lenin; - int *din; - int i, - j; - - in = (ArrayType *) PG_DETOAST_DATUM(entry->key); - - if (ARRISVOID(in)) - PG_RETURN_POINTER(entry); - - lenin = ARRNELEMS(in); - - if (lenin < 2 * MAXNUMRANGE || ISLEAFKEY(in)) - { /* not compressed value */ - if (in != (ArrayType *) DatumGetPointer(entry->key)) - { - retval = palloc(sizeof(GISTENTRY)); - gistentryinit(*retval, PointerGetDatum(in), - entry->rel, entry->page, entry->offset, VARSIZE(in), FALSE); - - PG_RETURN_POINTER(retval); - } - PG_RETURN_POINTER(entry); - } - - din = ARRPTR(in); - lenr = internal_size(din, lenin); - - r = new_intArrayType(lenr); - dr = ARRPTR(r); - - for (i = 0; i < lenin; i += 2) - for (j = din[i]; j <= din[i + 1]; j++) - if ((!i) || *(dr - 1) != j) - *dr++ = j; - - if (in != (ArrayType *) DatumGetPointer(entry->key)) - pfree(in); - retval = palloc(sizeof(GISTENTRY)); - gistentryinit(*retval, PointerGetDatum(r), - entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE); - - PG_RETURN_POINTER(retval); -} - -/* -** The GiST Penalty method for _intments -*/ -Datum -g_int_penalty(PG_FUNCTION_ARGS) -{ - PG_RETURN_POINTER(_int_common_penalty( - (GISTENTRY *) PG_GETARG_POINTER(0), - (GISTENTRY *) PG_GETARG_POINTER(1), - (float *) PG_GETARG_POINTER(2), - inner_int_union, rt__int_size - )); -} - - -Datum -g_int_picksplit(PG_FUNCTION_ARGS) -{ - PG_RETURN_POINTER(_int_common_picksplit( - (bytea *) PG_GETARG_POINTER(0), - (GIST_SPLITVEC *) PG_GETARG_POINTER(1), - inner_int_union, - inner_int_inter, - rt__int_size, - 0.01 - )); -} - -/* -** Equality methods -*/ - - -Datum -g_int_same(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) PointerGetDatum(PG_GETARG_POINTER(0)); - ArrayType *b = (ArrayType *) PointerGetDatum(PG_GETARG_POINTER(1)); - bool *result = (bool *) PG_GETARG_POINTER(2); - int4 n = ARRNELEMS(a); - int4 *da, - *db; - - if (n != ARRNELEMS(b)) - { - *result = false; - PG_RETURN_POINTER(result); - } - *result = TRUE; - da = ARRPTR(a); - db = ARRPTR(b); - while (n--) - if (*da++ != *db++) - { - *result = FALSE; - break; - } - - PG_RETURN_POINTER(result); -} - -Datum -_int_contained(PG_FUNCTION_ARGS) -{ - PG_RETURN_BOOL(DatumGetBool( - DirectFunctionCall2( - _int_contains, - PointerGetDatum(PG_GETARG_POINTER(1)), - PointerGetDatum(PG_GETARG_POINTER(0)) - ) - )); -} - -Datum -_int_contains(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); - ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); - bool res; - - if (ARRISVOID(a) || ARRISVOID(b)) - return FALSE; - - PREPAREARR(a); - PREPAREARR(b); - res = inner_int_contains(a, b); - pfree(a); - pfree(b); - PG_RETURN_BOOL(res); -} - -static bool -inner_int_contains(ArrayType *a, ArrayType *b) -{ - int na, - nb; - int i, - j, - n; - int *da, - *db; - - if (ARRISVOID(a) || ARRISVOID(b)) - return FALSE; - - na = ARRNELEMS(a); - nb = ARRNELEMS(b); - da = ARRPTR(a); - db = ARRPTR(b); - -#ifdef GIST_DEBUG - elog(DEBUG4, "contains %d %d", na, nb); -#endif - - i = j = n = 0; - while (i < na && j < nb) - if (da[i] < db[j]) - i++; - else if (da[i] == db[j]) - { - n++; - i++; - j++; - } - else - j++; - - return (n == nb) ? TRUE : FALSE; -} - -/***************************************************************************** - * Operator class for R-tree indexing - *****************************************************************************/ - -Datum -_int_different(PG_FUNCTION_ARGS) -{ - PG_RETURN_BOOL(!DatumGetBool( - DirectFunctionCall2( - _int_same, - PointerGetDatum(PG_GETARG_POINTER(0)), - PointerGetDatum(PG_GETARG_POINTER(1)) - ) - )); -} - -Datum -_int_same(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); - ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); - int na, - nb; - int n; - int *da, - *db; - bool result; - bool avoid = ARRISVOID(a); - bool bvoid = ARRISVOID(b); - - if (avoid || bvoid) - return (avoid && bvoid) ? TRUE : FALSE; - - SORT(a); - SORT(b); - na = ARRNELEMS(a); - nb = ARRNELEMS(b); - da = ARRPTR(a); - db = ARRPTR(b); - - result = FALSE; - - if (na == nb) - { - result = TRUE; - for (n = 0; n < na; n++) - if (da[n] != db[n]) - { - result = FALSE; - break; - } - } - - pfree(a); - pfree(b); - - PG_RETURN_BOOL(result); -} - -/* _int_overlap -- does a overlap b? - */ -Datum -_int_overlap(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); - ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); - bool result; - - if (ARRISVOID(a) || ARRISVOID(b)) - return FALSE; - - SORT(a); - SORT(b); - - result = inner_int_overlap(a, b); - - pfree(a); - pfree(b); - - PG_RETURN_BOOL(result); -} - -static bool -inner_int_overlap(ArrayType *a, ArrayType *b) -{ - int na, - nb; - int i, - j; - int *da, - *db; - - if (ARRISVOID(a) || ARRISVOID(b)) - return FALSE; - - na = ARRNELEMS(a); - nb = ARRNELEMS(b); - da = ARRPTR(a); - db = ARRPTR(b); - -#ifdef GIST_DEBUG - elog(DEBUG4, "g_int_overlap"); -#endif - - i = j = 0; - while (i < na && j < nb) - if (da[i] < db[j]) - i++; - else if (da[i] == db[j]) - return TRUE; - else - j++; - - return FALSE; -} - -Datum -_int_union(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); - ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); - ArrayType *result; - - if (!ARRISVOID(a)) - SORT(a); - if (!ARRISVOID(b)) - SORT(b); - - result = inner_int_union(a, b); - - if (a) - pfree(a); - if (b) - pfree(b); - - PG_RETURN_POINTER(result); -} - -static ArrayType * -inner_int_union(ArrayType *a, ArrayType *b) -{ - ArrayType *r = NULL; - int na, - nb; - int *da, - *db, - *dr; - int i, - j; - - if (ARRISVOID(a) && ARRISVOID(b)) - return new_intArrayType(0); - if (ARRISVOID(a)) - r = copy_intArrayType(b); - if (ARRISVOID(b)) - r = copy_intArrayType(a); - - if (r) - dr = ARRPTR(r); - else - { - na = ARRNELEMS(a); - nb = ARRNELEMS(b); - da = ARRPTR(a); - db = ARRPTR(b); - - r = new_intArrayType(na + nb); - dr = ARRPTR(r); - - /* union */ - i = j = 0; - while (i < na && j < nb) - if (da[i] < db[j]) - *dr++ = da[i++]; - else - *dr++ = db[j++]; - - while (i < na) - *dr++ = da[i++]; - while (j < nb) - *dr++ = db[j++]; - - } - - if (ARRNELEMS(r) > 1) - r = _int_unique(r); - - return r; -} - - -Datum -_int_inter(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); - ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); - ArrayType *result; - - if (ARRISVOID(a) || ARRISVOID(b)) - PG_RETURN_POINTER(new_intArrayType(0)); - - SORT(a); - SORT(b); - - result = inner_int_inter(a, b); - - pfree(a); - pfree(b); - - PG_RETURN_POINTER(result); -} - -static ArrayType * -inner_int_inter(ArrayType *a, ArrayType *b) -{ - ArrayType *r; - int na, - nb; - int *da, - *db, - *dr; - int i, - j; - - if (ARRISVOID(a) || ARRISVOID(b)) - return new_intArrayType(0); - - na = ARRNELEMS(a); - nb = ARRNELEMS(b); - da = ARRPTR(a); - db = ARRPTR(b); - r = new_intArrayType(min(na, nb)); - dr = ARRPTR(r); - - i = j = 0; - while (i < na && j < nb) - if (da[i] < db[j]) - i++; - else if (da[i] == db[j]) - { - if (i + j == 0 || (i + j > 0 && *(dr - 1) != db[j])) - *dr++ = db[j]; - i++; - j++; - } - else - j++; - - if ((dr - ARRPTR(r)) == 0) - { - pfree(r); - return new_intArrayType(0); - } - else - return resize_intArrayType(r, dr - ARRPTR(r)); -} - -static void -rt__int_size(ArrayType *a, float *size) -{ - *size = (float) ARRNELEMS(a); - - return; -} - - -/***************************************************************************** - * Miscellaneous operators and functions - *****************************************************************************/ - -/* len >= 2 */ -static bool -isort(int4 *a, int len) -{ - int4 tmp, - index; - int4 *cur, - *end; - bool r = FALSE; - - end = a + len; - do - { - index = 0; - cur = a + 1; - while (cur < end) - { - if (*(cur - 1) > *cur) - { - tmp = *(cur - 1); - *(cur - 1) = *cur; - *cur = tmp; - index = 1; - } - else if (!r && *(cur - 1) == *cur) - r = TRUE; - cur++; - } - } while (index); - return r; -} - -static ArrayType * -new_intArrayType(int num) -{ - ArrayType *r; - int nbytes = ARR_OVERHEAD(NDIM) + sizeof(int) * num; - - r = (ArrayType *) palloc0(nbytes); - - ARR_SIZE(r) = nbytes; - ARR_NDIM(r) = NDIM; - ARR_ELEMTYPE(r) = INT4OID; - r->flags &= ~LEAFKEY; - *((int *) ARR_DIMS(r)) = num; - *((int *) ARR_LBOUND(r)) = 1; - - return r; -} - -static ArrayType * -resize_intArrayType(ArrayType *a, int num) -{ - int nbytes = ARR_OVERHEAD(NDIM) + sizeof(int) * num; - - if (num == ARRNELEMS(a)) - return a; - - a = (ArrayType *) repalloc(a, nbytes); - - a->size = nbytes; - *((int *) ARR_DIMS(a)) = num; - return a; -} - -static ArrayType * -copy_intArrayType(ArrayType *a) -{ - ArrayType *r; - - r = new_intArrayType(ARRNELEMS(a)); - memmove(r, a, VARSIZE(a)); - return r; -} - -/* num for compressed key */ -static int -internal_size(int *a, int len) -{ - int i, - size = 0; - - for (i = 0; i < len; i += 2) - if (!i || a[i] != a[i - 1]) /* do not count repeated range */ - size += a[i + 1] - a[i] + 1; - - return size; -} - -#define UNIX_UNIQ(a) a = _int_unique(a) - -/* r is sorted and size of r > 1 */ -static ArrayType * -_int_unique(ArrayType *r) -{ - int *tmp, - *dr, - *data; - int num = ARRNELEMS(r); - - if ( num<2 ) - return r; - - data = tmp = dr = ARRPTR(r); - while (tmp - data < num) - if (*tmp != *dr) - *(++dr) = *tmp++; - else - tmp++; - return resize_intArrayType(r, dr + 1 - ARRPTR(r)); -} - -/********************************************************************* -** intbig functions -*********************************************************************/ -static void -gensign(BITVEC sign, int *a, int len) -{ - int i; - - /* we assume that the sign vector is previously zeroed */ - for (i = 0; i < len; i++) - { - HASH(sign, *a); - a++; - } -} - -static bool -_intbig_overlap(ArrayType *a, ArrayType *b) -{ - int i; - BITVECP da, - db; - - da = SIGPTR(a); - db = SIGPTR(b); - - LOOPBYTE(if (da[i] & db[i]) return TRUE); - return FALSE; -} - -static bool -_intbig_contains(ArrayType *a, ArrayType *b) -{ - int i; - BITVECP da, - db; - - da = SIGPTR(a); - db = SIGPTR(b); - - LOOPBYTE(if (db[i] & ~da[i]) return FALSE); - - return TRUE; -} - -static void -rt__intbig_size(ArrayType *a, float *sz) -{ - int i, - len = 0; - BITVECP bv = SIGPTR(a); - - LOOPBYTE( - len += - GETBITBYTE(bv, 0) + - GETBITBYTE(bv, 1) + - GETBITBYTE(bv, 2) + - GETBITBYTE(bv, 3) + - GETBITBYTE(bv, 4) + - GETBITBYTE(bv, 5) + - GETBITBYTE(bv, 6) + - GETBITBYTE(bv, 7); - bv = (BITVECP) (((char *) bv) + 1); - ); - - *sz = (float) len; - return; -} - -static ArrayType * -_intbig_union(ArrayType *a, ArrayType *b) -{ - ArrayType *r; - BITVECP da, - db, - dr; - int i; - - r = new_intArrayType(SIGLENINT); - - da = SIGPTR(a); - db = SIGPTR(b); - dr = SIGPTR(r); - - LOOPBYTE(dr[i] = da[i] | db[i]); - - return r; -} - -static ArrayType * -_intbig_inter(ArrayType *a, ArrayType *b) -{ - ArrayType *r; - BITVECP da, - db, - dr; - int i; - - r = new_intArrayType(SIGLENINT); - - da = SIGPTR(a); - db = SIGPTR(b); - dr = SIGPTR(r); - - LOOPBYTE(dr[i] = da[i] & db[i]); - - return r; -} - -Datum -g_intbig_same(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) PG_GETARG_POINTER(0); - ArrayType *b = (ArrayType *) PG_GETARG_POINTER(1); - bool *result = (bool *) PG_GETARG_POINTER(2); - BITVECP da, - db; - int i; - - da = SIGPTR(a); - db = SIGPTR(b); - - LOOPBYTE( - if (da[i] != db[i]) - { - *result = FALSE; - PG_RETURN_POINTER(result); - } - ); - - *result = TRUE; - PG_RETURN_POINTER(result); -} - -Datum -g_intbig_compress(PG_FUNCTION_ARGS) -{ - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); - GISTENTRY *retval; - ArrayType *r, - *in; - bool maycompress = true; - int i; - - if (DatumGetPointer(entry->key) != NULL) - in = (ArrayType *) PG_DETOAST_DATUM(entry->key); - else - in = NULL; - - if (!entry->leafkey) - { - LOOPBYTE( - if ((((char *) ARRPTR(in))[i] & 0xff) != 0xff) - { - maycompress = false; - break; - } - ); - if (maycompress) - { - retval = palloc(sizeof(GISTENTRY)); - r = new_intArrayType(1); - gistentryinit(*retval, PointerGetDatum(r), - entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE); - PG_RETURN_POINTER(retval); - } - PG_RETURN_POINTER(entry); - } - - retval = palloc(sizeof(GISTENTRY)); - r = new_intArrayType(SIGLENINT); - - if (ARRISVOID(in)) - { - gistentryinit(*retval, PointerGetDatum(r), - entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE); - if (in != (ArrayType *) DatumGetPointer(entry->key)) - pfree(in); - PG_RETURN_POINTER(retval); - } - - gensign(SIGPTR(r), - ARRPTR(in), - ARRNELEMS(in)); - - LOOPBYTE( - if ((((char *) ARRPTR(in))[i] & 0xff) != 0xff) - { - maycompress = false; - break; - } - ); - - if (maycompress) - { - pfree(r); - r = new_intArrayType(1); - } - - gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE); - - if (in != (ArrayType *) DatumGetPointer(entry->key)) - pfree(in); - - PG_RETURN_POINTER(retval); -} - -Datum -g_intbig_decompress(PG_FUNCTION_ARGS) -{ - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); - ArrayType *key; - - key = (ArrayType *) PG_DETOAST_DATUM(entry->key); - - if (key != (ArrayType *) DatumGetPointer(entry->key)) - { - GISTENTRY *retval; - - retval = palloc(sizeof(GISTENTRY)); - - gistentryinit(*retval, PointerGetDatum(key), - entry->rel, entry->page, entry->offset, (key) ? VARSIZE(key) : 0, FALSE); - PG_RETURN_POINTER(retval); - } - if (ARRNELEMS(key) == 1) - { - GISTENTRY *retval; - ArrayType *newkey; - - retval = palloc(sizeof(GISTENTRY)); - newkey = new_intArrayType(SIGLENINT); - MemSet((void *) ARRPTR(newkey), 0xff, SIGLEN); - - gistentryinit(*retval, PointerGetDatum(newkey), - entry->rel, entry->page, entry->offset, VARSIZE(newkey), FALSE); - PG_RETURN_POINTER(retval); - } - PG_RETURN_POINTER(entry); -} - -Datum -g_intbig_picksplit(PG_FUNCTION_ARGS) -{ - PG_RETURN_POINTER(_int_common_picksplit( - (bytea *) PG_GETARG_POINTER(0), - (GIST_SPLITVEC *) PG_GETARG_POINTER(1), - _intbig_union, - _intbig_inter, - rt__intbig_size, - 0.1 - )); -} - -Datum -g_intbig_union(PG_FUNCTION_ARGS) -{ - PG_RETURN_POINTER(_int_common_union( - (bytea *) PG_GETARG_POINTER(0), - (int *) PG_GETARG_POINTER(1), - _intbig_union - )); -} - -Datum -g_intbig_penalty(PG_FUNCTION_ARGS) -{ - PG_RETURN_POINTER(_int_common_penalty( - (GISTENTRY *) PG_GETARG_POINTER(0), - (GISTENTRY *) PG_GETARG_POINTER(1), - (float *) PG_GETARG_POINTER(2), - _intbig_union, rt__intbig_size - )); -} - -Datum -g_intbig_consistent(PG_FUNCTION_ARGS) -{ - GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); - ArrayType *query = (ArrayType *) PG_GETARG_POINTER(1); - StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); - bool retval; - ArrayType *q; - - if (strategy == BooleanSearchStrategy) - PG_RETURN_BOOL(signconsistent((QUERYTYPE *) query, - SIGPTR((ArrayType *) DatumGetPointer(entry->key)), - false)); - - /* XXX what about toasted input? */ - if (ARRISVOID(query)) - return FALSE; - - q = new_intArrayType(SIGLENINT); - gensign(SIGPTR(q), - ARRPTR(query), - ARRNELEMS(query)); - - switch (strategy) - { - case RTOverlapStrategyNumber: - retval = _intbig_overlap((ArrayType *) DatumGetPointer(entry->key), q); - break; - case RTSameStrategyNumber: - if (GIST_LEAF(entry)) - DirectFunctionCall3( - g_intbig_same, - entry->key, - PointerGetDatum(q), - PointerGetDatum(&retval) - ); - else - retval = _intbig_contains((ArrayType *) DatumGetPointer(entry->key), q); - break; - case RTContainsStrategyNumber: - retval = _intbig_contains((ArrayType *) DatumGetPointer(entry->key), q); - break; - case RTContainedByStrategyNumber: - retval = _intbig_overlap((ArrayType *) DatumGetPointer(entry->key), q); - break; - default: - retval = FALSE; - } - pfree(q); - PG_RETURN_BOOL(retval); -} - -/***************************************************************** -** Common GiST Method -*****************************************************************/ - -/* -** The GiST Union method for _intments -** returns the minimal set that encloses all the entries in entryvec -*/ -static ArrayType * -_int_common_union(bytea *entryvec, int *sizep, formarray unionf) -{ - int numranges, - i; - ArrayType *out = (ArrayType *) NULL; - ArrayType *tmp; - -#ifdef GIST_DEBUG - elog(DEBUG4, "_int_common_union in"); -#endif - - numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY); - tmp = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[0].key); - - for (i = 1; i < numranges; i++) - { - out = (*unionf) (tmp, (ArrayType *) - DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key)); - if (i > 1 && tmp) - pfree(tmp); - tmp = out; - } - - out->flags &= ~LEAFKEY; - *sizep = VARSIZE(out); - if (*sizep == 0) - { - pfree(out); -#ifdef GIST_DEBUG - elog(DEBUG4, "_int_common_union out1"); -#endif - return NULL; - } -#ifdef GIST_DEBUG - elog(DEBUG4, "_int_common_union out"); -#endif - return (out); - -} - -/***************************************** - * The GiST Penalty method for _intments * - *****************************************/ - -static float * -_int_common_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result, - formarray unionf, - formfloat sizef) -{ - ArrayType *ud; - float tmp1, - tmp2; - -#ifdef GIST_DEBUG - elog(DEBUG4, "penalty"); -#endif - ud = (*unionf) ((ArrayType *) DatumGetPointer(origentry->key), - (ArrayType *) DatumGetPointer(newentry->key)); - (*sizef) (ud, &tmp1); - (*sizef) ((ArrayType *) DatumGetPointer(origentry->key), &tmp2); - *result = tmp1 - tmp2; - pfree(ud); - -#ifdef GIST_DEBUG - elog(DEBUG4, "--penalty\t%g", *result); -#endif - - return (result); -} - -typedef struct -{ - OffsetNumber pos; - float cost; -} SPLITCOST; - -static int -comparecost(const void *a, const void *b) -{ - if (((SPLITCOST *) a)->cost == ((SPLITCOST *) b)->cost) - return 0; - else - return (((SPLITCOST *) a)->cost > ((SPLITCOST *) b)->cost) ? 1 : -1; -} - -/* -** The GiST PickSplit method for _intments -** We use Guttman's poly time split algorithm -*/ -static GIST_SPLITVEC * -_int_common_picksplit(bytea *entryvec, - GIST_SPLITVEC *v, - formarray unionf, - formarray interf, - formfloat sizef, - float coef) -{ - OffsetNumber i, - j; - ArrayType *datum_alpha, - *datum_beta; - ArrayType *datum_l, - *datum_r; - ArrayType *union_d, - *union_dl, - *union_dr; - ArrayType *inter_d; - bool firsttime; - float size_alpha, - size_beta, - size_union, - size_inter; - float size_waste, - waste; - float size_l, - size_r; - int nbytes; - OffsetNumber seed_1 = 0, - seed_2 = 0; - OffsetNumber *left, - *right; - OffsetNumber maxoff; - SPLITCOST *costvector; - -#ifdef GIST_DEBUG - elog(DEBUG4, "--------picksplit %d", (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY)); -#endif - - maxoff = ((VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY)) - 2; - nbytes = (maxoff + 2) * sizeof(OffsetNumber); - v->spl_left = (OffsetNumber *) palloc(nbytes); - v->spl_right = (OffsetNumber *) palloc(nbytes); - - firsttime = true; - waste = 0.0; - for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i)) - { - datum_alpha = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key); - for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j)) - { - datum_beta = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[j].key); - - /* compute the wasted space by unioning these guys */ - /* size_waste = size_union - size_inter; */ - union_d = (*unionf) (datum_alpha, datum_beta); - (*sizef) (union_d, &size_union); - inter_d = (*interf) (datum_alpha, datum_beta); - (*sizef) (inter_d, &size_inter); - size_waste = size_union - size_inter; - - pfree(union_d); - - if (inter_d != (ArrayType *) NULL) - pfree(inter_d); - - /* - * are these a more promising split that what we've already - * seen? - */ - - if (size_waste > waste || firsttime) - { - waste = size_waste; - seed_1 = i; - seed_2 = j; - firsttime = false; - } - } - } - - left = v->spl_left; - v->spl_nleft = 0; - right = v->spl_right; - v->spl_nright = 0; - if (seed_1 == 0 || seed_2 == 0) - { - seed_1 = 1; - seed_2 = 2; - } - - datum_alpha = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[seed_1].key); - datum_l = copy_intArrayType(datum_alpha); - (*sizef) (datum_l, &size_l); - datum_beta = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[seed_2].key); - datum_r = copy_intArrayType(datum_beta); - (*sizef) (datum_r, &size_r); - - maxoff = OffsetNumberNext(maxoff); - - /* - * sort entries - */ - costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff); - for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) - { - costvector[i - 1].pos = i; - datum_alpha = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key); - union_d = (*unionf) (datum_l, datum_alpha); - (*sizef) (union_d, &size_alpha); - pfree(union_d); - union_d = (*unionf) (datum_r, datum_alpha); - (*sizef) (union_d, &size_beta); - pfree(union_d); - costvector[i - 1].cost = abs((size_alpha - size_l) - (size_beta - size_r)); - } - qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost); - - /* - * Now split up the regions between the two seeds. An important - * property of this split algorithm is that the split vector v has the - * indices of items to be split in order in its left and right - * vectors. We exploit this property by doing a merge in the code - * that actually splits the page. - * - * For efficiency, we also place the new index tuple in this loop. This - * is handled at the very end, when we have placed all the existing - * tuples and i == maxoff + 1. - */ - - - for (j = 0; j < maxoff; j++) - { - i = costvector[j].pos; - - /* - * If we've already decided where to place this item, just put it - * on the right list. Otherwise, we need to figure out which page - * needs the least enlargement in order to store the item. - */ - - if (i == seed_1) - { - *left++ = i; - v->spl_nleft++; - continue; - } - else if (i == seed_2) - { - *right++ = i; - v->spl_nright++; - continue; - } - - /* okay, which page needs least enlargement? */ - datum_alpha = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key); - union_dl = (*unionf) (datum_l, datum_alpha); - union_dr = (*unionf) (datum_r, datum_alpha); - (*sizef) (union_dl, &size_alpha); - (*sizef) (union_dr, &size_beta); - - /* pick which page to add it to */ - if (size_alpha - size_l < size_beta - size_r + WISH_F(v->spl_nleft, v->spl_nright, coef)) - { - if (datum_l) - pfree(datum_l); - if (union_dr) - pfree(union_dr); - datum_l = union_dl; - size_l = size_alpha; - *left++ = i; - v->spl_nleft++; - } - else - { - if (datum_r) - pfree(datum_r); - if (union_dl) - pfree(union_dl); - datum_r = union_dr; - size_r = size_beta; - *right++ = i; - v->spl_nright++; - } - } - pfree(costvector); - *right = *left = FirstOffsetNumber; - - datum_l->flags &= ~LEAFKEY; - datum_r->flags &= ~LEAFKEY; - v->spl_ldatum = PointerGetDatum(datum_l); - v->spl_rdatum = PointerGetDatum(datum_r); - -#ifdef GIST_DEBUG - elog(DEBUG4, "--------ENDpicksplit %d %d", v->spl_nleft, v->spl_nright); -#endif - return v; -} - -/***************************************************************************** - * BoolSearch - *****************************************************************************/ - - -#define END 0 -#define ERR 1 -#define VAL 2 -#define OPR 3 -#define OPEN 4 -#define CLOSE 5 - -/* parser's states */ -#define WAITOPERAND 1 -#define WAITENDOPERAND 2 -#define WAITOPERATOR 3 - -/* - * node of query tree, also used - * for storing polish notation in parser - */ -typedef struct NODE -{ - int4 type; - int4 val; - struct NODE *next; -} NODE; - -typedef struct -{ - char *buf; - int4 state; - int4 count; - /* reverse polish notation in list (for temporary usage) */ - NODE *str; - /* number in str */ - int4 num; -} WORKSTATE; - -/* - * get token from query string - */ -static int4 -gettoken(WORKSTATE * state, int4 *val) -{ - char nnn[16], - *curnnn; - - curnnn = nnn; - while (1) - { - switch (state->state) - { - case WAITOPERAND: - curnnn = nnn; - if ((*(state->buf) >= '0' && *(state->buf) <= '9') || - *(state->buf) == '-') - { - state->state = WAITENDOPERAND; - *curnnn = *(state->buf); - curnnn++; - } - else if (*(state->buf) == '!') - { - (state->buf)++; - *val = (int4) '!'; - return OPR; - } - else if (*(state->buf) == '(') - { - state->count++; - (state->buf)++; - return OPEN; - } - else if (*(state->buf) != ' ') - return ERR; - break; - case WAITENDOPERAND: - if (*(state->buf) >= '0' && *(state->buf) <= '9') - { - *curnnn = *(state->buf); - curnnn++; - } - else - { - *curnnn = '\0'; - *val = (int4) atoi(nnn); - state->state = WAITOPERATOR; - return (state->count && *(state->buf) == '\0') - ? ERR : VAL; - } - break; - case WAITOPERATOR: - if (*(state->buf) == '&' || *(state->buf) == '|') - { - state->state = WAITOPERAND; - *val = (int4) *(state->buf); - (state->buf)++; - return OPR; - } - else if (*(state->buf) == ')') - { - (state->buf)++; - state->count--; - return (state->count < 0) ? ERR : CLOSE; - } - else if (*(state->buf) == '\0') - return (state->count) ? ERR : END; - else if (*(state->buf) != ' ') - return ERR; - break; - default: - return ERR; - break; - } - (state->buf)++; - } - return END; -} - -/* - * push new one in polish notation reverse view - */ -static void -pushquery(WORKSTATE * state, int4 type, int4 val) -{ - NODE *tmp = (NODE *) palloc(sizeof(NODE)); - - tmp->type = type; - tmp->val = val; - tmp->next = state->str; - state->str = tmp; - state->num++; -} - -#define STACKDEPTH 16 - -/* - * make polish notation of query - */ -static int4 -makepol(WORKSTATE * state) -{ - int4 val, - type; - int4 stack[STACKDEPTH]; - int4 lenstack = 0; - - while ((type = gettoken(state, &val)) != END) - { - switch (type) - { - case VAL: - pushquery(state, type, val); - while (lenstack && (stack[lenstack - 1] == (int4) '&' || - stack[lenstack - 1] == (int4) '!')) - { - lenstack--; - pushquery(state, OPR, stack[lenstack]); - } - break; - case OPR: - if (lenstack && val == (int4) '|') - pushquery(state, OPR, val); - else - { - if (lenstack == STACKDEPTH) - elog(ERROR, "Stack too short"); - stack[lenstack] = val; - lenstack++; - } - break; - case OPEN: - if (makepol(state) == ERR) - return ERR; - if (lenstack && (stack[lenstack - 1] == (int4) '&' || - stack[lenstack - 1] == (int4) '!')) - { - lenstack--; - pushquery(state, OPR, stack[lenstack]); - } - break; - case CLOSE: - while (lenstack) - { - lenstack--; - pushquery(state, OPR, stack[lenstack]); - }; - return END; - break; - case ERR: - default: - elog(ERROR, "Syntax error"); - return ERR; - - } - } - - while (lenstack) - { - lenstack--; - pushquery(state, OPR, stack[lenstack]); - }; - return END; -} - -typedef struct -{ - int4 *arrb; - int4 *arre; -} CHKVAL; - -/* - * is there value 'val' in array or not ? - */ -static bool -checkcondition_arr(void *checkval, int4 val) -{ - int4 *StopLow = ((CHKVAL *) checkval)->arrb; - int4 *StopHigh = ((CHKVAL *) checkval)->arre; - int4 *StopMiddle; - - /* Loop invariant: StopLow <= val < StopHigh */ - - while (StopLow < StopHigh) - { - StopMiddle = StopLow + (StopHigh - StopLow) / 2; - if (*StopMiddle == val) - return (true); - else if (*StopMiddle < val) - StopLow = StopMiddle + 1; - else - StopHigh = StopMiddle; - } - return false; -} - -static bool -checkcondition_bit(void *checkval, int4 val) -{ - return GETBIT(checkval, HASHVAL(val)); -} - -/* - * check for boolean condition - */ -static bool -execute(ITEM * curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, int4 val)) -{ - - if (curitem->type == VAL) - return (*chkcond) (checkval, curitem->val); - else if (curitem->val == (int4) '!') - { - return (calcnot) ? - ((execute(curitem - 1, checkval, calcnot, chkcond)) ? false : true) - : true; - } - else if (curitem->val == (int4) '&') - { - if (execute(curitem + curitem->left, checkval, calcnot, chkcond)) - return execute(curitem - 1, checkval, calcnot, chkcond); - else - return false; - } - else - { /* |-operator */ - if (execute(curitem + curitem->left, checkval, calcnot, chkcond)) - return true; - else - return execute(curitem - 1, checkval, calcnot, chkcond); - } - return false; -} - -/* - * signconsistent & execconsistent called by *_consistent - */ -static bool -signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot) -{ - return execute( - GETQUERY(query) + query->size - 1, - (void *) sign, calcnot, - checkcondition_bit - ); -} - -static bool -execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot) -{ - CHKVAL chkval; - - chkval.arrb = ARRPTR(array); - chkval.arre = chkval.arrb + ARRNELEMS(array); - return execute( - GETQUERY(query) + query->size - 1, - (void *) &chkval, calcnot, - checkcondition_arr - ); -} - -/* - * boolean operations - */ -Datum -rboolop(PG_FUNCTION_ARGS) -{ - return DirectFunctionCall2( - boolop, - PG_GETARG_DATUM(1), - PG_GETARG_DATUM(0) - ); -} - -Datum -boolop(PG_FUNCTION_ARGS) -{ - ArrayType *val = (ArrayType *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0)); - QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(1)); - CHKVAL chkval; - bool result; - - if (ARRISVOID(val)) - { - pfree(val); - PG_FREE_IF_COPY(query, 1); - PG_RETURN_BOOL(false); - } - - PREPAREARR(val); - chkval.arrb = ARRPTR(val); - chkval.arre = chkval.arrb + ARRNELEMS(val); - result = execute( - GETQUERY(query) + query->size - 1, - &chkval, true, - checkcondition_arr - ); - pfree(val); - - PG_FREE_IF_COPY(query, 1); - PG_RETURN_BOOL(result); -} - -static void -findoprnd(ITEM * ptr, int4 *pos) -{ -#ifdef BS_DEBUG - elog(DEBUG4, (ptr[*pos].type == OPR) ? - "%d %c" : "%d %d ", *pos, ptr[*pos].val); -#endif - if (ptr[*pos].type == VAL) - { - ptr[*pos].left = 0; - (*pos)--; - } - else if (ptr[*pos].val == (int4) '!') - { - ptr[*pos].left = -1; - (*pos)--; - findoprnd(ptr, pos); - } - else - { - ITEM *curitem = &ptr[*pos]; - int4 tmp = *pos; - - (*pos)--; - findoprnd(ptr, pos); - curitem->left = *pos - tmp; - findoprnd(ptr, pos); - } -} - - -/* - * input - */ -Datum -bqarr_in(PG_FUNCTION_ARGS) -{ - char *buf = (char *) PG_GETARG_POINTER(0); - WORKSTATE state; - int4 i; - QUERYTYPE *query; - int4 commonlen; - ITEM *ptr; - NODE *tmp; - int4 pos = 0; - -#ifdef BS_DEBUG - StringInfoData pbuf; -#endif - - state.buf = buf; - state.state = WAITOPERAND; - state.count = 0; - state.num = 0; - state.str = NULL; - - /* make polish notation (postfix, but in reverse order) */ - makepol(&state); - if (!state.num) - elog(ERROR, "Empty query"); - - commonlen = COMPUTESIZE(state.num); - query = (QUERYTYPE *) palloc(commonlen); - query->len = commonlen; - query->size = state.num; - ptr = GETQUERY(query); - - for (i = state.num - 1; i >= 0; i--) - { - ptr[i].type = state.str->type; - ptr[i].val = state.str->val; - tmp = state.str->next; - pfree(state.str); - state.str = tmp; - } - - pos = query->size - 1; - findoprnd(ptr, &pos); -#ifdef BS_DEBUG - initStringInfo(&pbuf); - for (i = 0; i < query->size; i++) - { - if (ptr[i].type == OPR) - appendStringInfo(&pbuf, "%c(%d) ", ptr[i].val, ptr[i].left); - else - appendStringInfo(&pbuf, "%d ", ptr[i].val); - } - elog(DEBUG4, "POR: %s", pbuf.data); - pfree(pbuf.data); -#endif - - PG_RETURN_POINTER(query); -} - - -/* - * out function - */ -typedef struct -{ - ITEM *curpol; - char *buf; - char *cur; - int4 buflen; -} INFIX; - -#define RESIZEBUF(inf,addsize) while( ( inf->cur - inf->buf ) + addsize + 1 >= inf->buflen ) { \ - int4 len = inf->cur - inf->buf; \ - inf->buflen *= 2; \ - inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \ - inf->cur = inf->buf + len; \ -} - -static void -infix(INFIX * in, bool first) -{ - if (in->curpol->type == VAL) - { - RESIZEBUF(in, 11); - sprintf(in->cur, "%d", in->curpol->val); - in->cur = strchr(in->cur, '\0'); - in->curpol--; - } - else if (in->curpol->val == (int4) '!') - { - bool isopr = false; - - RESIZEBUF(in, 1); - *(in->cur) = '!'; - in->cur++; - *(in->cur) = '\0'; - in->curpol--; - if (in->curpol->type == OPR) - { - isopr = true; - RESIZEBUF(in, 2); - sprintf(in->cur, "( "); - in->cur = strchr(in->cur, '\0'); - } - infix(in, isopr); - if (isopr) - { - RESIZEBUF(in, 2); - sprintf(in->cur, " )"); - in->cur = strchr(in->cur, '\0'); - } - } - else - { - int4 op = in->curpol->val; - INFIX nrm; - - in->curpol--; - if (op == (int4) '|' && !first) - { - RESIZEBUF(in, 2); - sprintf(in->cur, "( "); - in->cur = strchr(in->cur, '\0'); - } - - nrm.curpol = in->curpol; - nrm.buflen = 16; - nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen); - - /* get right operand */ - infix(&nrm, false); - - /* get & print left operand */ - in->curpol = nrm.curpol; - infix(in, false); - - /* print operator & right operand */ - RESIZEBUF(in, 3 + (nrm.cur - nrm.buf)); - sprintf(in->cur, " %c %s", op, nrm.buf); - in->cur = strchr(in->cur, '\0'); - pfree(nrm.buf); - - if (op == (int4) '|' && !first) - { - RESIZEBUF(in, 2); - sprintf(in->cur, " )"); - in->cur = strchr(in->cur, '\0'); - } - } -} - - -Datum -bqarr_out(PG_FUNCTION_ARGS) -{ - QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0)); - INFIX nrm; - - if (query->size == 0) - elog(ERROR, "Empty"); - nrm.curpol = GETQUERY(query) + query->size - 1; - nrm.buflen = 32; - nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen); - *(nrm.cur) = '\0'; - infix(&nrm, true); - - PG_FREE_IF_COPY(query, 0); - PG_RETURN_POINTER(nrm.buf); -} - -static int4 -countdroptree(ITEM * q, int4 pos) -{ - if (q[pos].type == VAL) - return 1; - else if (q[pos].val == (int4) '!') - return 1 + countdroptree(q, pos - 1); - else - return 1 + countdroptree(q, pos - 1) + countdroptree(q, pos + q[pos].left); -} - -/* - * common algorithm: - * result of all '!' will be = 'true', so - * we can modify query tree for clearing - */ -static int4 -shorterquery(ITEM * q, int4 len) -{ - int4 index, - posnot, - poscor; - bool notisleft = false; - int4 drop, - i; - - /* out all '!' */ - do - { - index = 0; - drop = 0; - /* find ! */ - for (posnot = 0; posnot < len; posnot++) - if (q[posnot].type == OPR && q[posnot].val == (int4) '!') - { - index = 1; - break; - } - - if (posnot == len) - return len; - - /* last operator is ! */ - if (posnot == len - 1) - return 0; - - /* find operator for this operand */ - for (poscor = posnot + 1; poscor < len; poscor++) - { - if (q[poscor].type == OPR) - { - if (poscor == posnot + 1) - { - notisleft = false; - break; - } - else if (q[poscor].left + poscor == posnot) - { - notisleft = true; - break; - } - } - } - if (q[poscor].val == (int4) '!') - { - drop = countdroptree(q, poscor); - q[poscor - 1].type = VAL; - for (i = poscor + 1; i < len; i++) - if (q[i].type == OPR && q[i].left + i <= poscor) - q[i].left += drop - 2; - memcpy((void *) &q[poscor - drop + 1], - (void *) &q[poscor - 1], - sizeof(ITEM) * (len - (poscor - 1))); - len -= drop - 2; - } - else if (q[poscor].val == (int4) '|') - { - drop = countdroptree(q, poscor); - q[poscor - 1].type = VAL; - q[poscor].val = (int4) '!'; - q[poscor].left = -1; - for (i = poscor + 1; i < len; i++) - if (q[i].type == OPR && q[i].left + i < poscor) - q[i].left += drop - 2; - memcpy((void *) &q[poscor - drop + 1], - (void *) &q[poscor - 1], - sizeof(ITEM) * (len - (poscor - 1))); - len -= drop - 2; - } - else - { /* &-operator */ - if ( - (notisleft && q[poscor - 1].type == OPR && - q[poscor - 1].val == (int4) '!') || - (!notisleft && q[poscor + q[poscor].left].type == OPR && - q[poscor + q[poscor].left].val == (int4) '!') - ) - { /* drop subtree */ - drop = countdroptree(q, poscor); - q[poscor - 1].type = VAL; - q[poscor].val = (int4) '!'; - q[poscor].left = -1; - for (i = poscor + 1; i < len; i++) - if (q[i].type == OPR && q[i].left + i < poscor) - q[i].left += drop - 2; - memcpy((void *) &q[poscor - drop + 1], - (void *) &q[poscor - 1], - sizeof(ITEM) * (len - (poscor - 1))); - len -= drop - 2; - } - else - { /* drop only operator */ - int4 subtreepos = (notisleft) ? - poscor - 1 : poscor + q[poscor].left; - int4 subtreelen = countdroptree(q, subtreepos); - - drop = countdroptree(q, poscor); - for (i = poscor + 1; i < len; i++) - if (q[i].type == OPR && q[i].left + i < poscor) - q[i].left += drop - subtreelen; - memcpy((void *) &q[subtreepos + 1], - (void *) &q[poscor + 1], - sizeof(ITEM) * (len - (poscor - 1))); - memcpy((void *) &q[poscor - drop + 1], - (void *) &q[subtreepos - subtreelen + 1], - sizeof(ITEM) * (len - (drop - subtreelen))); - len -= drop - subtreelen; - } - } - } while (index); - return len; -} - - -Datum -querytree(PG_FUNCTION_ARGS) -{ - QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0)); - INFIX nrm; - text *res; - ITEM *q; - int4 len; - - if (query->size == 0) - elog(ERROR, "Empty"); - - q = (ITEM *) palloc(sizeof(ITEM) * query->size); - memcpy((void *) q, GETQUERY(query), sizeof(ITEM) * query->size); - len = shorterquery(q, query->size); - PG_FREE_IF_COPY(query, 0); - - if (len == 0) - { - res = (text *) palloc(1 + VARHDRSZ); - VARATT_SIZEP(res) = 1 + VARHDRSZ; - *((char *) VARDATA(res)) = 'T'; - } - else - { - nrm.curpol = q + len - 1; - nrm.buflen = 32; - nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen); - *(nrm.cur) = '\0'; - infix(&nrm, true); - - res = (text *) palloc(nrm.cur - nrm.buf + VARHDRSZ); - VARATT_SIZEP(res) = nrm.cur - nrm.buf + VARHDRSZ; - strncpy(VARDATA(res), nrm.buf, nrm.cur - nrm.buf); - } - pfree(q); - - PG_RETURN_POINTER(res); -} - -/* -** Additional array functions -*/ -static int32 intarray_match_first(ArrayType *a, int32 elem); -static ArrayType *intarray_add_elem(ArrayType *a, int32 elem); -static ArrayType *intarray_concat_arrays(ArrayType *a, ArrayType *b); -static ArrayType *int_to_intset(int32 elem); - -PG_FUNCTION_INFO_V1(intset); -PG_FUNCTION_INFO_V1(icount); -PG_FUNCTION_INFO_V1(sort); -PG_FUNCTION_INFO_V1(sort_asc); -PG_FUNCTION_INFO_V1(sort_desc); -PG_FUNCTION_INFO_V1(uniq); -PG_FUNCTION_INFO_V1(idx); -PG_FUNCTION_INFO_V1(subarray); -PG_FUNCTION_INFO_V1(intarray_push_elem); -PG_FUNCTION_INFO_V1(intarray_push_array); -PG_FUNCTION_INFO_V1(intarray_del_elem); -PG_FUNCTION_INFO_V1(intset_union_elem); -PG_FUNCTION_INFO_V1(intset_subtract); -Datum intset(PG_FUNCTION_ARGS); -Datum icount(PG_FUNCTION_ARGS); -Datum sort(PG_FUNCTION_ARGS); -Datum sort_asc(PG_FUNCTION_ARGS); -Datum sort_desc(PG_FUNCTION_ARGS); -Datum uniq(PG_FUNCTION_ARGS); -Datum idx(PG_FUNCTION_ARGS); -Datum subarray(PG_FUNCTION_ARGS); -Datum intarray_push_elem(PG_FUNCTION_ARGS); -Datum intarray_push_array(PG_FUNCTION_ARGS); -Datum intarray_del_elem(PG_FUNCTION_ARGS); -Datum intset_union_elem(PG_FUNCTION_ARGS); -Datum intset_subtract(PG_FUNCTION_ARGS); - -static int32 -intarray_match_first(ArrayType *a, int32 elem) -{ - int32 *aa, - c, - i; - - c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); - aa = ARRPTR(a); - for (i = 0; i < c; i++) - if (aa[i] == elem) - return (i + 1); - return 0; -} - -static ArrayType * -intarray_add_elem(ArrayType *a, int32 elem) -{ - ArrayType *result; - int32 *r; - int32 c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); - - result = new_intArrayType(c + 1); - r = ARRPTR(result); - if (c > 0) - memcpy(r, ARRPTR(a), c * sizeof(int32)); - r[c] = elem; - return result; -} - -static ArrayType * -intarray_concat_arrays(ArrayType *a, ArrayType *b) -{ - ArrayType *result; - int32 ac = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); - int32 bc = (ARRISVOID(b)) ? 0 : ARRNELEMS(b); - - result = new_intArrayType(ac + bc); - if (ac) - memcpy(ARRPTR(result), ARRPTR(a), ac * sizeof(int32)); - if (bc) - memcpy(ARRPTR(result) + ac, ARRPTR(b), bc * sizeof(int32)); - return result; -} - -static ArrayType * -int_to_intset(int32 n) -{ - ArrayType *result; - int32 *aa; - - result = new_intArrayType(1); - aa = ARRPTR(result); - aa[0] = n; - return result; -} - -static int -compASC(const void *a, const void *b) -{ - if (*(int4 *) a == *(int4 *) b) - return 0; - return (*(int4 *) a > *(int4 *) b) ? 1 : -1; -} - -static int -compDESC(const void *a, const void *b) -{ - if (*(int4 *) a == *(int4 *) b) - return 0; - return (*(int4 *) a < *(int4 *) b) ? 1 : -1; -} - -#define QSORT(a, direction) \ -if (ARRNELEMS(a) > 1) \ - qsort((void*)ARRPTR(a), ARRNELEMS(a),sizeof(int4), \ - (direction) ? compASC : compDESC ) - - -Datum -intset(PG_FUNCTION_ARGS) -{ - PG_RETURN_POINTER(int_to_intset(PG_GETARG_INT32(0))); -} - -Datum -icount(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); - int32 count = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); - - PG_FREE_IF_COPY(a, 0); - PG_RETURN_INT32(count); -} - -Datum -sort(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); - text *dirstr = (fcinfo->nargs == 2) ? PG_GETARG_TEXT_P(1) : NULL; - int32 dc = (dirstr) ? VARSIZE(dirstr) - VARHDRSZ : 0; - char *d = (dirstr) ? VARDATA(dirstr) : NULL; - int dir = -1; - - if (ARRISVOID(a) || ARRNELEMS(a) < 2) - PG_RETURN_POINTER(a); - - if (dirstr == NULL || (dc == 3 - && (d[0] == 'A' || d[0] == 'a') - && (d[1] == 'S' || d[1] == 's') - && (d[2] == 'C' || d[2] == 'c'))) - dir = 1; - else if (dc == 4 - && (d[0] == 'D' || d[0] == 'd') - && (d[1] == 'E' || d[1] == 'e') - && (d[2] == 'S' || d[2] == 's') - && (d[3] == 'C' || d[3] == 'c')) - dir = 0; - if (dir == -1) - elog(ERROR, "Invalid second parameter in function sort. It must be 'ASC' or 'DESC'."); - QSORT(a, dir); - PG_RETURN_POINTER(a); -} - -Datum -sort_asc(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); - - if (ARRISVOID(a)) - PG_RETURN_POINTER(a); - QSORT(a, 1); - PG_RETURN_POINTER(a); -} - -Datum -sort_desc(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); - - if (ARRISVOID(a)) - PG_RETURN_POINTER(a); - QSORT(a, 0); - PG_RETURN_POINTER(a); -} - -Datum -uniq(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); - - if (ARRISVOID(a) || ARRNELEMS(a) < 2) - PG_RETURN_POINTER(a); - UNIX_UNIQ(a); - PG_RETURN_POINTER(a); -} - -Datum -idx(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); - int32 result = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); - - if (result) - result = intarray_match_first(a, PG_GETARG_INT32(1)); - PG_FREE_IF_COPY(a, 0); - PG_RETURN_INT32(result); -} - -Datum -subarray(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); - ArrayType *result; - int32 start = (PG_GETARG_INT32(1) > 0) ? PG_GETARG_INT32(1) - 1 : PG_GETARG_INT32(1); - int32 len = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0; - int32 end = 0; - int32 c; - - if (ARRISVOID(a)) - { - PG_FREE_IF_COPY(a, 0); - PG_RETURN_POINTER(new_intArrayType(0)); - } - - c = ARRNELEMS(a); - - if (start < 0) - start = c + start; - - if (len < 0) - end = c + len; - else if (len == 0) - end = c; - else - end = start + len; - - if (end > c) - end = c; - - if (start < 0) - start = 0; - - if (start >= end || end <= 0) - { - PG_FREE_IF_COPY(a, 0); - PG_RETURN_POINTER(new_intArrayType(0)); - } - - - result = new_intArrayType(end - start); - if (end - start > 0) - memcpy(ARRPTR(result), ARRPTR(a) + start, (end - start) * sizeof(int32)); - PG_FREE_IF_COPY(a, 0); - PG_RETURN_POINTER(result); -} - -Datum -intarray_push_elem(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); - ArrayType *result; - - result = intarray_add_elem(a, PG_GETARG_INT32(1)); - PG_FREE_IF_COPY(a, 0); - PG_RETURN_POINTER(result); -} - -Datum -intarray_push_array(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); - ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1))); - ArrayType *result; - - result = intarray_concat_arrays(a, b); - PG_FREE_IF_COPY(a, 0); - PG_FREE_IF_COPY(b, 1); - PG_RETURN_POINTER(result); -} - -Datum -intarray_del_elem(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); - int32 c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); - int32 *aa = ARRPTR(a); - int32 n = 0, - i; - int32 elem = PG_GETARG_INT32(1); - - for (i = 0; i < c; i++) - if (aa[i] != elem) - { - if (i > n) - aa[n++] = aa[i]; - else - n++; - } - if (c > 0) - a = resize_intArrayType(a, n); - PG_RETURN_POINTER(a); -} - -Datum -intset_union_elem(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); - ArrayType *result; - - result = intarray_add_elem(a, PG_GETARG_INT32(1)); - PG_FREE_IF_COPY(a, 0); - QSORT(result, 1); - UNIX_UNIQ(result); - PG_RETURN_POINTER(result); -} - -Datum -intset_subtract(PG_FUNCTION_ARGS) -{ - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); - ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); - ArrayType *result; - int32 ca = ARRISVOID(a); - int32 cb = ARRISVOID(b); - int32 *aa, - *bb, - *r; - int32 n = 0, - i = 0, - k = 0; - - QSORT(a, 1); - UNIX_UNIQ(a); - ca = ARRNELEMS(a); - QSORT(b, 1); - UNIX_UNIQ(b); - cb = ARRNELEMS(b); - result = new_intArrayType(ca); - aa = ARRPTR(a); - bb = ARRPTR(b); - r = ARRPTR(result); - while (i < ca) - { - if (k == cb || aa[i] < bb[k]) - r[n++] = aa[i++]; - else if (aa[i] == bb[k]) - { - i++; - k++; - } - else - k++; - } - result = resize_intArrayType(result, n); - pfree(a); - pfree(b); - PG_RETURN_POINTER(result); -} diff --git a/contrib/intarray/_int.sql.in b/contrib/intarray/_int.sql.in index 21786e51e7..2c30bac99e 100644 --- a/contrib/intarray/_int.sql.in +++ b/contrib/intarray/_int.sql.in @@ -360,7 +360,24 @@ DEFAULT FOR TYPE _int4 USING gist AS -- intbig --------------------------------------------- -- define the GiST support methods -CREATE FUNCTION g_intbig_consistent(internal,_int4,int4) + +CREATE FUNCTION _intbig_in(cstring) +RETURNS intbig_gkey +AS 'MODULE_PATHNAME' +LANGUAGE 'C' with (isstrict); + +CREATE FUNCTION _intbig_out(intbig_gkey) +RETURNS cstring +AS 'MODULE_PATHNAME' +LANGUAGE 'C' with (isstrict); + +CREATE TYPE intbig_gkey ( + INTERNALLENGTH = -1, + INPUT = _intbig_in, + OUTPUT = _intbig_out +); + +CREATE FUNCTION g_intbig_consistent(internal,internal,int4) RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE 'C'; @@ -390,7 +407,7 @@ RETURNS _int4 AS 'MODULE_PATHNAME' LANGUAGE 'C'; -CREATE FUNCTION g_intbig_same(_int4, _int4, internal) +CREATE FUNCTION g_intbig_same(internal, internal, internal) RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE 'C'; @@ -405,10 +422,11 @@ AS OPERATOR 7 @ RECHECK, OPERATOR 8 ~ RECHECK, OPERATOR 20 @@ (_int4, query_int) RECHECK, - FUNCTION 1 g_intbig_consistent (internal, _int4, int4), + FUNCTION 1 g_intbig_consistent (internal, internal, int4), FUNCTION 2 g_intbig_union (bytea, internal), FUNCTION 3 g_intbig_compress (internal), FUNCTION 4 g_intbig_decompress (internal), FUNCTION 5 g_intbig_penalty (internal, internal, internal), FUNCTION 6 g_intbig_picksplit (internal, internal), - FUNCTION 7 g_intbig_same (_int4, _int4, internal); + FUNCTION 7 g_intbig_same (internal, internal, internal), + STORAGE intbig_gkey; diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out index b602df33d8..142697f225 100644 --- a/contrib/intarray/expected/_int.out +++ b/contrib/intarray/expected/_int.out @@ -5,6 +5,8 @@ \set ECHO none psql:_int.sql:13: NOTICE: ProcedureCreate: type query_int is not yet defined psql:_int.sql:18: NOTICE: Argument type "query_int" is only a shell +psql:_int.sql:369: NOTICE: ProcedureCreate: type intbig_gkey is not yet defined +psql:_int.sql:374: NOTICE: Argument type "intbig_gkey" is only a shell SELECT intset(1234); intset -------- diff --git a/contrib/ltree/_ltree_gist.c b/contrib/ltree/_ltree_gist.c index 1791f5bd8d..ec20067230 100644 --- a/contrib/ltree/_ltree_gist.c +++ b/contrib/ltree/_ltree_gist.c @@ -211,35 +211,39 @@ sizebitvec(BITVECP sign) return size; } +static int +hemdistsign(BITVECP a, BITVECP b) { + int i,dist=0; + + ALOOPBIT( + if ( GETBIT(a,i) != GETBIT(b,i) ) + dist++; + ); + return dist; +} + +static int +hemdist(ltree_gist *a, ltree_gist *b) { + if ( LTG_ISALLTRUE(a) ) { + if (LTG_ISALLTRUE(b)) + return 0; + else + return ASIGLENBIT-sizebitvec(LTG_SIGN(b)); + } else if (LTG_ISALLTRUE(b)) + return ASIGLENBIT-sizebitvec(LTG_SIGN(a)); + + return hemdistsign( LTG_SIGN(a), LTG_SIGN(b) ); +} + + Datum _ltree_penalty(PG_FUNCTION_ARGS) { ltree_gist *origval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key); ltree_gist *newval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key); float *penalty = (float *) PG_GETARG_POINTER(2); - BITVECP orig = LTG_SIGN(origval); - if (LTG_ISALLTRUE(origval)) - { - *penalty = 0.1; - PG_RETURN_POINTER(penalty); - } - - if (LTG_ISALLTRUE(newval)) - *penalty = (float) (ASIGLENBIT - sizebitvec(orig)); - else - { - unsigned char valtmp; - BITVECP nval = LTG_SIGN(newval); - int4 i, - unionsize = 0; - - ALOOPBYTE( - valtmp = nval[i] | orig[i]; - unionsize += SUMBIT(valtmp) - SUMBIT(orig[i]); - ); - *penalty = (float) unionsize; - } + *penalty=hemdist(origval,newval); PG_RETURN_POINTER(penalty); } @@ -264,28 +268,19 @@ _ltree_picksplit(PG_FUNCTION_ARGS) j; ltree_gist *datum_l, *datum_r; - ABITVEC union_l, + BITVECP union_l, union_r; - bool firsttime = true; - int4 size_alpha, - size_beta, - sizeu, - sizei; + int4 size_alpha, size_beta; int4 size_waste, - waste = 0.0; - int4 size_l, - size_r; + waste = -1; int4 nbytes; OffsetNumber seed_1 = 0, seed_2 = 0; OffsetNumber *left, *right; OffsetNumber maxoff; - BITVECP ptra, - ptrb, - ptrc; + BITVECP ptr; int i; - unsigned char valtmp; SPLITCOST *costvector; ltree_gist *_k, *_j; @@ -295,57 +290,14 @@ _ltree_picksplit(PG_FUNCTION_ARGS) v->spl_left = (OffsetNumber *) palloc(nbytes); v->spl_right = (OffsetNumber *) palloc(nbytes); - for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k)) - { + for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k)) { _k = GETENTRY(entryvec, k); - for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) - { - _j = GETENTRY(entryvec, j); - if (LTG_ISALLTRUE(_k) || LTG_ISALLTRUE(_j)) - { - sizeu = ASIGLENBIT; - if (LTG_ISALLTRUE(_k) && LTG_ISALLTRUE(_j)) - sizei = ASIGLENBIT; - else - sizei = (LTG_ISALLTRUE(_k)) ? - sizebitvec(LTG_SIGN(_j)) : sizebitvec(LTG_SIGN(_k)); - } - else - { - sizeu = sizei = 0; - ptra = LTG_SIGN(_j); - ptrb = LTG_SIGN(_k); - /* critical section for bench !!! */ - -#define COUNT(pos) do { \ - if ( GETBITBYTE(*(char*)ptra,pos) ) { \ - sizeu++; \ - if ( GETBITBYTE(*(char*)ptrb, pos) ) \ - sizei++; \ - } else if ( GETBITBYTE(*(char*)ptrb, pos) ) \ - sizeu++; \ -} while(0) - - ALOOPBYTE( - COUNT(0); - COUNT(1); - COUNT(2); - COUNT(3); - COUNT(4); - COUNT(5); - COUNT(6); - COUNT(7); - ptra = (BITVECP) (((char *) ptra) + 1); - ptrb = (BITVECP) (((char *) ptrb) + 1); - ); - } - size_waste = sizeu - sizei; - if (size_waste > waste || firsttime) - { + for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) { + size_waste=hemdist(_k, GETENTRY(entryvec, j)); + if (size_waste > waste ) { waste = size_waste; seed_1 = k; seed_2 = j; - firsttime = false; } } } @@ -367,7 +319,6 @@ _ltree_picksplit(PG_FUNCTION_ARGS) datum_l = (ltree_gist *) palloc(LTG_HDRSIZE); datum_l->len = LTG_HDRSIZE; datum_l->flag = LTG_ALLTRUE; - size_l = ASIGLENBIT; } else { @@ -375,14 +326,12 @@ _ltree_picksplit(PG_FUNCTION_ARGS) datum_l->len = LTG_HDRSIZE + ASIGLEN; datum_l->flag = 0; memcpy((void *) LTG_SIGN(datum_l), (void *) LTG_SIGN(GETENTRY(entryvec, seed_1)), sizeof(ABITVEC)); - size_l = sizebitvec(LTG_SIGN(datum_l)); } if (LTG_ISALLTRUE(GETENTRY(entryvec, seed_2))) { datum_r = (ltree_gist *) palloc(LTG_HDRSIZE); datum_r->len = LTG_HDRSIZE; datum_r->flag = LTG_ALLTRUE; - size_r = ASIGLENBIT; } else { @@ -390,7 +339,6 @@ _ltree_picksplit(PG_FUNCTION_ARGS) datum_r->len = LTG_HDRSIZE + ASIGLEN; datum_r->flag = 0; memcpy((void *) LTG_SIGN(datum_r), (void *) LTG_SIGN(GETENTRY(entryvec, seed_2)), sizeof(ABITVEC)); - size_r = sizebitvec(LTG_SIGN(datum_r)); } maxoff = OffsetNumberNext(maxoff); @@ -400,55 +348,18 @@ _ltree_picksplit(PG_FUNCTION_ARGS) { costvector[j - 1].pos = j; _j = GETENTRY(entryvec, j); - if (LTG_ISALLTRUE(_j)) - { - size_alpha = ASIGLENBIT - size_l; - size_beta = ASIGLENBIT - size_r; - } - else - { - ptra = LTG_SIGN(datum_l); - ptrb = LTG_SIGN(datum_r); - ptrc = LTG_SIGN(_j); - size_beta = size_alpha = 0; - if (LTG_ISALLTRUE(datum_l)) - { - if (!LTG_ISALLTRUE(datum_r)) - { - ALOOPBIT( - if (GETBIT(ptrc, i) && !GETBIT(ptrb, i)) - size_beta++; - ); - } - } - else if (LTG_ISALLTRUE(datum_r)) - { - if (!LTG_ISALLTRUE(datum_l)) - { - ALOOPBIT( - if (GETBIT(ptrc, i) && !GETBIT(ptra, i)) - size_alpha++; - ); - } - } - else - { - ALOOPBIT( - if (GETBIT(ptrc, i) && !GETBIT(ptra, i)) - size_alpha++; - if (GETBIT(ptrc, i) && !GETBIT(ptrb, i)) - size_beta++; - ); - } - } + size_alpha = hemdist(datum_l,_j); + size_beta = hemdist(datum_r,_j); costvector[j - 1].cost = abs(size_alpha - size_beta); } qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost); + union_l=LTG_SIGN(datum_l); + union_r=LTG_SIGN(datum_r); + for (k = 0; k < maxoff; k++) { j = costvector[k].pos; - _j = GETENTRY(entryvec, j); if (j == seed_1) { *left++ = j; @@ -461,62 +372,35 @@ _ltree_picksplit(PG_FUNCTION_ARGS) v->spl_nright++; continue; } + _j = GETENTRY(entryvec, j); + size_alpha = hemdist(datum_l,_j); + size_beta = hemdist(datum_r,_j); - if (LTG_ISALLTRUE(datum_l) || LTG_ISALLTRUE(_j)) - size_alpha = ASIGLENBIT; - else + if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.00001)) { - ptra = LTG_SIGN(_j); - ptrb = LTG_SIGN(datum_l); - size_alpha = 0; - ALOOPBYTE( - valtmp = union_l[i] = ptra[i] | ptrb[i]; - size_alpha += SUMBIT(valtmp); - ); - } - - if (LTG_ISALLTRUE(datum_r) || LTG_ISALLTRUE(_j)) - size_beta = ASIGLENBIT; - else - { - ptra = LTG_SIGN(_j); - ptrb = LTG_SIGN(datum_r); - size_beta = 0; - ALOOPBYTE( - valtmp = union_r[i] = ptra[i] | ptrb[i]; - size_beta += SUMBIT(valtmp); - ); - } - - if (size_alpha - size_l < size_beta - size_r + WISH_F(v->spl_nleft, v->spl_nright, 0.00001)) - { - if (!LTG_ISALLTRUE(datum_l)) - { - if (size_alpha == ASIGLENBIT) - { - if (size_alpha != size_l) - MemSet((void *) LTG_SIGN(datum_l), 0xff, sizeof(ABITVEC)); - } - else - memcpy((void *) LTG_SIGN(datum_l), (void *) union_l, sizeof(ABITVEC)); + if (LTG_ISALLTRUE(datum_l) || LTG_ISALLTRUE(_j) ) { + if (!LTG_ISALLTRUE(datum_l)) + MemSet((void *) union_l, 0xff, sizeof(ABITVEC)); + } else { + ptr=LTG_SIGN(_j); + ALOOPBYTE( + union_l[i] |= ptr[i]; + ); } - size_l = size_alpha; *left++ = j; v->spl_nleft++; } else { - if (!LTG_ISALLTRUE(datum_r)) - { - if (size_beta == ASIGLENBIT) - { - if (size_beta != size_r) - MemSet((void *) LTG_SIGN(datum_r), 0xff, sizeof(ABITVEC)); - } - else - memcpy((void *) LTG_SIGN(datum_r), (void *) union_r, sizeof(ABITVEC)); + if (LTG_ISALLTRUE(datum_r) || LTG_ISALLTRUE(_j) ) { + if (!LTG_ISALLTRUE(datum_r)) + MemSet((void *) union_r, 0xff, sizeof(ABITVEC)); + } else { + ptr=LTG_SIGN(_j); + ALOOPBYTE( + union_r[i] |= ptr[i]; + ); } - size_r = size_beta; *right++ = j; v->spl_nright++; } diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h index 1bc36e722d..39bc0cd311 100644 --- a/contrib/ltree/ltree.h +++ b/contrib/ltree/ltree.h @@ -239,7 +239,7 @@ typedef struct /* GiST support for ltree[] */ -#define ASIGLENINT (2*SIGLENINT) +#define ASIGLENINT (7) #define ASIGLEN (sizeof(int4)*ASIGLENINT) #define ASIGLENBIT (ASIGLEN*BITBYTE) typedef unsigned char ABITVEC[ASIGLEN];