OSDN Git Service

Add missing intarray files.
authorBruce Momjian <bruce@momjian.us>
Wed, 11 Jun 2003 19:31:05 +0000 (19:31 +0000)
committerBruce Momjian <bruce@momjian.us>
Wed, 11 Jun 2003 19:31:05 +0000 (19:31 +0000)
contrib/intarray/_int.h [new file with mode: 0644]
contrib/intarray/_int_bool.c [new file with mode: 0644]
contrib/intarray/_int_gist.c [new file with mode: 0644]
contrib/intarray/_int_op.c [new file with mode: 0644]
contrib/intarray/_int_tool.c [new file with mode: 0644]
contrib/intarray/_intbig_gist.c [new file with mode: 0644]

diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h
new file mode 100644 (file)
index 0000000..102d9b7
--- /dev/null
@@ -0,0 +1,175 @@
+#include "postgres.h"
+
+#include <float.h>
+
+#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  63                  /* >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))
+
+/*
+ * type of index key
+ */
+typedef struct
+{
+        int4            len;
+        int4            flag;
+        char            data[1];
+}       GISTTYPE;
+
+#define ALLISTRUE       0x04
+
+#define ISALLTRUE(x)    ( ((GISTTYPE*)x)->flag & ALLISTRUE )
+
+#define GTHDRSIZE       ( sizeof(int4)*2  )
+#define CALCGTSIZE(flag) ( GTHDRSIZE+(((flag) & ALLISTRUE) ? 0 : SIGLEN) )
+
+#define GETSIGN(x)      ( (BITVECP)( (char*)x+GTHDRSIZE ) )
+
+/*
+** types for functions
+*/
+typedef ArrayType *(*formarray) (ArrayType *, ArrayType *);
+typedef void (*formfloat) (ArrayType *, float *);
+
+/*
+** useful function
+*/
+bool isort(int4 *a, const int len);
+ArrayType *new_intArrayType(int num);
+ArrayType *copy_intArrayType(ArrayType *a);
+ArrayType *resize_intArrayType(ArrayType *a, int num);
+int    internal_size(int *a, int len);
+ArrayType *_int_unique(ArrayType *a);
+int32 intarray_match_first(ArrayType *a, int32 elem);
+ArrayType *intarray_add_elem(ArrayType *a, int32 elem);
+ArrayType *intarray_concat_arrays(ArrayType *a, ArrayType *b);
+ArrayType *int_to_intset(int32 elem);
+bool inner_int_overlap(ArrayType *a, ArrayType *b);
+bool inner_int_contains(ArrayType *a, ArrayType *b);
+ArrayType * inner_int_union(ArrayType *a, ArrayType *b);
+ArrayType * inner_int_inter(ArrayType *a, ArrayType *b);
+void rt__int_size(ArrayType *a, float *size);
+void gensign(BITVEC sign, int *a, int len);
+
+
+/*****************************************************************************
+ *                     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 )
+
+bool signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot);
+bool execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot);
+
+
+
+int compASC(const void *a, const void *b);
+
+int compDESC(const void *a, const void *b);
+
+#define QSORT(a, direction)                                     \
+if (ARRNELEMS(a) > 1)                                           \
+        qsort((void*)ARRPTR(a), ARRNELEMS(a),sizeof(int4),      \
+                (direction) ? compASC : compDESC )
+
+
diff --git a/contrib/intarray/_int_bool.c b/contrib/intarray/_int_bool.c
new file mode 100644 (file)
index 0000000..3e8cfd9
--- /dev/null
@@ -0,0 +1,735 @@
+#include "_int.h"
+
+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);
+
+
+#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
+ */
+bool
+signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot)
+{
+       return execute(
+                                  GETQUERY(query) + query->size - 1,
+                                  (void *) sign, calcnot,
+                                  checkcondition_bit
+       );
+}
+
+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
+       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(DEBUG3, "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);
+}
+
diff --git a/contrib/intarray/_int_gist.c b/contrib/intarray/_int_gist.c
new file mode 100644 (file)
index 0000000..fa6d502
--- /dev/null
@@ -0,0 +1,504 @@
+#include "_int.h"
+
+#define GETENTRY(vec,pos) ((ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(vec))[(pos)].key))
+
+/*
+** 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);
+
+
+/*
+** 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) {
+       bytea      *entryvec = (bytea *) PG_GETARG_POINTER(0);
+       int                *size = (int *) PG_GETARG_POINTER(1);
+       int4            i,len = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
+       ArrayType       *res;
+       int totlen=0,*ptr;
+
+       for (i = 0; i < len; i++)
+               totlen+=ARRNELEMS( GETENTRY(entryvec,i) );
+
+       res=new_intArrayType(totlen);
+       ptr=ARRPTR(res);
+
+       for (i = 0; i < len; i++) {
+               memcpy(ptr, ARRPTR( GETENTRY(entryvec,i) ), ARRNELEMS( GETENTRY(entryvec,i) )*sizeof(int4) );
+               ptr+=ARRNELEMS( GETENTRY(entryvec,i) );
+       }
+
+       QSORT(res,1);
+       res=_int_unique(res);
+       *size = VARSIZE(res);   
+       PG_RETURN_POINTER(res);
+}
+
+/*
+** 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) {
+       GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
+       GISTENTRY *newentry  = (GISTENTRY *) PG_GETARG_POINTER(1);
+       float *result = (float *) PG_GETARG_POINTER(2);
+       ArrayType  *ud;
+       float           tmp1,
+                               tmp2;
+
+       ud = inner_int_union((ArrayType *) DatumGetPointer(origentry->key),
+                                       (ArrayType *) DatumGetPointer(newentry->key));
+       rt__int_size(ud, &tmp1);
+       rt__int_size((ArrayType *) DatumGetPointer(origentry->key), &tmp2);
+       *result = tmp1 - tmp2;
+       pfree(ud);
+
+       PG_RETURN_POINTER (result);
+}
+
+
+
+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);
+}
+
+/*****************************************************************
+** Common GiST Method
+*****************************************************************/
+
+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
+*/
+Datum
+g_int_picksplit(PG_FUNCTION_ARGS) {
+       bytea *entryvec = (bytea *) PG_GETARG_POINTER(0);
+       GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+       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 = inner_int_union(datum_alpha, datum_beta);
+                       rt__int_size(union_d, &size_union);
+                       inter_d = inner_int_inter(datum_alpha, datum_beta);
+                       rt__int_size(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);
+       rt__int_size(datum_l, &size_l);
+       datum_beta = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[seed_2].key);
+       datum_r = copy_intArrayType(datum_beta);
+       rt__int_size(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 = inner_int_union(datum_l, datum_alpha);
+               rt__int_size(union_d, &size_alpha);
+               pfree(union_d);
+               union_d = inner_int_union(datum_r, datum_alpha);
+               rt__int_size(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 = inner_int_union(datum_l, datum_alpha);
+               union_dr = inner_int_union(datum_r, datum_alpha);
+               rt__int_size(union_dl, &size_alpha);
+               rt__int_size(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, 0.01))
+               {
+                       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);
+
+       PG_RETURN_POINTER(v);
+}
+
diff --git a/contrib/intarray/_int_op.c b/contrib/intarray/_int_op.c
new file mode 100644 (file)
index 0000000..5aa27f0
--- /dev/null
@@ -0,0 +1,444 @@
+#include "_int.h"
+
+#include "lib/stringinfo.h"
+
+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);
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+
+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);
+
+#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);
+       a = _int_unique(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);
+       PG_RETURN_POINTER(_int_unique(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);
+       a = _int_unique(a);
+       ca = ARRNELEMS(a);
+       QSORT(b, 1);
+       b = _int_unique(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_tool.c b/contrib/intarray/_int_tool.c
new file mode 100644 (file)
index 0000000..04ff5e4
--- /dev/null
@@ -0,0 +1,370 @@
+#include "_int.h"
+
+
+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);
+
+       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;
+}
+
+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);
+
+       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;
+}
+
+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;
+}
+
+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));
+}
+
+void
+rt__int_size(ArrayType *a, float *size)
+{
+       *size = (float) ARRNELEMS(a);
+
+       return;
+}
+
+
+/* len >= 2 */
+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;
+}
+
+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;
+}
+
+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;
+}
+
+ArrayType *
+copy_intArrayType(ArrayType *a)
+{
+       ArrayType  *r;
+
+       r = new_intArrayType(ARRNELEMS(a));
+       memmove(r, a, VARSIZE(a));
+       return r;
+}
+
+/* num for compressed key */
+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 */
+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));
+}
+
+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++;
+       }
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+ArrayType *
+int_to_intset(int32 n)
+{
+       ArrayType  *result;
+       int32      *aa;
+
+       result = new_intArrayType(1);
+       aa = ARRPTR(result);
+       aa[0] = n;
+       return result;
+}
+
+int
+compASC(const void *a, const void *b)
+{
+       if (*(int4 *) a == *(int4 *) b)
+               return 0;
+       return (*(int4 *) a > *(int4 *) b) ? 1 : -1;
+}
+
+int
+compDESC(const void *a, const void *b)
+{
+       if (*(int4 *) a == *(int4 *) b)
+               return 0;
+       return (*(int4 *) a < *(int4 *) b) ? 1 : -1;
+}
+
diff --git a/contrib/intarray/_intbig_gist.c b/contrib/intarray/_intbig_gist.c
new file mode 100644 (file)
index 0000000..ad1279c
--- /dev/null
@@ -0,0 +1,522 @@
+#include "_int.h"
+
+#define GETENTRY(vec,pos) ((GISTTYPE *) DatumGetPointer(((GISTENTRY *) VARDATA(vec))[(pos)].key))
+/*
+** _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);
+
+#define SUMBIT(val) (       \
+        GETBITBYTE((val),0) + \
+        GETBITBYTE((val),1) + \
+        GETBITBYTE((val),2) + \
+        GETBITBYTE((val),3) + \
+        GETBITBYTE((val),4) + \
+        GETBITBYTE((val),5) + \
+        GETBITBYTE((val),6) + \
+        GETBITBYTE((val),7)   \
+)
+
+PG_FUNCTION_INFO_V1(_intbig_in);
+Datum           _intbig_in(PG_FUNCTION_ARGS);
+                                                                                
+PG_FUNCTION_INFO_V1(_intbig_out);
+Datum           _intbig_out(PG_FUNCTION_ARGS);   
+                        
+        
+Datum
+_intbig_in(PG_FUNCTION_ARGS) {
+        elog(ERROR, "Not implemented");
+        PG_RETURN_DATUM(0);
+}
+                
+Datum
+_intbig_out(PG_FUNCTION_ARGS) {
+        elog(ERROR, "Not implemented");
+        PG_RETURN_DATUM(0);
+}                                
+
+
+/*********************************************************************
+** intbig functions
+*********************************************************************/
+static bool
+_intbig_overlap(GISTTYPE *a, ArrayType *b)
+{
+       int                     num=ARRNELEMS(b);
+       int4 *ptr=ARRPTR(b);
+
+       while(num--) {
+               if (GETBIT(GETSIGN(a),HASHVAL(*ptr)))
+                       return true;
+               ptr++;
+       }
+
+       return false;
+}
+
+static bool
+_intbig_contains(GISTTYPE *a, ArrayType *b)
+{
+       int                     num=ARRNELEMS(b);
+       int4 *ptr=ARRPTR(b);
+
+       while(num--) {
+               if (!GETBIT(GETSIGN(a),HASHVAL(*ptr)))
+                       return false;
+               ptr++;
+       }
+
+       return true;
+}
+
+Datum
+g_intbig_same(PG_FUNCTION_ARGS) {
+       GISTTYPE   *a = (GISTTYPE *) PG_GETARG_POINTER(0);
+       GISTTYPE   *b = (GISTTYPE *) PG_GETARG_POINTER(1);
+       bool       *result = (bool *) PG_GETARG_POINTER(2);
+
+       if (ISALLTRUE(a) && ISALLTRUE(b))
+               *result = true;
+       else if (ISALLTRUE(a))
+               *result = false;
+       else if (ISALLTRUE(b))
+               *result = false;
+       else {
+               int4            i;
+               BITVECP         sa = GETSIGN(a),
+               sb = GETSIGN(b);
+               *result = true;
+               LOOPBYTE(
+                       if (sa[i] != sb[i]) {
+                               *result = false;
+                               break;
+                       }
+               );
+       }
+       PG_RETURN_POINTER(result);
+}
+
+Datum
+g_intbig_compress(PG_FUNCTION_ARGS)
+{
+       GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+       if (entry->leafkey) {
+               GISTENTRY  *retval;
+               ArrayType *in = (ArrayType *) PG_DETOAST_DATUM(entry->key);
+               int4 *ptr;
+               int num;
+               GISTTYPE *res=(GISTTYPE*)palloc(CALCGTSIZE(0));
+
+               ARRISVOID(in);
+
+               ptr=ARRPTR(in);
+               num=ARRNELEMS(in);
+               memset(res,0,CALCGTSIZE(0));
+               res->len=CALCGTSIZE(0);
+
+               while(num--) {
+                       HASH(GETSIGN(res),*ptr);
+                       ptr++;
+               }
+
+               retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
+               gistentryinit(*retval, PointerGetDatum(res),
+                       entry->rel, entry->page,
+                       entry->offset, res->len, FALSE);
+               
+               if ( in!=(ArrayType *) PG_DETOAST_DATUM(entry->key) )
+                       pfree(in);
+
+               PG_RETURN_POINTER(retval);
+       } else if ( !ISALLTRUE(DatumGetPointer(entry->key)) ) {
+               GISTENTRY  *retval;
+               int     i;
+               BITVECP         sign = GETSIGN(DatumGetPointer(entry->key));
+               GISTTYPE   *res;
+
+               LOOPBYTE(
+                       if ((sign[i] & 0xff) != 0xff)
+                               PG_RETURN_POINTER(entry);
+               );
+
+               res=(GISTTYPE*)palloc(CALCGTSIZE(ALLISTRUE));   
+               res->len=CALCGTSIZE(ALLISTRUE);
+               res->flag = ALLISTRUE;
+
+               retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
+               gistentryinit(*retval, PointerGetDatum(res),
+                       entry->rel, entry->page,
+                       entry->offset, res->len, FALSE);
+               
+               PG_RETURN_POINTER(retval);
+       }
+       
+       PG_RETURN_POINTER(entry);
+}
+
+
+static int4
+sizebitvec(BITVECP sign) {
+       int4            size = 0, i;
+       LOOPBYTE(
+               size += SUMBIT(sign);
+               sign = (BITVECP) (((char *) sign) + 1);
+       );
+        return size;
+}
+
+static int
+hemdistsign(BITVECP  a, BITVECP b) {
+        int i,dist=0;
+        
+        LOOPBIT(
+                if ( GETBIT(a,i) != GETBIT(b,i) )
+                        dist++;
+        );
+        return dist;
+}
+
+static int
+hemdist(GISTTYPE   *a, GISTTYPE   *b) {
+        if ( ISALLTRUE(a) ) {
+                if (ISALLTRUE(b))
+                        return 0;
+                else
+                        return SIGLENBIT-sizebitvec(GETSIGN(b));
+        } else if (ISALLTRUE(b))
+                return SIGLENBIT-sizebitvec(GETSIGN(a));
+        return hemdistsign( GETSIGN(a), GETSIGN(b) );
+}
+
+Datum
+g_intbig_decompress(PG_FUNCTION_ARGS)
+{
+       PG_RETURN_DATUM(PG_GETARG_DATUM(0));
+}
+
+static int4
+unionkey(BITVECP sbase, GISTTYPE * add)
+{
+       int4            i;
+       BITVECP         sadd = GETSIGN(add);
+
+       if (ISALLTRUE(add))
+               return 1;
+       LOOPBYTE(
+               sbase[i] |= sadd[i];
+       );
+       return 0;
+}
+
+Datum
+g_intbig_union(PG_FUNCTION_ARGS) {
+       bytea      *entryvec = (bytea *) PG_GETARG_POINTER(0);
+       int                *size = (int *) PG_GETARG_POINTER(1);
+       BITVEC          base;
+       int4            len = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
+       int4            i;
+       int4            flag = 0;
+       GISTTYPE   *result;
+
+       MemSet((void *) base, 0, sizeof(BITVEC));
+       for (i = 0; i < len; i++) {
+               if (unionkey(base, GETENTRY(entryvec, i))) {
+                       flag = ALLISTRUE;
+                       break;
+               }
+       }
+
+       len = CALCGTSIZE(flag);
+       result = (GISTTYPE *) palloc(len);
+       *size = result->len = len;
+       result->flag = flag;
+       if (!ISALLTRUE(result))
+               memcpy((void *) GETSIGN(result), (void *) base, sizeof(BITVEC));
+       PG_RETURN_POINTER(result);
+}
+
+Datum
+g_intbig_penalty(PG_FUNCTION_ARGS) {
+       GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
+       GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
+       float      *penalty = (float *) PG_GETARG_POINTER(2);
+       GISTTYPE   *origval = (GISTTYPE *) DatumGetPointer(origentry->key);
+       GISTTYPE   *newval = (GISTTYPE *) DatumGetPointer(newentry->key);
+
+       *penalty=hemdist(origval,newval);
+       PG_RETURN_POINTER(penalty);
+}
+
+
+typedef struct {
+       OffsetNumber pos;
+       int4            cost;
+} SPLITCOST;
+
+static int
+comparecost(const void *a, const void *b) {
+       return ((SPLITCOST *) a)->cost - ((SPLITCOST *) b)->cost;
+}
+
+
+Datum
+g_intbig_picksplit(PG_FUNCTION_ARGS) {
+        bytea      *entryvec = (bytea *) PG_GETARG_POINTER(0);
+        GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+        OffsetNumber k,
+                                j;
+        GISTTYPE *datum_l,
+                           *datum_r;
+        BITVECP         union_l,
+                                union_r;
+        int4            size_alpha, size_beta;
+        int4            size_waste,
+                                waste = -1;
+        int4            nbytes;
+        OffsetNumber seed_1 = 0,
+                                seed_2 = 0;
+        OffsetNumber *left,
+                           *right;
+        OffsetNumber maxoff;
+        BITVECP         ptr;
+        int                     i;
+        SPLITCOST  *costvector;
+        GISTTYPE *_k,
+                           *_j;
+
+        maxoff = ((VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY)) - 2;
+        nbytes = (maxoff + 2) * sizeof(OffsetNumber);
+        v->spl_left = (OffsetNumber *) palloc(nbytes);
+        v->spl_right = (OffsetNumber *) palloc(nbytes);
+
+        for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k)) {
+                _k = GETENTRY(entryvec, k);
+                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;
+                        }
+                }
+        }
+
+        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;
+        }
+
+        /* form initial .. */
+        if (ISALLTRUE(GETENTRY(entryvec, seed_1)))
+        {
+                datum_l = (GISTTYPE *) palloc(GTHDRSIZE);
+                datum_l->len = GTHDRSIZE;
+                datum_l->flag = ALLISTRUE;
+        }
+        else
+        {
+                datum_l = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
+                datum_l->len = GTHDRSIZE + SIGLEN;
+                datum_l->flag = 0;
+                memcpy((void *) GETSIGN(datum_l), (void *) GETSIGN(GETENTRY(entryvec, seed_1)), sizeof(BITVEC));
+        }
+        if (ISALLTRUE(GETENTRY(entryvec, seed_2)))
+        {
+                datum_r = (GISTTYPE *) palloc(GTHDRSIZE);
+                datum_r->len = GTHDRSIZE;
+                datum_r->flag = ALLISTRUE;
+        }
+        else
+        {
+                datum_r = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
+                datum_r->len = GTHDRSIZE + SIGLEN;
+                datum_r->flag = 0;
+                memcpy((void *) GETSIGN(datum_r), (void *) GETSIGN(GETENTRY(entryvec, seed_2)), sizeof(BITVEC));
+        }
+
+        maxoff = OffsetNumberNext(maxoff);
+        /* sort before ... */
+        costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
+        for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
+        {
+                costvector[j - 1].pos = j;
+                _j = GETENTRY(entryvec, j);
+                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=GETSIGN(datum_l);
+        union_r=GETSIGN(datum_r);
+
+        for (k = 0; k < maxoff; k++)
+        {
+                j = costvector[k].pos;
+                if (j == seed_1)
+                {
+                        *left++ = j;
+                        v->spl_nleft++;
+                        continue;
+                }
+                else if (j == seed_2)
+                {
+                        *right++ = j;
+                        v->spl_nright++;
+                        continue;
+                }
+                _j = GETENTRY(entryvec, j);
+                size_alpha = hemdist(datum_l,_j);
+                size_beta  = hemdist(datum_r,_j);
+
+                if (size_alpha < size_beta  + WISH_F(v->spl_nleft, v->spl_nright, 0.00001))
+                {
+                        if (ISALLTRUE(datum_l) || ISALLTRUE(_j) ) {
+                                if (!ISALLTRUE(datum_l))
+                                        MemSet((void *) union_l, 0xff, sizeof(BITVEC));
+                        } else {
+                                ptr=GETSIGN(_j);
+                                LOOPBYTE(
+                                        union_l[i] |= ptr[i];
+                                );
+                        }
+                        *left++ = j;
+                        v->spl_nleft++;
+                }
+                else
+                {
+                        if (ISALLTRUE(datum_r) || ISALLTRUE(_j) ) {
+                                if (!ISALLTRUE(datum_r))
+                                        MemSet((void *) union_r, 0xff, sizeof(BITVEC));
+                        } else {
+                                ptr=GETSIGN(_j);
+                                LOOPBYTE(
+                                        union_r[i] |= ptr[i];
+                                );
+                        }
+                        *right++ = j;
+                        v->spl_nright++;
+                }
+        }
+
+        *right = *left = FirstOffsetNumber;
+        pfree(costvector);
+
+        v->spl_ldatum = PointerGetDatum(datum_l);
+        v->spl_rdatum = PointerGetDatum(datum_r);
+
+        PG_RETURN_POINTER(v);
+}
+
+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;
+
+       if ( ISALLTRUE(DatumGetPointer(entry->key)) )
+               PG_RETURN_BOOL(true);
+       
+       if (strategy == BooleanSearchStrategy) {
+               PG_RETURN_BOOL(signconsistent((QUERYTYPE *) query,
+                                          GETSIGN(DatumGetPointer(entry->key)),
+                                                                         false));
+       }
+
+       /* XXX what about toasted input? */
+       if (ARRISVOID(query))
+               return FALSE;
+
+       switch (strategy)
+       {
+               case RTOverlapStrategyNumber:
+                       retval = _intbig_overlap((GISTTYPE *) DatumGetPointer(entry->key), query);
+                       break;
+               case RTSameStrategyNumber:
+                       if (GIST_LEAF(entry)) {
+                               int i,num=ARRNELEMS(query);
+                               int4 *ptr=ARRPTR(query);
+                               BITVEC  qp;
+                               BITVECP dq, de;
+                               memset(qp,0,sizeof(BITVEC));
+
+                               while(num--) {
+                                       HASH(qp, *ptr);
+                                       ptr++;
+                               }
+
+                               de=GETSIGN((GISTTYPE *) DatumGetPointer(entry->key));
+                               dq=qp;
+                               retval=true;
+                               LOOPBYTE(
+                                       if ( de[i] != dq[i] ) {
+                                               retval=false;
+                                               break;
+                                       }
+                               );
+
+                       } else
+                               retval = _intbig_contains((GISTTYPE *) DatumGetPointer(entry->key), query);
+                       break;
+               case RTContainsStrategyNumber:
+                       retval = _intbig_contains((GISTTYPE *) DatumGetPointer(entry->key), query);
+                       break;
+               case RTContainedByStrategyNumber:
+                       if (GIST_LEAF(entry)) {
+                               int i,num=ARRNELEMS(query);
+                               int4 *ptr=ARRPTR(query);
+                               BITVEC  qp;
+                               BITVECP dq, de;
+                               memset(qp,0,sizeof(BITVEC));
+
+                               while(num--) {
+                                       HASH(qp, *ptr);
+                                       ptr++;
+                               }
+
+                               de=GETSIGN((GISTTYPE *) DatumGetPointer(entry->key));
+                               dq=qp;
+                               retval=true;
+                               LOOPBYTE(
+                                       if ( de[i] & ~dq[i] ) {
+                                               retval=false;
+                                               break;
+                                       }
+                               );
+
+                       } else
+                               retval = _intbig_overlap((GISTTYPE *) DatumGetPointer(entry->key), query);
+                       break;
+               default:
+                       retval = FALSE;
+       }
+       PG_RETURN_BOOL(retval);
+}
+
+