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