diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h index dd50b37d2ea..11c069890ea 100644 --- a/contrib/intarray/_int.h +++ b/contrib/intarray/_int.h @@ -9,41 +9,36 @@ /* number ranges for compression */ #define MAXNUMRANGE 100 -/* dimension of array */ -#define NDIM 1 - /* useful macros for accessing int4 arrays */ #define ARRPTR(x) ( (int4 *) ARR_DATA_PTR(x) ) #define ARRNELEMS(x) ArrayGetNItems(ARR_NDIM(x), ARR_DIMS(x)) -/* reject arrays we can't handle; but allow a NULL or empty array */ +/* reject arrays we can't handle; to wit, those containing nulls */ #define CHECKARRVALID(x) \ do { \ - if (x) { \ - if (ARR_NDIM(x) != NDIM && ARR_NDIM(x) != 0) \ - ereport(ERROR, \ - (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), \ - errmsg("array must be one-dimensional"))); \ - if (ARR_HASNULL(x)) \ - ereport(ERROR, \ - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \ - errmsg("array must not contain nulls"))); \ - } \ + if (ARR_HASNULL(x) && array_contains_nulls(x)) \ + ereport(ERROR, \ + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \ + errmsg("array must not contain nulls"))); \ } while(0) -#define ARRISVOID(x) ((x) == NULL || ARRNELEMS(x) == 0) +#define ARRISEMPTY(x) (ARRNELEMS(x) == 0) +/* sort the elements of the array */ #define SORT(x) \ do { \ - if ( ARRNELEMS( x ) > 1 ) \ - isort( ARRPTR( x ), ARRNELEMS( x ) ); \ + int _nelems_ = ARRNELEMS(x); \ + if (_nelems_ > 1) \ + isort(ARRPTR(x), _nelems_); \ } while(0) +/* sort the elements of the array and remove duplicates */ #define PREPAREARR(x) \ do { \ - if ( ARRNELEMS( x ) > 1 ) \ - if ( isort( ARRPTR( x ), ARRNELEMS( x ) ) ) \ - x = _int_unique( x ); \ + int _nelems_ = ARRNELEMS(x); \ + if (_nelems_ > 1) \ + if (isort(ARRPTR(x), _nelems_)) \ + (x) = _int_unique(x); \ } while(0) /* "wish" function */ @@ -90,14 +85,14 @@ typedef struct #define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) ) /* -** types for functions -*/ + * types for functions + */ typedef ArrayType *(*formarray) (ArrayType *, ArrayType *); typedef void (*formfloat) (ArrayType *, float *); /* -** useful function -*/ + * useful functions + */ bool isort(int4 *a, int len); ArrayType *new_intArrayType(int num); ArrayType *copy_intArrayType(ArrayType *a); @@ -133,17 +128,18 @@ typedef struct ITEM int4 val; } ITEM; -typedef struct +typedef struct QUERYTYPE { int32 vl_len_; /* varlena header (do not touch directly!) */ - int4 size; - char data[1]; + int4 size; /* number of ITEMs */ + ITEM items[1]; /* variable length array */ } QUERYTYPE; -#define HDRSIZEQT (VARHDRSZ + sizeof(int4)) -#define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) ) -#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT ) +#define HDRSIZEQT offsetof(QUERYTYPE, items) +#define COMPUTESIZE(size) ( HDRSIZEQT + (size) * sizeof(ITEM) ) +#define GETQUERY(x) ( (x)->items ) +/* "type" codes for ITEM */ #define END 0 #define ERR 1 #define VAL 2 @@ -151,18 +147,28 @@ typedef struct #define OPEN 4 #define CLOSE 5 +/* fmgr macros for QUERYTYPE objects */ +#define DatumGetQueryTypeP(X) ((QUERYTYPE *) PG_DETOAST_DATUM(X)) +#define DatumGetQueryTypePCopy(X) ((QUERYTYPE *) PG_DETOAST_DATUM_COPY(X)) +#define PG_GETARG_QUERYTYPE_P(n) DatumGetQueryTypeP(PG_GETARG_DATUM(n)) +#define PG_GETARG_QUERYTYPE_P_COPY(n) DatumGetQueryTypePCopy(PG_GETARG_DATUM(n)) + bool signconsistent(QUERYTYPE *query, BITVEC sign, bool calcnot); bool execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot); -bool ginconsistent(QUERYTYPE *query, bool *check); -int4 shorterquery(ITEM *q, int4 len); + +bool gin_bool_consistent(QUERYTYPE *query, bool *check); +bool query_has_required_values(QUERYTYPE *query); 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 ) +/* sort, either ascending or descending */ +#define QSORT(a, direction) \ + do { \ + int _nelems_ = ARRNELEMS(a); \ + if (_nelems_ > 1) \ + qsort((void*) ARRPTR(a), _nelems_, sizeof(int4), \ + (direction) ? compASC : compDESC ); \ + } while(0) #endif /* ___INT_H__ */ diff --git a/contrib/intarray/_int_bool.c b/contrib/intarray/_int_bool.c index 4cc447bab2d..3492100c0c2 100644 --- a/contrib/intarray/_int_bool.c +++ b/contrib/intarray/_int_bool.c @@ -3,6 +3,7 @@ */ #include "postgres.h" +#include "miscadmin.h" #include "utils/builtins.h" #include "_int.h" @@ -22,13 +23,6 @@ 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 @@ -167,6 +161,9 @@ makepol(WORKSTATE *state) int4 stack[STACKDEPTH]; int4 lenstack = 0; + /* since this function recurses, it could be driven to stack overflow */ + check_stack_depth(); + while ((type = gettoken(state, &val)) != END) { switch (type) @@ -236,7 +233,7 @@ typedef struct } CHKVAL; /* - * is there value 'val' in array or not ? + * is there value 'val' in (sorted) array or not ? */ static bool checkcondition_arr(void *checkval, ITEM *item) @@ -267,11 +264,14 @@ checkcondition_bit(void *checkval, ITEM *item) } /* - * check for boolean condition + * evaluate boolean expression, using chkcond() to test the primitive cases */ static bool -execute(ITEM *curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, ITEM *item)) +execute(ITEM *curitem, void *checkval, bool calcnot, + bool (*chkcond) (void *checkval, ITEM *item)) { + /* since this function recurses, it could be driven to stack overflow */ + check_stack_depth(); if (curitem->type == VAL) return (*chkcond) (checkval, curitem); @@ -304,13 +304,12 @@ execute(ITEM *curitem, void *checkval, bool calcnot, bool (*chkcond) (void *chec bool signconsistent(QUERYTYPE *query, BITVEC sign, bool calcnot) { - return execute( - GETQUERY(query) + query->size - 1, + return execute(GETQUERY(query) + query->size - 1, (void *) sign, calcnot, - checkcondition_bit - ); + checkcondition_bit); } +/* Array must be sorted! */ bool execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot) { @@ -319,11 +318,9 @@ execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot) CHECKARRVALID(array); chkval.arrb = ARRPTR(array); chkval.arre = chkval.arrb + ARRNELEMS(array); - return execute( - GETQUERY(query) + query->size - 1, + return execute(GETQUERY(query) + query->size - 1, (void *) &chkval, calcnot, - checkcondition_arr - ); + checkcondition_arr); } typedef struct @@ -341,27 +338,75 @@ checkcondition_gin(void *checkval, ITEM *item) } bool -ginconsistent(QUERYTYPE *query, bool *check) +gin_bool_consistent(QUERYTYPE *query, bool *check) { GinChkVal gcv; ITEM *items = GETQUERY(query); int i, j = 0; - if (query->size < 0) + if (query->size <= 0) return FALSE; + /* + * Set up data for checkcondition_gin. This must agree with the + * query extraction code in ginint4_queryextract. + */ gcv.first = items; gcv.mapped_check = (bool *) palloc(sizeof(bool) * query->size); for (i = 0; i < query->size; i++) + { if (items[i].type == VAL) gcv.mapped_check[i] = check[j++]; + } - return execute( - GETQUERY(query) + query->size - 1, + return execute(GETQUERY(query) + query->size - 1, (void *) &gcv, true, - checkcondition_gin - ); + checkcondition_gin); +} + +static bool +contains_required_value(ITEM *curitem) +{ + /* since this function recurses, it could be driven to stack overflow */ + check_stack_depth(); + + if (curitem->type == VAL) + return true; + else if (curitem->val == (int4) '!') + { + /* + * Assume anything under a NOT is non-required. For some cases with + * nested NOTs, we could prove there's a required value, but it seems + * unlikely to be worth the trouble. + */ + return false; + } + else if (curitem->val == (int4) '&') + { + /* If either side has a required value, we're good */ + if (contains_required_value(curitem + curitem->left)) + return true; + else + return contains_required_value(curitem - 1); + } + else + { /* |-operator */ + /* Both sides must have required values */ + if (contains_required_value(curitem + curitem->left)) + return contains_required_value(curitem - 1); + else + return false; + } + return false; +} + +bool +query_has_required_values(QUERYTYPE *query) +{ + if (query->size <= 0) + return false; + return contains_required_value(GETQUERY(query) + query->size - 1); } /* @@ -370,37 +415,27 @@ ginconsistent(QUERYTYPE *query, bool *check) Datum rboolop(PG_FUNCTION_ARGS) { - return DirectFunctionCall2( - boolop, + /* just reverse the operands */ + return DirectFunctionCall2(boolop, PG_GETARG_DATUM(1), - PG_GETARG_DATUM(0) - ); + 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)); + ArrayType *val = PG_GETARG_ARRAYTYPE_P_COPY(0); + QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(1); CHKVAL chkval; bool result; CHECKARRVALID(val); - 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, + result = execute(GETQUERY(query) + query->size - 1, &chkval, true, - checkcondition_arr - ); + checkcondition_arr); pfree(val); PG_FREE_IF_COPY(query, 1); @@ -599,7 +634,7 @@ infix(INFIX *in, bool first) Datum bqarr_out(PG_FUNCTION_ARGS) { - QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0)); + QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(0); INFIX nrm; if (query->size == 0) @@ -617,173 +652,11 @@ bqarr_out(PG_FUNCTION_ARGS) 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 - */ -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; -} - +/* Useless old "debugging" function for a fundamentally wrong algorithm */ 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) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("empty query"))); - - 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 = cstring_to_text("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 = cstring_to_text_with_len(nrm.buf, nrm.cur - nrm.buf); - } - pfree(q); - - PG_RETURN_TEXT_P(res); + elog(ERROR, "querytree is no longer implemented"); + PG_RETURN_NULL(); } diff --git a/contrib/intarray/_int_gin.c b/contrib/intarray/_int_gin.c index b5ad69eba35..3ef5c4635a1 100644 --- a/contrib/intarray/_int_gin.c +++ b/contrib/intarray/_int_gin.c @@ -3,6 +3,7 @@ */ #include "postgres.h" +#include "access/gin.h" #include "access/gist.h" #include "access/skey.h" @@ -16,66 +17,90 @@ ginint4_queryextract(PG_FUNCTION_ARGS) { int32 *nentries = (int32 *) PG_GETARG_POINTER(1); StrategyNumber strategy = PG_GETARG_UINT16(2); + int32 *searchMode = (int32 *) PG_GETARG_POINTER(6); Datum *res = NULL; *nentries = 0; if (strategy == BooleanSearchStrategy) { - QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0)); + QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(0); ITEM *items = GETQUERY(query); int i; - if (query->size == 0) + /* empty query must fail */ + if (query->size <= 0) PG_RETURN_POINTER(NULL); - if (shorterquery(items, query->size) == 0) - elog(ERROR, "Query requires full scan, GIN doesn't support it"); - - pfree(query); - - query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0)); - items = GETQUERY(query); + /* + * If the query doesn't have any required primitive values (for + * instance, it's something like '! 42'), we have to do a full + * index scan. + */ + if (query_has_required_values(query)) + *searchMode = GIN_SEARCH_MODE_DEFAULT; + else + *searchMode = GIN_SEARCH_MODE_ALL; + /* + * Extract all the VAL items as things we want GIN to check for. + */ res = (Datum *) palloc(sizeof(Datum) * query->size); *nentries = 0; for (i = 0; i < query->size; i++) + { if (items[i].type == VAL) { res[*nentries] = Int32GetDatum(items[i].val); (*nentries)++; } + } } else { ArrayType *query = PG_GETARG_ARRAYTYPE_P(0); - int4 *arr; - uint32 i; CHECKARRVALID(query); *nentries = ARRNELEMS(query); if (*nentries > 0) { + int4 *arr; + int32 i; + res = (Datum *) palloc(sizeof(Datum) * (*nentries)); arr = ARRPTR(query); for (i = 0; i < *nentries; i++) res[i] = Int32GetDatum(arr[i]); } - } - if (*nentries == 0) - { switch (strategy) { - case BooleanSearchStrategy: case RTOverlapStrategyNumber: - *nentries = -1; /* nobody can be found */ + *searchMode = GIN_SEARCH_MODE_DEFAULT; break; - default: /* require fullscan: GIN can't find void - * arrays */ + case RTContainedByStrategyNumber: + case RTOldContainedByStrategyNumber: + /* empty set is contained in everything */ + *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY; break; + case RTSameStrategyNumber: + if (*nentries > 0) + *searchMode = GIN_SEARCH_MODE_DEFAULT; + else + *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY; + break; + case RTContainsStrategyNumber: + case RTOldContainsStrategyNumber: + if (*nentries > 0) + *searchMode = GIN_SEARCH_MODE_DEFAULT; + else /* everything contains the empty set */ + *searchMode = GIN_SEARCH_MODE_ALL; + break; + default: + elog(ERROR, "ginint4_queryextract: unknown strategy number: %d", + strategy); } } @@ -90,16 +115,11 @@ ginint4_consistent(PG_FUNCTION_ARGS) { bool *check = (bool *) PG_GETARG_POINTER(0); StrategyNumber strategy = PG_GETARG_UINT16(1); - - /* int32 nkeys = PG_GETARG_INT32(3); */ + int32 nkeys = PG_GETARG_INT32(3); /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */ bool *recheck = (bool *) PG_GETARG_POINTER(5); bool res = FALSE; - - /* - * we need not check array carefully, it's done by previous - * ginarrayextract call - */ + int32 i; switch (strategy) { @@ -117,47 +137,41 @@ ginint4_consistent(PG_FUNCTION_ARGS) res = TRUE; break; case RTSameStrategyNumber: + /* we will need recheck */ + *recheck = true; + /* Must have all elements in check[] true */ + res = TRUE; + for (i = 0; i < nkeys; i++) { - ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); - int i, - nentries = ARRNELEMS(query); - - /* we will need recheck */ - *recheck = true; - res = TRUE; - for (i = 0; i < nentries; i++) - if (!check[i]) - { - res = FALSE; - break; - } + if (!check[i]) + { + res = FALSE; + break; + } } break; case RTContainsStrategyNumber: case RTOldContainsStrategyNumber: + /* result is not lossy */ + *recheck = false; + /* Must have all elements in check[] true */ + res = TRUE; + for (i = 0; i < nkeys; i++) { - ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); - int i, - nentries = ARRNELEMS(query); - - /* result is not lossy */ - *recheck = false; - res = TRUE; - for (i = 0; i < nentries; i++) - if (!check[i]) - { - res = FALSE; - break; - } + if (!check[i]) + { + res = FALSE; + break; + } } break; case BooleanSearchStrategy: { - QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(2)); + QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(2); /* result is not lossy */ *recheck = false; - res = ginconsistent(query, check); + res = gin_bool_consistent(query, check); } break; default: diff --git a/contrib/intarray/_int_gist.c b/contrib/intarray/_int_gist.c index 65c9bf2e74b..0a173bfcb66 100644 --- a/contrib/intarray/_int_gist.c +++ b/contrib/intarray/_int_gist.c @@ -40,7 +40,7 @@ Datum g_int_consistent(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); - ArrayType *query = (ArrayType *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(1)); + ArrayType *query = PG_GETARG_ARRAYTYPE_P_COPY(1); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); /* Oid subtype = PG_GETARG_OID(3); */ @@ -62,11 +62,6 @@ g_int_consistent(PG_FUNCTION_ARGS) /* sort query for fast search, key is already sorted */ CHECKARRVALID(query); - if (ARRISVOID(query)) - { - pfree(query); - PG_RETURN_BOOL(false); - } PREPAREARR(query); switch (strategy) @@ -77,12 +72,10 @@ g_int_consistent(PG_FUNCTION_ARGS) break; case RTSameStrategyNumber: if (GIST_LEAF(entry)) - DirectFunctionCall3( - g_int_same, + DirectFunctionCall3(g_int_same, entry->key, PointerGetDatum(query), - PointerGetDatum(&retval) - ); + PointerGetDatum(&retval)); else retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key), query); @@ -162,7 +155,7 @@ g_int_compress(PG_FUNCTION_ARGS) if (entry->leafkey) { - r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key); + r = DatumGetArrayTypePCopy(entry->key); CHECKARRVALID(r); PREPAREARR(r); @@ -182,9 +175,9 @@ g_int_compress(PG_FUNCTION_ARGS) * ==true, so now we work only with internal keys */ - r = (ArrayType *) PG_DETOAST_DATUM(entry->key); + r = DatumGetArrayTypeP(entry->key); CHECKARRVALID(r); - if (ARRISVOID(r)) + if (ARRISEMPTY(r)) { if (r != (ArrayType *) DatumGetPointer(entry->key)) pfree(r); @@ -194,7 +187,7 @@ g_int_compress(PG_FUNCTION_ARGS) if ((len = ARRNELEMS(r)) >= 2 * MAXNUMRANGE) { /* compress */ if (r == (ArrayType *) DatumGetPointer(entry->key)) - r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key); + r = DatumGetArrayTypePCopy(entry->key); r = resize_intArrayType(r, 2 * (len)); dr = ARRPTR(r); @@ -242,10 +235,10 @@ g_int_decompress(PG_FUNCTION_ARGS) int i, j; - in = (ArrayType *) PG_DETOAST_DATUM(entry->key); + in = DatumGetArrayTypeP(entry->key); CHECKARRVALID(in); - if (ARRISVOID(in)) + if (ARRISEMPTY(in)) { if (in != (ArrayType *) DatumGetPointer(entry->key)) { @@ -321,8 +314,8 @@ g_int_penalty(PG_FUNCTION_ARGS) Datum g_int_same(PG_FUNCTION_ARGS) { - ArrayType *a = (ArrayType *) PointerGetDatum(PG_GETARG_POINTER(0)); - ArrayType *b = (ArrayType *) PointerGetDatum(PG_GETARG_POINTER(1)); + ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P(1); bool *result = (bool *) PG_GETARG_POINTER(2); int4 n = ARRNELEMS(a); int4 *da, @@ -340,11 +333,13 @@ g_int_same(PG_FUNCTION_ARGS) da = ARRPTR(a); db = ARRPTR(b); while (n--) + { if (*da++ != *db++) { *result = FALSE; break; } + } PG_RETURN_POINTER(result); } diff --git a/contrib/intarray/_int_op.c b/contrib/intarray/_int_op.c index 1d99c6905ef..392e227cff8 100644 --- a/contrib/intarray/_int_op.c +++ b/contrib/intarray/_int_op.c @@ -29,27 +29,22 @@ 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)) - ) - )); + /* just reverse the operands and call _int_contains */ + return DirectFunctionCall2(_int_contains, + PG_GETARG_DATUM(1), + PG_GETARG_DATUM(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))); + /* Force copy so we can modify the arrays in-place */ + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1); bool res; CHECKARRVALID(a); CHECKARRVALID(b); - if (ARRISVOID(a) || ARRISVOID(b)) - return FALSE; - PREPAREARR(a); PREPAREARR(b); res = inner_int_contains(a, b); @@ -73,24 +68,17 @@ _int_different(PG_FUNCTION_ARGS) 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))); + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1); int na, nb; int n; int *da, *db; bool result; - bool avoid; - bool bvoid; CHECKARRVALID(a); CHECKARRVALID(b); - avoid = ARRISVOID(a); - bvoid = ARRISVOID(b); - if (avoid || bvoid) - return (avoid && bvoid) ? TRUE : FALSE; - na = ARRNELEMS(a); nb = ARRNELEMS(b); da = ARRPTR(a); @@ -105,11 +93,13 @@ _int_same(PG_FUNCTION_ARGS) result = TRUE; for (n = 0; n < na; n++) + { if (da[n] != db[n]) { result = FALSE; break; } + } } pfree(a); @@ -123,13 +113,13 @@ _int_same(PG_FUNCTION_ARGS) 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))); + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1); bool result; CHECKARRVALID(a); CHECKARRVALID(b); - if (ARRISVOID(a) || ARRISVOID(b)) + if (ARRISEMPTY(a) || ARRISEMPTY(b)) return FALSE; SORT(a); @@ -146,24 +136,20 @@ _int_overlap(PG_FUNCTION_ARGS) 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 *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1); ArrayType *result; CHECKARRVALID(a); CHECKARRVALID(b); - if (!ARRISVOID(a)) - SORT(a); - if (!ARRISVOID(b)) - SORT(b); + SORT(a); + SORT(b); result = inner_int_union(a, b); - if (a) - pfree(a); - if (b) - pfree(b); + pfree(a); + pfree(b); PG_RETURN_POINTER(result); } @@ -171,14 +157,12 @@ _int_union(PG_FUNCTION_ARGS) 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 *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1); ArrayType *result; CHECKARRVALID(a); CHECKARRVALID(b); - if (ARRISVOID(a) || ARRISVOID(b)) - PG_RETURN_POINTER(new_intArrayType(0)); SORT(a); SORT(b); @@ -228,7 +212,7 @@ intset(PG_FUNCTION_ARGS) Datum icount(PG_FUNCTION_ARGS) { - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); + ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); int32 count = ARRNELEMS(a); PG_FREE_IF_COPY(a, 0); @@ -238,14 +222,14 @@ icount(PG_FUNCTION_ARGS) Datum sort(PG_FUNCTION_ARGS) { - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(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; CHECKARRVALID(a); - if (ARRISVOID(a) || ARRNELEMS(a) < 2) + if (ARRNELEMS(a) < 2) PG_RETURN_POINTER(a); if (dirstr == NULL || (dc == 3 @@ -270,11 +254,9 @@ sort(PG_FUNCTION_ARGS) Datum sort_asc(PG_FUNCTION_ARGS) { - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); CHECKARRVALID(a); - if (ARRISVOID(a)) - PG_RETURN_POINTER(a); QSORT(a, 1); PG_RETURN_POINTER(a); } @@ -282,11 +264,9 @@ sort_asc(PG_FUNCTION_ARGS) Datum sort_desc(PG_FUNCTION_ARGS) { - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); CHECKARRVALID(a); - if (ARRISVOID(a)) - PG_RETURN_POINTER(a); QSORT(a, 0); PG_RETURN_POINTER(a); } @@ -294,10 +274,10 @@ sort_desc(PG_FUNCTION_ARGS) Datum uniq(PG_FUNCTION_ARGS) { - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); CHECKARRVALID(a); - if (ARRISVOID(a) || ARRNELEMS(a) < 2) + if (ARRNELEMS(a) < 2) PG_RETURN_POINTER(a); a = _int_unique(a); PG_RETURN_POINTER(a); @@ -306,11 +286,11 @@ uniq(PG_FUNCTION_ARGS) Datum idx(PG_FUNCTION_ARGS) { - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); + ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); int32 result; CHECKARRVALID(a); - result = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); + result = ARRNELEMS(a); if (result) result = intarray_match_first(a, PG_GETARG_INT32(1)); PG_FREE_IF_COPY(a, 0); @@ -320,15 +300,17 @@ idx(PG_FUNCTION_ARGS) 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); + ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); + int32 start = PG_GETARG_INT32(1); int32 len = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0; int32 end = 0; int32 c; + ArrayType *result; + + start = (start > 0) ? start - 1 : start; CHECKARRVALID(a); - if (ARRISVOID(a)) + if (ARRISEMPTY(a)) { PG_FREE_IF_COPY(a, 0); PG_RETURN_POINTER(new_intArrayType(0)); @@ -358,7 +340,6 @@ subarray(PG_FUNCTION_ARGS) 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)); @@ -369,7 +350,7 @@ subarray(PG_FUNCTION_ARGS) Datum intarray_push_elem(PG_FUNCTION_ARGS) { - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); + ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); ArrayType *result; result = intarray_add_elem(a, PG_GETARG_INT32(1)); @@ -380,8 +361,8 @@ intarray_push_elem(PG_FUNCTION_ARGS) 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 *a = PG_GETARG_ARRAYTYPE_P(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P(1); ArrayType *result; result = intarray_concat_arrays(a, b); @@ -393,7 +374,7 @@ intarray_push_array(PG_FUNCTION_ARGS) Datum intarray_del_elem(PG_FUNCTION_ARGS) { - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); int32 elem = PG_GETARG_INT32(1); int32 c; int32 *aa; @@ -401,7 +382,7 @@ intarray_del_elem(PG_FUNCTION_ARGS) i; CHECKARRVALID(a); - if (!ARRISVOID(a)) + if (!ARRISEMPTY(a)) { c = ARRNELEMS(a); aa = ARRPTR(a); @@ -423,7 +404,7 @@ intarray_del_elem(PG_FUNCTION_ARGS) Datum intset_union_elem(PG_FUNCTION_ARGS) { - ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); + ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); ArrayType *result; result = intarray_add_elem(a, PG_GETARG_INT32(1)); @@ -435,8 +416,8 @@ intset_union_elem(PG_FUNCTION_ARGS) 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 *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1); ArrayType *result; int32 ca; int32 cb; diff --git a/contrib/intarray/_int_tool.c b/contrib/intarray/_int_tool.c index 8093103ba46..ddf07f042b2 100644 --- a/contrib/intarray/_int_tool.c +++ b/contrib/intarray/_int_tool.c @@ -8,6 +8,7 @@ #include "_int.h" +/* arguments are assumed sorted & unique-ified */ bool inner_int_contains(ArrayType *a, ArrayType *b) { @@ -19,12 +20,6 @@ inner_int_contains(ArrayType *a, ArrayType *b) int *da, *db; - CHECKARRVALID(a); - CHECKARRVALID(b); - - if (ARRISVOID(a) || ARRISVOID(b)) - return FALSE; - na = ARRNELEMS(a); nb = ARRNELEMS(b); da = ARRPTR(a); @@ -32,6 +27,7 @@ inner_int_contains(ArrayType *a, ArrayType *b) i = j = n = 0; while (i < na && j < nb) + { if (da[i] < db[j]) i++; else if (da[i] == db[j]) @@ -41,11 +37,13 @@ inner_int_contains(ArrayType *a, ArrayType *b) j++; } else - break; + break; /* db[j] is not in da */ + } return (n == nb) ? TRUE : FALSE; } +/* arguments are assumed sorted */ bool inner_int_overlap(ArrayType *a, ArrayType *b) { @@ -56,12 +54,6 @@ inner_int_overlap(ArrayType *a, ArrayType *b) int *da, *db; - CHECKARRVALID(a); - CHECKARRVALID(b); - - if (ARRISVOID(a) || ARRISVOID(b)) - return FALSE; - na = ARRNELEMS(a); nb = ARRNELEMS(b); da = ARRPTR(a); @@ -69,12 +61,14 @@ inner_int_overlap(ArrayType *a, ArrayType *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; } @@ -87,11 +81,11 @@ inner_int_union(ArrayType *a, ArrayType *b) CHECKARRVALID(a); CHECKARRVALID(b); - if (ARRISVOID(a) && ARRISVOID(b)) + if (ARRISEMPTY(a) && ARRISEMPTY(b)) return new_intArrayType(0); - if (ARRISVOID(a)) + if (ARRISEMPTY(a)) r = copy_intArrayType(b); - if (ARRISVOID(b)) + if (ARRISEMPTY(b)) r = copy_intArrayType(a); if (!r) @@ -148,10 +142,7 @@ inner_int_inter(ArrayType *a, ArrayType *b) int i, j; - CHECKARRVALID(a); - CHECKARRVALID(b); - - if (ARRISVOID(a) || ARRISVOID(b)) + if (ARRISEMPTY(a) || ARRISEMPTY(b)) return new_intArrayType(0); na = ARRNELEMS(a); @@ -163,6 +154,7 @@ inner_int_inter(ArrayType *a, ArrayType *b) i = j = 0; while (i < na && j < nb) + { if (da[i] < db[j]) i++; else if (da[i] == db[j]) @@ -174,6 +166,7 @@ inner_int_inter(ArrayType *a, ArrayType *b) } else j++; + } if ((dr - ARRPTR(r)) == 0) { @@ -188,57 +181,60 @@ void rt__int_size(ArrayType *a, float *size) { *size = (float) ARRNELEMS(a); - - return; } - -/* len >= 2 */ +/* Sort the given data (len >= 2). Return true if any duplicates found */ bool isort(int4 *a, int len) { - int4 tmp, - index; - int4 *cur, + int4 cur, + prev; + int4 *pcur, + *pprev, *end; bool r = FALSE; + /* + * We use a simple insertion sort. While this is O(N^2) in the worst + * case, it's quite fast if the input is already sorted or nearly so. + * Also, for not-too-large inputs it's faster than more complex methods + * anyhow. + */ end = a + len; - do + for (pcur = a + 1; pcur < end; pcur++) { - index = 0; - cur = a + 1; - while (cur < end) + cur = *pcur; + for (pprev = pcur - 1; pprev >= a; pprev--) { - if (*(cur - 1) > *cur) + prev = *pprev; + if (prev <= cur) { - tmp = *(cur - 1); - *(cur - 1) = *cur; - *cur = tmp; - index = 1; + if (prev == cur) + r = TRUE; + break; } - else if (!r && *(cur - 1) == *cur) - r = TRUE; - cur++; + pprev[1] = prev; } - } while (index); + pprev[1] = cur; + } return r; } +/* Create a new int array with room for "num" elements */ ArrayType * new_intArrayType(int num) { ArrayType *r; - int nbytes = ARR_OVERHEAD_NONULLS(NDIM) + sizeof(int) * num; + int nbytes = ARR_OVERHEAD_NONULLS(1) + sizeof(int) * num; r = (ArrayType *) palloc0(nbytes); SET_VARSIZE(r, nbytes); - ARR_NDIM(r) = NDIM; + ARR_NDIM(r) = 1; r->dataoffset = 0; /* marker for no null bitmap */ ARR_ELEMTYPE(r) = INT4OID; - *((int *) ARR_DIMS(r)) = num; - *((int *) ARR_LBOUND(r)) = 1; + ARR_DIMS(r)[0] = num; + ARR_LBOUND(r)[0] = 1; return r; } @@ -246,7 +242,8 @@ new_intArrayType(int num) ArrayType * resize_intArrayType(ArrayType *a, int num) { - int nbytes = ARR_OVERHEAD_NONULLS(NDIM) + sizeof(int) * num; + int nbytes = ARR_DATA_OFFSET(a) + sizeof(int) * num; + int i; if (num == ARRNELEMS(a)) return a; @@ -254,7 +251,12 @@ resize_intArrayType(ArrayType *a, int num) a = (ArrayType *) repalloc(a, nbytes); SET_VARSIZE(a, nbytes); - *((int *) ARR_DIMS(a)) = num; + /* usually the array should be 1-D already, but just in case ... */ + for (i = 0; i < ARR_NDIM(a); i++) + { + ARR_DIMS(a)[i] = num; + num = 1; + } return a; } @@ -262,9 +264,10 @@ ArrayType * copy_intArrayType(ArrayType *a) { ArrayType *r; + int n = ARRNELEMS(a); - r = new_intArrayType(ARRNELEMS(a)); - memmove(r, a, VARSIZE(r)); + r = new_intArrayType(n); + memcpy(ARRPTR(r), ARRPTR(a), n * sizeof(int4)); return r; } @@ -276,13 +279,15 @@ internal_size(int *a, int len) 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 */ +/* unique-ify elements of r in-place ... r must be sorted already */ ArrayType * _int_unique(ArrayType *r) { @@ -291,17 +296,17 @@ _int_unique(ArrayType *r) *data; int num = ARRNELEMS(r); - CHECKARRVALID(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)); } @@ -326,8 +331,6 @@ intarray_match_first(ArrayType *a, int32 elem) i; CHECKARRVALID(a); - if (ARRISVOID(a)) - return 0; c = ARRNELEMS(a); aa = ARRPTR(a); for (i = 0; i < c; i++) @@ -344,7 +347,7 @@ intarray_add_elem(ArrayType *a, int32 elem) int32 c; CHECKARRVALID(a); - c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); + c = ARRNELEMS(a); result = new_intArrayType(c + 1); r = ARRPTR(result); if (c > 0) @@ -357,8 +360,8 @@ ArrayType * intarray_concat_arrays(ArrayType *a, ArrayType *b) { ArrayType *result; - int32 ac = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); - int32 bc = (ARRISVOID(b)) ? 0 : ARRNELEMS(b); + int32 ac = ARRNELEMS(a); + int32 bc = ARRNELEMS(b); CHECKARRVALID(a); CHECKARRVALID(b); diff --git a/contrib/intarray/_intbig_gist.c b/contrib/intarray/_intbig_gist.c index d9557a6b11a..eb8f2826349 100644 --- a/contrib/intarray/_intbig_gist.c +++ b/contrib/intarray/_intbig_gist.c @@ -153,13 +153,13 @@ g_intbig_compress(PG_FUNCTION_ARGS) if (entry->leafkey) { GISTENTRY *retval; - ArrayType *in = (ArrayType *) PG_DETOAST_DATUM(entry->key); + ArrayType *in = DatumGetArrayTypeP(entry->key); int4 *ptr; int num; GISTTYPE *res = (GISTTYPE *) palloc0(CALCGTSIZE(0)); CHECKARRVALID(in); - if (ARRISVOID(in)) + if (ARRISEMPTY(in)) { ptr = NULL; num = 0; @@ -182,7 +182,7 @@ g_intbig_compress(PG_FUNCTION_ARGS) entry->rel, entry->page, entry->offset, FALSE); - if (in != (ArrayType *) PG_DETOAST_DATUM(entry->key)) + if (in != DatumGetArrayTypeP(entry->key)) pfree(in); PG_RETURN_POINTER(retval); @@ -504,7 +504,7 @@ Datum g_intbig_consistent(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); - ArrayType *query = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_POINTER(1)); + ArrayType *query = PG_GETARG_ARRAYTYPE_P(1); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); /* Oid subtype = PG_GETARG_OID(3); */ @@ -527,11 +527,6 @@ g_intbig_consistent(PG_FUNCTION_ARGS) } CHECKARRVALID(query); - if (ARRISVOID(query)) - { - PG_FREE_IF_COPY(query, 1); - PG_RETURN_BOOL(FALSE); - } switch (strategy) { @@ -548,8 +543,6 @@ g_intbig_consistent(PG_FUNCTION_ARGS) BITVECP dq, de; - CHECKARRVALID(query); - memset(qp, 0, sizeof(BITVEC)); while (num--) @@ -589,8 +582,6 @@ g_intbig_consistent(PG_FUNCTION_ARGS) BITVECP dq, de; - CHECKARRVALID(query); - memset(qp, 0, sizeof(BITVEC)); while (num--) diff --git a/contrib/intarray/uninstall__int.sql b/contrib/intarray/uninstall__int.sql index 5cda23fdad1..345ad4464bd 100644 --- a/contrib/intarray/uninstall__int.sql +++ b/contrib/intarray/uninstall__int.sql @@ -5,9 +5,9 @@ SET search_path = public; DROP OPERATOR CLASS gin__int_ops USING gin; -DROP FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal); +DROP FUNCTION ginint4_queryextract(internal, internal, int2, internal, internal, internal, internal); -DROP FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal); +DROP FUNCTION ginint4_consistent(internal, int2, internal, int4, internal, internal, internal, internal); DROP OPERATOR CLASS gist__intbig_ops USING gist; diff --git a/doc/src/sgml/intarray.sgml b/doc/src/sgml/intarray.sgml index 1cf72a12010..449878d6716 100644 --- a/doc/src/sgml/intarray.sgml +++ b/doc/src/sgml/intarray.sgml @@ -9,10 +9,21 @@ The intarray module provides a number of useful functions - and operators for manipulating one-dimensional arrays of integers. + and operators for manipulating null-free arrays of integers. There is also support for indexed searches using some of the operators. + + All of these operations will throw an error if a supplied array contains any + NULL elements. + + + + Many of these operations are only sensible for one-dimensional arrays. + Although they will accept input arrays of more dimensions, the data is + treated as though it were a linear array in storage order. + + <filename>intarray</> Functions and Operators @@ -211,14 +222,12 @@ - The containment operators @> and <@ are - approximately equivalent to PostgreSQL's built-in operators - of the same names, except that they work only on integer arrays while the - built-in operators work for any array type. An important difference is - that intarray's operators do not consider an empty array to be - contained in anything else. This is consistent with the behavior of - GIN-indexed queries, but not with the usual mathematical definition of - containment. + The operators &&, @> and + <@ are equivalent to PostgreSQL's built-in + operators of the same names, except that they work only on integer arrays + that do not contain nulls, while the built-in operators work for any array + type. This restriction makes them faster than the built-in operators + in many cases.