summaryrefslogtreecommitdiff
path: root/contrib/intarray/_int.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/intarray/_int.c')
-rw-r--r--contrib/intarray/_int.c2219
1 files changed, 0 insertions, 2219 deletions
diff --git a/contrib/intarray/_int.c b/contrib/intarray/_int.c
deleted file mode 100644
index d956543af5f..00000000000
--- a/contrib/intarray/_int.c
+++ /dev/null
@@ -1,2219 +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 <float.h>
-
-#include "access/gist.h"
-#include "access/itup.h"
-#include "access/rtree.h"
-#include "utils/elog.h"
-#include "utils/palloc.h"
-#include "utils/array.h"
-#include "utils/builtins.h"
-#include "storage/bufpage.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<SIGLEN;i++) {\
- a;\
- }
-
-#define LOOPBIT(a) \
- for(i=0;i<SIGLENBIT;i++) {\
- a;\
- }
-
-/* beware of multiple evaluation of arguments to these macros! */
-#define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITBYTE ) ) )
-#define GETBITBYTE(x,i) ( (*((char*)(x)) >> (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)
-{
- char bbb[16384];
- char *cur;
- int l;
- int *d;
-
- d = ARRPTR(a);
- *bbb = '\0';
- cur = bbb;
- for (l = 0; l < min(num, ARRNELEMS(a)); l++)
- {
- sprintf(cur, "%d ", d[l]);
- cur = strchr(cur, '\0');
- }
- elog(DEBUG3, "\t\t%s", bbb);
-}
-static void
-printbitvec(BITVEC bv)
-{
- int i;
- char str[SIGLENBIT + 1];
-
- str[SIGLENBIT] = '\0';
- LOOPBIT(str[i] = (GETBIT(bv, i)) ? '1' : '0');
-
- elog(DEBUG3, "BV: %s", str);
-}
-
-#endif
-
-/*
-** types for functions
-*/
-typedef ArrayType *(*formarray) (ArrayType *, ArrayType *);
-typedef void (*formfloat) (ArrayType *, float *);
-
-/*
-** usefull 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 comressed 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(DEBUG3, "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(DEBUG3, "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 *) palloc(nbytes);
-
- MemSet(r, 0, nbytes);
- r->size = nbytes;
- r->ndim = NDIM;
- 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;
-}
-
-/* r is sorted and size of r > 1 */
-static ArrayType *
-_int_unique(ArrayType *r)
-{
- int *tmp,
- *dr,
- *data;
- int num = ARRNELEMS(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(DEBUG3, "_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(DEBUG3, "_int_common_union out1");
-#endif
- return NULL;
- }
-#ifdef GIST_DEBUG
- elog(DEBUG3, "_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(DEBUG3, "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(DEBUG3, "--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(DEBUG3, "--------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(DEBUG3, "--------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 temprorary 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 notaion 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(DEBUG3, ( 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
- char pbuf[16384],*cur;
-#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
- cur = pbuf;
- *cur = '\0';
- for( i=0;i<query->size;i++ ) {
- if ( ptr[i].type == OPR )
- sprintf(cur, "%c(%d) ", ptr[i].val, ptr[i].left);
- else
- sprintf(cur, "%d ", ptr[i].val );
- cur = strchr(cur,'\0');
- }
- elog(DEBUG3,"POR: %s", pbuf);
-#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 );
-}