Commit fdf2dbda authored by Tom Lane's avatar Tom Lane

Fix assorted corner-case bugs in contrib/intarray.

The array containment operators now behave per mathematical expectation
for empty arrays (ie, an empty array is contained in anything).
Both these operators and the query_int operators now work as expected in
GiST and GIN index searches, rather than having corner cases where the
index searches gave different answers.

Also, fix unexpected failures where the operators would claim that an array
contained nulls, when in fact there was no longer any null present (similar
to bug #5784).  The restriction to not have nulls is still there, as
removing it would take a lot of added code complexity and probably slow
things down significantly.

Also, remove the arbitrary restriction to 1-D arrays; unlike the other
restriction, this was buying us nothing performance-wise.

Assorted cosmetic improvements and marginal performance improvements, too.
parent adf328c0
...@@ -9,41 +9,36 @@ ...@@ -9,41 +9,36 @@
/* number ranges for compression */ /* number ranges for compression */
#define MAXNUMRANGE 100 #define MAXNUMRANGE 100
/* dimension of array */
#define NDIM 1
/* useful macros for accessing int4 arrays */ /* useful macros for accessing int4 arrays */
#define ARRPTR(x) ( (int4 *) ARR_DATA_PTR(x) ) #define ARRPTR(x) ( (int4 *) ARR_DATA_PTR(x) )
#define ARRNELEMS(x) ArrayGetNItems(ARR_NDIM(x), ARR_DIMS(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) \ #define CHECKARRVALID(x) \
do { \ do { \
if (x) { \ if (ARR_HASNULL(x) && array_contains_nulls(x)) \
if (ARR_NDIM(x) != NDIM && ARR_NDIM(x) != 0) \ ereport(ERROR, \
ereport(ERROR, \ (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), \ errmsg("array must not contain nulls"))); \
errmsg("array must be one-dimensional"))); \
if (ARR_HASNULL(x)) \
ereport(ERROR, \
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \
errmsg("array must not contain nulls"))); \
} \
} while(0) } 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) \ #define SORT(x) \
do { \ do { \
if ( ARRNELEMS( x ) > 1 ) \ int _nelems_ = ARRNELEMS(x); \
isort( ARRPTR( x ), ARRNELEMS( x ) ); \ if (_nelems_ > 1) \
isort(ARRPTR(x), _nelems_); \
} while(0) } while(0)
/* sort the elements of the array and remove duplicates */
#define PREPAREARR(x) \ #define PREPAREARR(x) \
do { \ do { \
if ( ARRNELEMS( x ) > 1 ) \ int _nelems_ = ARRNELEMS(x); \
if ( isort( ARRPTR( x ), ARRNELEMS( x ) ) ) \ if (_nelems_ > 1) \
x = _int_unique( x ); \ if (isort(ARRPTR(x), _nelems_)) \
(x) = _int_unique(x); \
} while(0) } while(0)
/* "wish" function */ /* "wish" function */
...@@ -90,14 +85,14 @@ typedef struct ...@@ -90,14 +85,14 @@ typedef struct
#define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) ) #define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) )
/* /*
** types for functions * types for functions
*/ */
typedef ArrayType *(*formarray) (ArrayType *, ArrayType *); typedef ArrayType *(*formarray) (ArrayType *, ArrayType *);
typedef void (*formfloat) (ArrayType *, float *); typedef void (*formfloat) (ArrayType *, float *);
/* /*
** useful function * useful functions
*/ */
bool isort(int4 *a, int len); bool isort(int4 *a, int len);
ArrayType *new_intArrayType(int num); ArrayType *new_intArrayType(int num);
ArrayType *copy_intArrayType(ArrayType *a); ArrayType *copy_intArrayType(ArrayType *a);
...@@ -133,17 +128,18 @@ typedef struct ITEM ...@@ -133,17 +128,18 @@ typedef struct ITEM
int4 val; int4 val;
} ITEM; } ITEM;
typedef struct typedef struct QUERYTYPE
{ {
int32 vl_len_; /* varlena header (do not touch directly!) */ int32 vl_len_; /* varlena header (do not touch directly!) */
int4 size; int4 size; /* number of ITEMs */
char data[1]; ITEM items[1]; /* variable length array */
} QUERYTYPE; } QUERYTYPE;
#define HDRSIZEQT (VARHDRSZ + sizeof(int4)) #define HDRSIZEQT offsetof(QUERYTYPE, items)
#define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) ) #define COMPUTESIZE(size) ( HDRSIZEQT + (size) * sizeof(ITEM) )
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT ) #define GETQUERY(x) ( (x)->items )
/* "type" codes for ITEM */
#define END 0 #define END 0
#define ERR 1 #define ERR 1
#define VAL 2 #define VAL 2
...@@ -151,18 +147,28 @@ typedef struct ...@@ -151,18 +147,28 @@ typedef struct
#define OPEN 4 #define OPEN 4
#define CLOSE 5 #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 signconsistent(QUERYTYPE *query, BITVEC sign, bool calcnot);
bool execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot); bool execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot);
bool ginconsistent(QUERYTYPE *query, bool *check);
int4 shorterquery(ITEM *q, int4 len);
int compASC(const void *a, const void *b); 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); int compDESC(const void *a, const void *b);
#define QSORT(a, direction) \ /* sort, either ascending or descending */
if (ARRNELEMS(a) > 1) \ #define QSORT(a, direction) \
qsort((void*)ARRPTR(a), ARRNELEMS(a),sizeof(int4), \ do { \
(direction) ? compASC : compDESC ) int _nelems_ = ARRNELEMS(a); \
if (_nelems_ > 1) \
qsort((void*) ARRPTR(a), _nelems_, sizeof(int4), \
(direction) ? compASC : compDESC ); \
} while(0)
#endif /* ___INT_H__ */ #endif /* ___INT_H__ */
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include "miscadmin.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "_int.h" #include "_int.h"
...@@ -22,13 +23,6 @@ PG_FUNCTION_INFO_V1(querytree); ...@@ -22,13 +23,6 @@ PG_FUNCTION_INFO_V1(querytree);
Datum querytree(PG_FUNCTION_ARGS); 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 */ /* parser's states */
#define WAITOPERAND 1 #define WAITOPERAND 1
#define WAITENDOPERAND 2 #define WAITENDOPERAND 2
...@@ -167,6 +161,9 @@ makepol(WORKSTATE *state) ...@@ -167,6 +161,9 @@ makepol(WORKSTATE *state)
int4 stack[STACKDEPTH]; int4 stack[STACKDEPTH];
int4 lenstack = 0; int4 lenstack = 0;
/* since this function recurses, it could be driven to stack overflow */
check_stack_depth();
while ((type = gettoken(state, &val)) != END) while ((type = gettoken(state, &val)) != END)
{ {
switch (type) switch (type)
...@@ -236,7 +233,7 @@ typedef struct ...@@ -236,7 +233,7 @@ typedef struct
} CHKVAL; } CHKVAL;
/* /*
* is there value 'val' in array or not ? * is there value 'val' in (sorted) array or not ?
*/ */
static bool static bool
checkcondition_arr(void *checkval, ITEM *item) checkcondition_arr(void *checkval, ITEM *item)
...@@ -267,11 +264,14 @@ checkcondition_bit(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 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) if (curitem->type == VAL)
return (*chkcond) (checkval, curitem); return (*chkcond) (checkval, curitem);
...@@ -304,13 +304,12 @@ execute(ITEM *curitem, void *checkval, bool calcnot, bool (*chkcond) (void *chec ...@@ -304,13 +304,12 @@ execute(ITEM *curitem, void *checkval, bool calcnot, bool (*chkcond) (void *chec
bool bool
signconsistent(QUERYTYPE *query, BITVEC sign, bool calcnot) signconsistent(QUERYTYPE *query, BITVEC sign, bool calcnot)
{ {
return execute( return execute(GETQUERY(query) + query->size - 1,
GETQUERY(query) + query->size - 1,
(void *) sign, calcnot, (void *) sign, calcnot,
checkcondition_bit checkcondition_bit);
);
} }
/* Array must be sorted! */
bool bool
execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot) execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot)
{ {
...@@ -319,11 +318,9 @@ execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot) ...@@ -319,11 +318,9 @@ execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot)
CHECKARRVALID(array); CHECKARRVALID(array);
chkval.arrb = ARRPTR(array); chkval.arrb = ARRPTR(array);
chkval.arre = chkval.arrb + ARRNELEMS(array); chkval.arre = chkval.arrb + ARRNELEMS(array);
return execute( return execute(GETQUERY(query) + query->size - 1,
GETQUERY(query) + query->size - 1,
(void *) &chkval, calcnot, (void *) &chkval, calcnot,
checkcondition_arr checkcondition_arr);
);
} }
typedef struct typedef struct
...@@ -341,27 +338,75 @@ checkcondition_gin(void *checkval, ITEM *item) ...@@ -341,27 +338,75 @@ checkcondition_gin(void *checkval, ITEM *item)
} }
bool bool
ginconsistent(QUERYTYPE *query, bool *check) gin_bool_consistent(QUERYTYPE *query, bool *check)
{ {
GinChkVal gcv; GinChkVal gcv;
ITEM *items = GETQUERY(query); ITEM *items = GETQUERY(query);
int i, int i,
j = 0; j = 0;
if (query->size < 0) if (query->size <= 0)
return FALSE; return FALSE;
/*
* Set up data for checkcondition_gin. This must agree with the
* query extraction code in ginint4_queryextract.
*/
gcv.first = items; gcv.first = items;
gcv.mapped_check = (bool *) palloc(sizeof(bool) * query->size); gcv.mapped_check = (bool *) palloc(sizeof(bool) * query->size);
for (i = 0; i < query->size; i++) for (i = 0; i < query->size; i++)
{
if (items[i].type == VAL) if (items[i].type == VAL)
gcv.mapped_check[i] = check[j++]; gcv.mapped_check[i] = check[j++];
}
return execute( return execute(GETQUERY(query) + query->size - 1,
GETQUERY(query) + query->size - 1,
(void *) &gcv, true, (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) ...@@ -370,37 +415,27 @@ ginconsistent(QUERYTYPE *query, bool *check)
Datum Datum
rboolop(PG_FUNCTION_ARGS) rboolop(PG_FUNCTION_ARGS)
{ {
return DirectFunctionCall2( /* just reverse the operands */
boolop, return DirectFunctionCall2(boolop,
PG_GETARG_DATUM(1), PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0) PG_GETARG_DATUM(0));
);
} }
Datum Datum
boolop(PG_FUNCTION_ARGS) boolop(PG_FUNCTION_ARGS)
{ {
ArrayType *val = (ArrayType *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0)); ArrayType *val = PG_GETARG_ARRAYTYPE_P_COPY(0);
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(1)); QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(1);
CHKVAL chkval; CHKVAL chkval;
bool result; bool result;
CHECKARRVALID(val); CHECKARRVALID(val);
if (ARRISVOID(val))
{
pfree(val);
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(false);
}
PREPAREARR(val); PREPAREARR(val);
chkval.arrb = ARRPTR(val); chkval.arrb = ARRPTR(val);
chkval.arre = chkval.arrb + ARRNELEMS(val); chkval.arre = chkval.arrb + ARRNELEMS(val);
result = execute( result = execute(GETQUERY(query) + query->size - 1,
GETQUERY(query) + query->size - 1,
&chkval, true, &chkval, true,
checkcondition_arr checkcondition_arr);
);
pfree(val); pfree(val);
PG_FREE_IF_COPY(query, 1); PG_FREE_IF_COPY(query, 1);
...@@ -599,7 +634,7 @@ infix(INFIX *in, bool first) ...@@ -599,7 +634,7 @@ infix(INFIX *in, bool first)
Datum Datum
bqarr_out(PG_FUNCTION_ARGS) bqarr_out(PG_FUNCTION_ARGS)
{ {
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0)); QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(0);
INFIX nrm; INFIX nrm;
if (query->size == 0) if (query->size == 0)
...@@ -617,173 +652,11 @@ bqarr_out(PG_FUNCTION_ARGS) ...@@ -617,173 +652,11 @@ bqarr_out(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(nrm.buf); 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 Datum
querytree(PG_FUNCTION_ARGS) querytree(PG_FUNCTION_ARGS)
{ {
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0)); elog(ERROR, "querytree is no longer implemented");
INFIX nrm; PG_RETURN_NULL();
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);
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/gin.h"
#include "access/gist.h" #include "access/gist.h"
#include "access/skey.h" #include "access/skey.h"
...@@ -16,66 +17,90 @@ ginint4_queryextract(PG_FUNCTION_ARGS) ...@@ -16,66 +17,90 @@ ginint4_queryextract(PG_FUNCTION_ARGS)
{ {
int32 *nentries = (int32 *) PG_GETARG_POINTER(1); int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
StrategyNumber strategy = PG_GETARG_UINT16(2); StrategyNumber strategy = PG_GETARG_UINT16(2);
int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
Datum *res = NULL; Datum *res = NULL;
*nentries = 0; *nentries = 0;
if (strategy == BooleanSearchStrategy) 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); ITEM *items = GETQUERY(query);
int i; int i;
if (query->size == 0) /* empty query must fail */
if (query->size <= 0)
PG_RETURN_POINTER(NULL); PG_RETURN_POINTER(NULL);
if (shorterquery(items, query->size) == 0) /*
elog(ERROR, "Query requires full scan, GIN doesn't support it"); * If the query doesn't have any required primitive values (for
* instance, it's something like '! 42'), we have to do a full
pfree(query); * index scan.
*/
query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0)); if (query_has_required_values(query))
items = GETQUERY(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); res = (Datum *) palloc(sizeof(Datum) * query->size);
*nentries = 0; *nentries = 0;
for (i = 0; i < query->size; i++) for (i = 0; i < query->size; i++)
{
if (items[i].type == VAL) if (items[i].type == VAL)
{ {
res[*nentries] = Int32GetDatum(items[i].val); res[*nentries] = Int32GetDatum(items[i].val);
(*nentries)++; (*nentries)++;
} }
}
} }
else else
{ {
ArrayType *query = PG_GETARG_ARRAYTYPE_P(0); ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
int4 *arr;
uint32 i;
CHECKARRVALID(query); CHECKARRVALID(query);
*nentries = ARRNELEMS(query); *nentries = ARRNELEMS(query);
if (*nentries > 0) if (*nentries > 0)
{ {
int4 *arr;
int32 i;
res = (Datum *) palloc(sizeof(Datum) * (*nentries)); res = (Datum *) palloc(sizeof(Datum) * (*nentries));
arr = ARRPTR(query); arr = ARRPTR(query);
for (i = 0; i < *nentries; i++) for (i = 0; i < *nentries; i++)
res[i] = Int32GetDatum(arr[i]); res[i] = Int32GetDatum(arr[i]);
} }
}
if (*nentries == 0)
{
switch (strategy) switch (strategy)
{ {
case BooleanSearchStrategy:
case RTOverlapStrategyNumber: case RTOverlapStrategyNumber:
*nentries = -1; /* nobody can be found */ *searchMode = GIN_SEARCH_MODE_DEFAULT;
break;
case RTContainedByStrategyNumber:
case RTOldContainedByStrategyNumber:
/* empty set is contained in everything */
*searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
break; break;
default: /* require fullscan: GIN can't find void case RTSameStrategyNumber:
* arrays */ if (*nentries > 0)
*searchMode = GIN_SEARCH_MODE_DEFAULT;
else
*searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
break; 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) ...@@ -90,16 +115,11 @@ ginint4_consistent(PG_FUNCTION_ARGS)
{ {
bool *check = (bool *) PG_GETARG_POINTER(0); bool *check = (bool *) PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1); 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); */ /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
bool *recheck = (bool *) PG_GETARG_POINTER(5); bool *recheck = (bool *) PG_GETARG_POINTER(5);
bool res = FALSE; bool res = FALSE;
int32 i;
/*
* we need not check array carefully, it's done by previous
* ginarrayextract call
*/
switch (strategy) switch (strategy)
{ {
...@@ -117,47 +137,41 @@ ginint4_consistent(PG_FUNCTION_ARGS) ...@@ -117,47 +137,41 @@ ginint4_consistent(PG_FUNCTION_ARGS)
res = TRUE; res = TRUE;
break; break;
case RTSameStrategyNumber: 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); if (!check[i])
int i, {
nentries = ARRNELEMS(query); res = FALSE;
break;
/* we will need recheck */ }
*recheck = true;
res = TRUE;
for (i = 0; i < nentries; i++)
if (!check[i])
{
res = FALSE;
break;
}
} }
break; break;
case RTContainsStrategyNumber: case RTContainsStrategyNumber:
case RTOldContainsStrategyNumber: 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); if (!check[i])
int i, {
nentries = ARRNELEMS(query); res = FALSE;
break;
/* result is not lossy */ }
*recheck = false;
res = TRUE;
for (i = 0; i < nentries; i++)
if (!check[i])
{
res = FALSE;
break;
}
} }
break; break;
case BooleanSearchStrategy: case BooleanSearchStrategy:
{ {
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(2)); QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(2);
/* result is not lossy */ /* result is not lossy */
*recheck = false; *recheck = false;
res = ginconsistent(query, check); res = gin_bool_consistent(query, check);
} }
break; break;
default: default:
......
...@@ -40,7 +40,7 @@ Datum ...@@ -40,7 +40,7 @@ Datum
g_int_consistent(PG_FUNCTION_ARGS) g_int_consistent(PG_FUNCTION_ARGS)
{ {
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 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); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
/* Oid subtype = PG_GETARG_OID(3); */ /* Oid subtype = PG_GETARG_OID(3); */
...@@ -62,11 +62,6 @@ g_int_consistent(PG_FUNCTION_ARGS) ...@@ -62,11 +62,6 @@ g_int_consistent(PG_FUNCTION_ARGS)
/* sort query for fast search, key is already sorted */ /* sort query for fast search, key is already sorted */
CHECKARRVALID(query); CHECKARRVALID(query);
if (ARRISVOID(query))
{
pfree(query);
PG_RETURN_BOOL(false);
}
PREPAREARR(query); PREPAREARR(query);
switch (strategy) switch (strategy)
...@@ -77,12 +72,10 @@ g_int_consistent(PG_FUNCTION_ARGS) ...@@ -77,12 +72,10 @@ g_int_consistent(PG_FUNCTION_ARGS)
break; break;
case RTSameStrategyNumber: case RTSameStrategyNumber:
if (GIST_LEAF(entry)) if (GIST_LEAF(entry))
DirectFunctionCall3( DirectFunctionCall3(g_int_same,
g_int_same,
entry->key, entry->key,
PointerGetDatum(query), PointerGetDatum(query),
PointerGetDatum(&retval) PointerGetDatum(&retval));
);
else else
retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key), retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key),
query); query);
...@@ -162,7 +155,7 @@ g_int_compress(PG_FUNCTION_ARGS) ...@@ -162,7 +155,7 @@ g_int_compress(PG_FUNCTION_ARGS)
if (entry->leafkey) if (entry->leafkey)
{ {
r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key); r = DatumGetArrayTypePCopy(entry->key);
CHECKARRVALID(r); CHECKARRVALID(r);
PREPAREARR(r); PREPAREARR(r);
...@@ -182,9 +175,9 @@ g_int_compress(PG_FUNCTION_ARGS) ...@@ -182,9 +175,9 @@ g_int_compress(PG_FUNCTION_ARGS)
* ==true, so now we work only with internal keys * ==true, so now we work only with internal keys
*/ */
r = (ArrayType *) PG_DETOAST_DATUM(entry->key); r = DatumGetArrayTypeP(entry->key);
CHECKARRVALID(r); CHECKARRVALID(r);
if (ARRISVOID(r)) if (ARRISEMPTY(r))
{ {
if (r != (ArrayType *) DatumGetPointer(entry->key)) if (r != (ArrayType *) DatumGetPointer(entry->key))
pfree(r); pfree(r);
...@@ -194,7 +187,7 @@ g_int_compress(PG_FUNCTION_ARGS) ...@@ -194,7 +187,7 @@ g_int_compress(PG_FUNCTION_ARGS)
if ((len = ARRNELEMS(r)) >= 2 * MAXNUMRANGE) if ((len = ARRNELEMS(r)) >= 2 * MAXNUMRANGE)
{ /* compress */ { /* compress */
if (r == (ArrayType *) DatumGetPointer(entry->key)) if (r == (ArrayType *) DatumGetPointer(entry->key))
r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key); r = DatumGetArrayTypePCopy(entry->key);
r = resize_intArrayType(r, 2 * (len)); r = resize_intArrayType(r, 2 * (len));
dr = ARRPTR(r); dr = ARRPTR(r);
...@@ -242,10 +235,10 @@ g_int_decompress(PG_FUNCTION_ARGS) ...@@ -242,10 +235,10 @@ g_int_decompress(PG_FUNCTION_ARGS)
int i, int i,
j; j;
in = (ArrayType *) PG_DETOAST_DATUM(entry->key); in = DatumGetArrayTypeP(entry->key);
CHECKARRVALID(in); CHECKARRVALID(in);
if (ARRISVOID(in)) if (ARRISEMPTY(in))
{ {
if (in != (ArrayType *) DatumGetPointer(entry->key)) if (in != (ArrayType *) DatumGetPointer(entry->key))
{ {
...@@ -321,8 +314,8 @@ g_int_penalty(PG_FUNCTION_ARGS) ...@@ -321,8 +314,8 @@ g_int_penalty(PG_FUNCTION_ARGS)
Datum Datum
g_int_same(PG_FUNCTION_ARGS) g_int_same(PG_FUNCTION_ARGS)
{ {
ArrayType *a = (ArrayType *) PointerGetDatum(PG_GETARG_POINTER(0)); ArrayType *a = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *b = (ArrayType *) PointerGetDatum(PG_GETARG_POINTER(1)); ArrayType *b = PG_GETARG_ARRAYTYPE_P(1);
bool *result = (bool *) PG_GETARG_POINTER(2); bool *result = (bool *) PG_GETARG_POINTER(2);
int4 n = ARRNELEMS(a); int4 n = ARRNELEMS(a);
int4 *da, int4 *da,
...@@ -340,11 +333,13 @@ g_int_same(PG_FUNCTION_ARGS) ...@@ -340,11 +333,13 @@ g_int_same(PG_FUNCTION_ARGS)
da = ARRPTR(a); da = ARRPTR(a);
db = ARRPTR(b); db = ARRPTR(b);
while (n--) while (n--)
{
if (*da++ != *db++) if (*da++ != *db++)
{ {
*result = FALSE; *result = FALSE;
break; break;
} }
}
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
} }
......
...@@ -29,27 +29,22 @@ Datum _int_inter(PG_FUNCTION_ARGS); ...@@ -29,27 +29,22 @@ Datum _int_inter(PG_FUNCTION_ARGS);
Datum Datum
_int_contained(PG_FUNCTION_ARGS) _int_contained(PG_FUNCTION_ARGS)
{ {
PG_RETURN_BOOL(DatumGetBool( /* just reverse the operands and call _int_contains */
DirectFunctionCall2( return DirectFunctionCall2(_int_contains,
_int_contains, PG_GETARG_DATUM(1),
PointerGetDatum(PG_GETARG_POINTER(1)), PG_GETARG_DATUM(0));
PointerGetDatum(PG_GETARG_POINTER(0))
)
));
} }
Datum Datum
_int_contains(PG_FUNCTION_ARGS) _int_contains(PG_FUNCTION_ARGS)
{ {
ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); /* Force copy so we can modify the arrays in-place */
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 res; bool res;
CHECKARRVALID(a); CHECKARRVALID(a);
CHECKARRVALID(b); CHECKARRVALID(b);
if (ARRISVOID(a) || ARRISVOID(b))
return FALSE;
PREPAREARR(a); PREPAREARR(a);
PREPAREARR(b); PREPAREARR(b);
res = inner_int_contains(a, b); res = inner_int_contains(a, b);
...@@ -73,24 +68,17 @@ _int_different(PG_FUNCTION_ARGS) ...@@ -73,24 +68,17 @@ _int_different(PG_FUNCTION_ARGS)
Datum Datum
_int_same(PG_FUNCTION_ARGS) _int_same(PG_FUNCTION_ARGS)
{ {
ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1);
int na, int na,
nb; nb;
int n; int n;
int *da, int *da,
*db; *db;
bool result; bool result;
bool avoid;
bool bvoid;
CHECKARRVALID(a); CHECKARRVALID(a);
CHECKARRVALID(b); CHECKARRVALID(b);
avoid = ARRISVOID(a);
bvoid = ARRISVOID(b);
if (avoid || bvoid)
return (avoid && bvoid) ? TRUE : FALSE;
na = ARRNELEMS(a); na = ARRNELEMS(a);
nb = ARRNELEMS(b); nb = ARRNELEMS(b);
da = ARRPTR(a); da = ARRPTR(a);
...@@ -105,11 +93,13 @@ _int_same(PG_FUNCTION_ARGS) ...@@ -105,11 +93,13 @@ _int_same(PG_FUNCTION_ARGS)
result = TRUE; result = TRUE;
for (n = 0; n < na; n++) for (n = 0; n < na; n++)
{
if (da[n] != db[n]) if (da[n] != db[n])
{ {
result = FALSE; result = FALSE;
break; break;
} }
}
} }
pfree(a); pfree(a);
...@@ -123,13 +113,13 @@ _int_same(PG_FUNCTION_ARGS) ...@@ -123,13 +113,13 @@ _int_same(PG_FUNCTION_ARGS)
Datum Datum
_int_overlap(PG_FUNCTION_ARGS) _int_overlap(PG_FUNCTION_ARGS)
{ {
ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1);
bool result; bool result;
CHECKARRVALID(a); CHECKARRVALID(a);
CHECKARRVALID(b); CHECKARRVALID(b);
if (ARRISVOID(a) || ARRISVOID(b)) if (ARRISEMPTY(a) || ARRISEMPTY(b))
return FALSE; return FALSE;
SORT(a); SORT(a);
...@@ -146,24 +136,20 @@ _int_overlap(PG_FUNCTION_ARGS) ...@@ -146,24 +136,20 @@ _int_overlap(PG_FUNCTION_ARGS)
Datum Datum
_int_union(PG_FUNCTION_ARGS) _int_union(PG_FUNCTION_ARGS)
{ {
ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1);
ArrayType *result; ArrayType *result;
CHECKARRVALID(a); CHECKARRVALID(a);
CHECKARRVALID(b); CHECKARRVALID(b);
if (!ARRISVOID(a)) SORT(a);
SORT(a); SORT(b);
if (!ARRISVOID(b))
SORT(b);
result = inner_int_union(a, b); result = inner_int_union(a, b);
if (a) pfree(a);
pfree(a); pfree(b);
if (b)
pfree(b);
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
} }
...@@ -171,14 +157,12 @@ _int_union(PG_FUNCTION_ARGS) ...@@ -171,14 +157,12 @@ _int_union(PG_FUNCTION_ARGS)
Datum Datum
_int_inter(PG_FUNCTION_ARGS) _int_inter(PG_FUNCTION_ARGS)
{ {
ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1);
ArrayType *result; ArrayType *result;
CHECKARRVALID(a); CHECKARRVALID(a);
CHECKARRVALID(b); CHECKARRVALID(b);
if (ARRISVOID(a) || ARRISVOID(b))
PG_RETURN_POINTER(new_intArrayType(0));
SORT(a); SORT(a);
SORT(b); SORT(b);
...@@ -228,7 +212,7 @@ intset(PG_FUNCTION_ARGS) ...@@ -228,7 +212,7 @@ intset(PG_FUNCTION_ARGS)
Datum Datum
icount(PG_FUNCTION_ARGS) 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); int32 count = ARRNELEMS(a);
PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(a, 0);
...@@ -238,14 +222,14 @@ icount(PG_FUNCTION_ARGS) ...@@ -238,14 +222,14 @@ icount(PG_FUNCTION_ARGS)
Datum Datum
sort(PG_FUNCTION_ARGS) 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; text *dirstr = (fcinfo->nargs == 2) ? PG_GETARG_TEXT_P(1) : NULL;
int32 dc = (dirstr) ? VARSIZE(dirstr) - VARHDRSZ : 0; int32 dc = (dirstr) ? VARSIZE(dirstr) - VARHDRSZ : 0;
char *d = (dirstr) ? VARDATA(dirstr) : NULL; char *d = (dirstr) ? VARDATA(dirstr) : NULL;
int dir = -1; int dir = -1;
CHECKARRVALID(a); CHECKARRVALID(a);
if (ARRISVOID(a) || ARRNELEMS(a) < 2) if (ARRNELEMS(a) < 2)
PG_RETURN_POINTER(a); PG_RETURN_POINTER(a);
if (dirstr == NULL || (dc == 3 if (dirstr == NULL || (dc == 3
...@@ -270,11 +254,9 @@ sort(PG_FUNCTION_ARGS) ...@@ -270,11 +254,9 @@ sort(PG_FUNCTION_ARGS)
Datum Datum
sort_asc(PG_FUNCTION_ARGS) 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); CHECKARRVALID(a);
if (ARRISVOID(a))
PG_RETURN_POINTER(a);
QSORT(a, 1); QSORT(a, 1);
PG_RETURN_POINTER(a); PG_RETURN_POINTER(a);
} }
...@@ -282,11 +264,9 @@ sort_asc(PG_FUNCTION_ARGS) ...@@ -282,11 +264,9 @@ sort_asc(PG_FUNCTION_ARGS)
Datum Datum
sort_desc(PG_FUNCTION_ARGS) 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); CHECKARRVALID(a);
if (ARRISVOID(a))
PG_RETURN_POINTER(a);
QSORT(a, 0); QSORT(a, 0);
PG_RETURN_POINTER(a); PG_RETURN_POINTER(a);
} }
...@@ -294,10 +274,10 @@ sort_desc(PG_FUNCTION_ARGS) ...@@ -294,10 +274,10 @@ sort_desc(PG_FUNCTION_ARGS)
Datum Datum
uniq(PG_FUNCTION_ARGS) 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); CHECKARRVALID(a);
if (ARRISVOID(a) || ARRNELEMS(a) < 2) if (ARRNELEMS(a) < 2)
PG_RETURN_POINTER(a); PG_RETURN_POINTER(a);
a = _int_unique(a); a = _int_unique(a);
PG_RETURN_POINTER(a); PG_RETURN_POINTER(a);
...@@ -306,11 +286,11 @@ uniq(PG_FUNCTION_ARGS) ...@@ -306,11 +286,11 @@ uniq(PG_FUNCTION_ARGS)
Datum Datum
idx(PG_FUNCTION_ARGS) idx(PG_FUNCTION_ARGS)
{ {
ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); ArrayType *a = PG_GETARG_ARRAYTYPE_P(0);
int32 result; int32 result;
CHECKARRVALID(a); CHECKARRVALID(a);
result = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); result = ARRNELEMS(a);
if (result) if (result)
result = intarray_match_first(a, PG_GETARG_INT32(1)); result = intarray_match_first(a, PG_GETARG_INT32(1));
PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(a, 0);
...@@ -320,15 +300,17 @@ idx(PG_FUNCTION_ARGS) ...@@ -320,15 +300,17 @@ idx(PG_FUNCTION_ARGS)
Datum Datum
subarray(PG_FUNCTION_ARGS) subarray(PG_FUNCTION_ARGS)
{ {
ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); ArrayType *a = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *result; int32 start = PG_GETARG_INT32(1);
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 len = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
int32 end = 0; int32 end = 0;
int32 c; int32 c;
ArrayType *result;
start = (start > 0) ? start - 1 : start;
CHECKARRVALID(a); CHECKARRVALID(a);
if (ARRISVOID(a)) if (ARRISEMPTY(a))
{ {
PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(a, 0);
PG_RETURN_POINTER(new_intArrayType(0)); PG_RETURN_POINTER(new_intArrayType(0));
...@@ -358,7 +340,6 @@ subarray(PG_FUNCTION_ARGS) ...@@ -358,7 +340,6 @@ subarray(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(new_intArrayType(0)); PG_RETURN_POINTER(new_intArrayType(0));
} }
result = new_intArrayType(end - start); result = new_intArrayType(end - start);
if (end - start > 0) if (end - start > 0)
memcpy(ARRPTR(result), ARRPTR(a) + start, (end - start) * sizeof(int32)); memcpy(ARRPTR(result), ARRPTR(a) + start, (end - start) * sizeof(int32));
...@@ -369,7 +350,7 @@ subarray(PG_FUNCTION_ARGS) ...@@ -369,7 +350,7 @@ subarray(PG_FUNCTION_ARGS)
Datum Datum
intarray_push_elem(PG_FUNCTION_ARGS) 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; ArrayType *result;
result = intarray_add_elem(a, PG_GETARG_INT32(1)); result = intarray_add_elem(a, PG_GETARG_INT32(1));
...@@ -380,8 +361,8 @@ intarray_push_elem(PG_FUNCTION_ARGS) ...@@ -380,8 +361,8 @@ intarray_push_elem(PG_FUNCTION_ARGS)
Datum Datum
intarray_push_array(PG_FUNCTION_ARGS) intarray_push_array(PG_FUNCTION_ARGS)
{ {
ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); ArrayType *a = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1))); ArrayType *b = PG_GETARG_ARRAYTYPE_P(1);
ArrayType *result; ArrayType *result;
result = intarray_concat_arrays(a, b); result = intarray_concat_arrays(a, b);
...@@ -393,7 +374,7 @@ intarray_push_array(PG_FUNCTION_ARGS) ...@@ -393,7 +374,7 @@ intarray_push_array(PG_FUNCTION_ARGS)
Datum Datum
intarray_del_elem(PG_FUNCTION_ARGS) 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 elem = PG_GETARG_INT32(1);
int32 c; int32 c;
int32 *aa; int32 *aa;
...@@ -401,7 +382,7 @@ intarray_del_elem(PG_FUNCTION_ARGS) ...@@ -401,7 +382,7 @@ intarray_del_elem(PG_FUNCTION_ARGS)
i; i;
CHECKARRVALID(a); CHECKARRVALID(a);
if (!ARRISVOID(a)) if (!ARRISEMPTY(a))
{ {
c = ARRNELEMS(a); c = ARRNELEMS(a);
aa = ARRPTR(a); aa = ARRPTR(a);
...@@ -423,7 +404,7 @@ intarray_del_elem(PG_FUNCTION_ARGS) ...@@ -423,7 +404,7 @@ intarray_del_elem(PG_FUNCTION_ARGS)
Datum Datum
intset_union_elem(PG_FUNCTION_ARGS) 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; ArrayType *result;
result = intarray_add_elem(a, PG_GETARG_INT32(1)); result = intarray_add_elem(a, PG_GETARG_INT32(1));
...@@ -435,8 +416,8 @@ intset_union_elem(PG_FUNCTION_ARGS) ...@@ -435,8 +416,8 @@ intset_union_elem(PG_FUNCTION_ARGS)
Datum Datum
intset_subtract(PG_FUNCTION_ARGS) intset_subtract(PG_FUNCTION_ARGS)
{ {
ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
ArrayType *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1))); ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1);
ArrayType *result; ArrayType *result;
int32 ca; int32 ca;
int32 cb; int32 cb;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "_int.h" #include "_int.h"
/* arguments are assumed sorted & unique-ified */
bool bool
inner_int_contains(ArrayType *a, ArrayType *b) inner_int_contains(ArrayType *a, ArrayType *b)
{ {
...@@ -19,12 +20,6 @@ inner_int_contains(ArrayType *a, ArrayType *b) ...@@ -19,12 +20,6 @@ inner_int_contains(ArrayType *a, ArrayType *b)
int *da, int *da,
*db; *db;
CHECKARRVALID(a);
CHECKARRVALID(b);
if (ARRISVOID(a) || ARRISVOID(b))
return FALSE;
na = ARRNELEMS(a); na = ARRNELEMS(a);
nb = ARRNELEMS(b); nb = ARRNELEMS(b);
da = ARRPTR(a); da = ARRPTR(a);
...@@ -32,6 +27,7 @@ inner_int_contains(ArrayType *a, ArrayType *b) ...@@ -32,6 +27,7 @@ inner_int_contains(ArrayType *a, ArrayType *b)
i = j = n = 0; i = j = n = 0;
while (i < na && j < nb) while (i < na && j < nb)
{
if (da[i] < db[j]) if (da[i] < db[j])
i++; i++;
else if (da[i] == db[j]) else if (da[i] == db[j])
...@@ -41,11 +37,13 @@ inner_int_contains(ArrayType *a, ArrayType *b) ...@@ -41,11 +37,13 @@ inner_int_contains(ArrayType *a, ArrayType *b)
j++; j++;
} }
else else
break; break; /* db[j] is not in da */
}
return (n == nb) ? TRUE : FALSE; return (n == nb) ? TRUE : FALSE;
} }
/* arguments are assumed sorted */
bool bool
inner_int_overlap(ArrayType *a, ArrayType *b) inner_int_overlap(ArrayType *a, ArrayType *b)
{ {
...@@ -56,12 +54,6 @@ inner_int_overlap(ArrayType *a, ArrayType *b) ...@@ -56,12 +54,6 @@ inner_int_overlap(ArrayType *a, ArrayType *b)
int *da, int *da,
*db; *db;
CHECKARRVALID(a);
CHECKARRVALID(b);
if (ARRISVOID(a) || ARRISVOID(b))
return FALSE;
na = ARRNELEMS(a); na = ARRNELEMS(a);
nb = ARRNELEMS(b); nb = ARRNELEMS(b);
da = ARRPTR(a); da = ARRPTR(a);
...@@ -69,12 +61,14 @@ inner_int_overlap(ArrayType *a, ArrayType *b) ...@@ -69,12 +61,14 @@ inner_int_overlap(ArrayType *a, ArrayType *b)
i = j = 0; i = j = 0;
while (i < na && j < nb) while (i < na && j < nb)
{
if (da[i] < db[j]) if (da[i] < db[j])
i++; i++;
else if (da[i] == db[j]) else if (da[i] == db[j])
return TRUE; return TRUE;
else else
j++; j++;
}
return FALSE; return FALSE;
} }
...@@ -87,11 +81,11 @@ inner_int_union(ArrayType *a, ArrayType *b) ...@@ -87,11 +81,11 @@ inner_int_union(ArrayType *a, ArrayType *b)
CHECKARRVALID(a); CHECKARRVALID(a);
CHECKARRVALID(b); CHECKARRVALID(b);
if (ARRISVOID(a) && ARRISVOID(b)) if (ARRISEMPTY(a) && ARRISEMPTY(b))
return new_intArrayType(0); return new_intArrayType(0);
if (ARRISVOID(a)) if (ARRISEMPTY(a))
r = copy_intArrayType(b); r = copy_intArrayType(b);
if (ARRISVOID(b)) if (ARRISEMPTY(b))
r = copy_intArrayType(a); r = copy_intArrayType(a);
if (!r) if (!r)
...@@ -148,10 +142,7 @@ inner_int_inter(ArrayType *a, ArrayType *b) ...@@ -148,10 +142,7 @@ inner_int_inter(ArrayType *a, ArrayType *b)
int i, int i,
j; j;
CHECKARRVALID(a); if (ARRISEMPTY(a) || ARRISEMPTY(b))
CHECKARRVALID(b);
if (ARRISVOID(a) || ARRISVOID(b))
return new_intArrayType(0); return new_intArrayType(0);
na = ARRNELEMS(a); na = ARRNELEMS(a);
...@@ -163,6 +154,7 @@ inner_int_inter(ArrayType *a, ArrayType *b) ...@@ -163,6 +154,7 @@ inner_int_inter(ArrayType *a, ArrayType *b)
i = j = 0; i = j = 0;
while (i < na && j < nb) while (i < na && j < nb)
{
if (da[i] < db[j]) if (da[i] < db[j])
i++; i++;
else if (da[i] == db[j]) else if (da[i] == db[j])
...@@ -174,6 +166,7 @@ inner_int_inter(ArrayType *a, ArrayType *b) ...@@ -174,6 +166,7 @@ inner_int_inter(ArrayType *a, ArrayType *b)
} }
else else
j++; j++;
}
if ((dr - ARRPTR(r)) == 0) if ((dr - ARRPTR(r)) == 0)
{ {
...@@ -188,57 +181,60 @@ void ...@@ -188,57 +181,60 @@ void
rt__int_size(ArrayType *a, float *size) rt__int_size(ArrayType *a, float *size)
{ {
*size = (float) ARRNELEMS(a); *size = (float) ARRNELEMS(a);
return;
} }
/* Sort the given data (len >= 2). Return true if any duplicates found */
/* len >= 2 */
bool bool
isort(int4 *a, int len) isort(int4 *a, int len)
{ {
int4 tmp, int4 cur,
index; prev;
int4 *cur, int4 *pcur,
*pprev,
*end; *end;
bool r = FALSE; 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; end = a + len;
do for (pcur = a + 1; pcur < end; pcur++)
{ {
index = 0; cur = *pcur;
cur = a + 1; for (pprev = pcur - 1; pprev >= a; pprev--)
while (cur < end)
{ {
if (*(cur - 1) > *cur) prev = *pprev;
if (prev <= cur)
{ {
tmp = *(cur - 1); if (prev == cur)
*(cur - 1) = *cur; r = TRUE;
*cur = tmp; break;
index = 1;
} }
else if (!r && *(cur - 1) == *cur) pprev[1] = prev;
r = TRUE;
cur++;
} }
} while (index); pprev[1] = cur;
}
return r; return r;
} }
/* Create a new int array with room for "num" elements */
ArrayType * ArrayType *
new_intArrayType(int num) new_intArrayType(int num)
{ {
ArrayType *r; ArrayType *r;
int nbytes = ARR_OVERHEAD_NONULLS(NDIM) + sizeof(int) * num; int nbytes = ARR_OVERHEAD_NONULLS(1) + sizeof(int) * num;
r = (ArrayType *) palloc0(nbytes); r = (ArrayType *) palloc0(nbytes);
SET_VARSIZE(r, nbytes); SET_VARSIZE(r, nbytes);
ARR_NDIM(r) = NDIM; ARR_NDIM(r) = 1;
r->dataoffset = 0; /* marker for no null bitmap */ r->dataoffset = 0; /* marker for no null bitmap */
ARR_ELEMTYPE(r) = INT4OID; ARR_ELEMTYPE(r) = INT4OID;
*((int *) ARR_DIMS(r)) = num; ARR_DIMS(r)[0] = num;
*((int *) ARR_LBOUND(r)) = 1; ARR_LBOUND(r)[0] = 1;
return r; return r;
} }
...@@ -246,7 +242,8 @@ new_intArrayType(int num) ...@@ -246,7 +242,8 @@ new_intArrayType(int num)
ArrayType * ArrayType *
resize_intArrayType(ArrayType *a, int num) 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)) if (num == ARRNELEMS(a))
return a; return a;
...@@ -254,7 +251,12 @@ resize_intArrayType(ArrayType *a, int num) ...@@ -254,7 +251,12 @@ resize_intArrayType(ArrayType *a, int num)
a = (ArrayType *) repalloc(a, nbytes); a = (ArrayType *) repalloc(a, nbytes);
SET_VARSIZE(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; return a;
} }
...@@ -262,9 +264,10 @@ ArrayType * ...@@ -262,9 +264,10 @@ ArrayType *
copy_intArrayType(ArrayType *a) copy_intArrayType(ArrayType *a)
{ {
ArrayType *r; ArrayType *r;
int n = ARRNELEMS(a);
r = new_intArrayType(ARRNELEMS(a)); r = new_intArrayType(n);
memmove(r, a, VARSIZE(r)); memcpy(ARRPTR(r), ARRPTR(a), n * sizeof(int4));
return r; return r;
} }
...@@ -276,13 +279,15 @@ internal_size(int *a, int len) ...@@ -276,13 +279,15 @@ internal_size(int *a, int len)
size = 0; size = 0;
for (i = 0; i < len; i += 2) for (i = 0; i < len; i += 2)
{
if (!i || a[i] != a[i - 1]) /* do not count repeated range */ if (!i || a[i] != a[i - 1]) /* do not count repeated range */
size += a[i + 1] - a[i] + 1; size += a[i + 1] - a[i] + 1;
}
return size; return size;
} }
/* r is sorted and size of r > 1 */ /* unique-ify elements of r in-place ... r must be sorted already */
ArrayType * ArrayType *
_int_unique(ArrayType *r) _int_unique(ArrayType *r)
{ {
...@@ -291,17 +296,17 @@ _int_unique(ArrayType *r) ...@@ -291,17 +296,17 @@ _int_unique(ArrayType *r)
*data; *data;
int num = ARRNELEMS(r); int num = ARRNELEMS(r);
CHECKARRVALID(r);
if (num < 2) if (num < 2)
return r; return r;
data = tmp = dr = ARRPTR(r); data = tmp = dr = ARRPTR(r);
while (tmp - data < num) while (tmp - data < num)
{
if (*tmp != *dr) if (*tmp != *dr)
*(++dr) = *tmp++; *(++dr) = *tmp++;
else else
tmp++; tmp++;
}
return resize_intArrayType(r, dr + 1 - ARRPTR(r)); return resize_intArrayType(r, dr + 1 - ARRPTR(r));
} }
...@@ -326,8 +331,6 @@ intarray_match_first(ArrayType *a, int32 elem) ...@@ -326,8 +331,6 @@ intarray_match_first(ArrayType *a, int32 elem)
i; i;
CHECKARRVALID(a); CHECKARRVALID(a);
if (ARRISVOID(a))
return 0;
c = ARRNELEMS(a); c = ARRNELEMS(a);
aa = ARRPTR(a); aa = ARRPTR(a);
for (i = 0; i < c; i++) for (i = 0; i < c; i++)
...@@ -344,7 +347,7 @@ intarray_add_elem(ArrayType *a, int32 elem) ...@@ -344,7 +347,7 @@ intarray_add_elem(ArrayType *a, int32 elem)
int32 c; int32 c;
CHECKARRVALID(a); CHECKARRVALID(a);
c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); c = ARRNELEMS(a);
result = new_intArrayType(c + 1); result = new_intArrayType(c + 1);
r = ARRPTR(result); r = ARRPTR(result);
if (c > 0) if (c > 0)
...@@ -357,8 +360,8 @@ ArrayType * ...@@ -357,8 +360,8 @@ ArrayType *
intarray_concat_arrays(ArrayType *a, ArrayType *b) intarray_concat_arrays(ArrayType *a, ArrayType *b)
{ {
ArrayType *result; ArrayType *result;
int32 ac = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); int32 ac = ARRNELEMS(a);
int32 bc = (ARRISVOID(b)) ? 0 : ARRNELEMS(b); int32 bc = ARRNELEMS(b);
CHECKARRVALID(a); CHECKARRVALID(a);
CHECKARRVALID(b); CHECKARRVALID(b);
......
...@@ -153,13 +153,13 @@ g_intbig_compress(PG_FUNCTION_ARGS) ...@@ -153,13 +153,13 @@ g_intbig_compress(PG_FUNCTION_ARGS)
if (entry->leafkey) if (entry->leafkey)
{ {
GISTENTRY *retval; GISTENTRY *retval;
ArrayType *in = (ArrayType *) PG_DETOAST_DATUM(entry->key); ArrayType *in = DatumGetArrayTypeP(entry->key);
int4 *ptr; int4 *ptr;
int num; int num;
GISTTYPE *res = (GISTTYPE *) palloc0(CALCGTSIZE(0)); GISTTYPE *res = (GISTTYPE *) palloc0(CALCGTSIZE(0));
CHECKARRVALID(in); CHECKARRVALID(in);
if (ARRISVOID(in)) if (ARRISEMPTY(in))
{ {
ptr = NULL; ptr = NULL;
num = 0; num = 0;
...@@ -182,7 +182,7 @@ g_intbig_compress(PG_FUNCTION_ARGS) ...@@ -182,7 +182,7 @@ g_intbig_compress(PG_FUNCTION_ARGS)
entry->rel, entry->page, entry->rel, entry->page,
entry->offset, FALSE); entry->offset, FALSE);
if (in != (ArrayType *) PG_DETOAST_DATUM(entry->key)) if (in != DatumGetArrayTypeP(entry->key))
pfree(in); pfree(in);
PG_RETURN_POINTER(retval); PG_RETURN_POINTER(retval);
...@@ -504,7 +504,7 @@ Datum ...@@ -504,7 +504,7 @@ Datum
g_intbig_consistent(PG_FUNCTION_ARGS) g_intbig_consistent(PG_FUNCTION_ARGS)
{ {
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 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); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
/* Oid subtype = PG_GETARG_OID(3); */ /* Oid subtype = PG_GETARG_OID(3); */
...@@ -527,11 +527,6 @@ g_intbig_consistent(PG_FUNCTION_ARGS) ...@@ -527,11 +527,6 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
} }
CHECKARRVALID(query); CHECKARRVALID(query);
if (ARRISVOID(query))
{
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(FALSE);
}
switch (strategy) switch (strategy)
{ {
...@@ -548,8 +543,6 @@ g_intbig_consistent(PG_FUNCTION_ARGS) ...@@ -548,8 +543,6 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
BITVECP dq, BITVECP dq,
de; de;
CHECKARRVALID(query);
memset(qp, 0, sizeof(BITVEC)); memset(qp, 0, sizeof(BITVEC));
while (num--) while (num--)
...@@ -589,8 +582,6 @@ g_intbig_consistent(PG_FUNCTION_ARGS) ...@@ -589,8 +582,6 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
BITVECP dq, BITVECP dq,
de; de;
CHECKARRVALID(query);
memset(qp, 0, sizeof(BITVEC)); memset(qp, 0, sizeof(BITVEC));
while (num--) while (num--)
......
...@@ -5,9 +5,9 @@ SET search_path = public; ...@@ -5,9 +5,9 @@ SET search_path = public;
DROP OPERATOR CLASS gin__int_ops USING gin; 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; DROP OPERATOR CLASS gist__intbig_ops USING gist;
......
...@@ -9,10 +9,21 @@ ...@@ -9,10 +9,21 @@
<para> <para>
The <filename>intarray</> module provides a number of useful functions The <filename>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. There is also support for indexed searches using some of the operators.
</para> </para>
<para>
All of these operations will throw an error if a supplied array contains any
NULL elements.
</para>
<para>
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.
</para>
<sect2> <sect2>
<title><filename>intarray</> Functions and Operators</title> <title><filename>intarray</> Functions and Operators</title>
...@@ -211,14 +222,12 @@ ...@@ -211,14 +222,12 @@
</para> </para>
<para> <para>
The containment operators <literal>@&gt;</> and <literal>&lt;@</> are The operators <literal>&amp;&amp;</>, <literal>@&gt;</> and
approximately equivalent to <productname>PostgreSQL</>'s built-in operators <literal>&lt;@</> are equivalent to <productname>PostgreSQL</>'s built-in
of the same names, except that they work only on integer arrays while the operators of the same names, except that they work only on integer arrays
built-in operators work for any array type. An important difference is that do not contain nulls, while the built-in operators work for any array
that <filename>intarray</>'s operators do not consider an empty array to be type. This restriction makes them faster than the built-in operators
contained in anything else. This is consistent with the behavior of in many cases.
GIN-indexed queries, but not with the usual mathematical definition of
containment.
</para> </para>
<para> <para>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment