]> granicus.if.org Git - postgresql/commitdiff
Fix assorted corner-case bugs in contrib/intarray.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 9 Jan 2011 05:39:21 +0000 (00:39 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 9 Jan 2011 05:39:21 +0000 (00:39 -0500)
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.

contrib/intarray/_int.h
contrib/intarray/_int_bool.c
contrib/intarray/_int_gin.c
contrib/intarray/_int_gist.c
contrib/intarray/_int_op.c
contrib/intarray/_int_tool.c
contrib/intarray/_intbig_gist.c
contrib/intarray/uninstall__int.sql
doc/src/sgml/intarray.sgml

index dd50b37d2ea6a93b6796e3619706bdbc2eb05d10..11c069890eafb77f0746a5de11b0fad765f9134d 100644 (file)
@@ -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);
 
-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);
 
-#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__ */
index 4cc447bab2d0f943e67d045932e1a4421625f039..3492100c0c2f9590f403660c86aedbfc17d686f9 100644 (file)
@@ -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();
 }
index b5ad69eba35f221a6e8010e34389bd1fdd1964e3..3ef5c4635a150b94a90651a375e1e523ee9f78cd 100644 (file)
@@ -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;
+                       case RTContainedByStrategyNumber:
+                       case RTOldContainedByStrategyNumber:
+                               /* empty set is contained in everything */
+                               *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
                                break;
-                       default:                        /* require fullscan: GIN can't find void
-                                                                * arrays */
+                       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:
index 65c9bf2e74bf10408a14e833a4df93d8eacad0c7..0a173bfcb66cac57f63f1b866112c38141e8b541 100644 (file)
@@ -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);
 }
index 1d99c6905ef45c1291b041573222f808bb72dcf9..392e227cff82f69519c57fe8cef159974fa8927d 100644 (file)
@@ -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;
index 8093103ba46e562ffbe0aca7e0781233902fd7f4..ddf07f042b24140a51f2311099c4accfae26e1f4 100644 (file)
@@ -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);
index d9557a6b11ad2fea17f461ea289b1c26703a8647..eb8f2826349a7e9ec0546a926d1e26753aa454c8 100644 (file)
@@ -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--)
index 5cda23fdad11ad1f89e89c38f2c45dd24ea5aae3..345ad4464bd3fadef3378ae473d8ade4b880ef73 100644 (file)
@@ -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;
 
index 1cf72a12010298834f6a0d81d1bfbb3c7e7f53c3..449878d671645854bd7e6c1269fa2ac583fd9b34 100644 (file)
@@ -9,10 +9,21 @@
 
  <para>
   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.
  </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>
   <title><filename>intarray</> Functions and Operators</title>
 
   </para>
 
   <para>
-   The containment operators <literal>@&gt;</> and <literal>&lt;@</> are
-   approximately equivalent to <productname>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 <filename>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 <literal>&amp;&amp;</>, <literal>@&gt;</> and
+   <literal>&lt;@</> are equivalent to <productname>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.
   </para>
 
   <para>