diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h new file mode 100644 index 0000000000..102d9b7903 --- /dev/null +++ b/contrib/intarray/_int.h @@ -0,0 +1,175 @@ +#include "postgres.h" + +#include + +#include "access/gist.h" +#include "access/itup.h" +#include "access/rtree.h" +#include "catalog/pg_type.h" +#include "utils/elog.h" +#include "utils/palloc.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "storage/bufpage.h" +#include "lib/stringinfo.h" + +/* number ranges for compression */ +#define MAXNUMRANGE 100 + +#define max(a,b) ((a) > (b) ? (a) : (b)) +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#define abs(a) ((a) < (0) ? -(a) : (a)) + +/* dimension of array */ +#define NDIM 1 + +/* + * flags for gist__int_ops, use ArrayType->flags + * which is unused (see array.h) + */ +#define LEAFKEY (1<<31) +#define ISLEAFKEY(x) ( ((ArrayType*)(x))->flags & LEAFKEY ) + +/* useful macros for accessing int4 arrays */ +#define ARRPTR(x) ( (int4 *) ARR_DATA_PTR(x) ) +#define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x)) + +#define ARRISVOID(x) ( (x) ? ( ( ARR_NDIM(x) == NDIM ) ? ( ( ARRNELEMS( x ) ) ? 0 : 1 ) : ( ( ARR_NDIM(x) ) ? (elog(ERROR,"Array is not one-dimensional: %d dimensions",ARRNELEMS( x )),1) : 0 ) ) : 0 ) + +#define SORT(x) \ + do { \ + if ( ARRNELEMS( x ) > 1 ) \ + isort( ARRPTR( x ), ARRNELEMS( x ) ); \ + } while(0) + +#define PREPAREARR(x) \ + do { \ + if ( ARRNELEMS( x ) > 1 ) \ + if ( isort( ARRPTR( x ), ARRNELEMS( x ) ) ) \ + x = _int_unique( x ); \ + } while(0) + +/* "wish" function */ +#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) ) + + +/* bigint defines */ +#define BITBYTE 8 +#define SIGLENINT 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> (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 index 0000000000..3e8cfd9342 --- /dev/null +++ b/contrib/intarray/_int_bool.c @@ -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 index 0000000000..fa6d502e89 --- /dev/null +++ b/contrib/intarray/_int_gist.c @@ -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 index 0000000000..5aa27f039d --- /dev/null +++ b/contrib/intarray/_int_op.c @@ -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 index 0000000000..04ff5e436b --- /dev/null +++ b/contrib/intarray/_int_tool.c @@ -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 index 0000000000..ad1279ced3 --- /dev/null +++ b/contrib/intarray/_intbig_gist.c @@ -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); +} + +