While looking at the GIN's partial match logic, I got an idea to let the generic
index code do what opclass-specific comparePartial() functions do. It can be
achieved if range type is accepted as key entry.

In this patch I add ANYRANGEARRAY pseudotype (note that changes in
parse_coerce.c are rather ad hoc so far) and a set of cross-type operators like

        ANYARRAY @> ANYRANGEARRAY

The semantics is that the range array is contained in the array iff each range
element has a matching (non-range) element in the left array. For example:


postgres=# SELECT ARRAY[-2, 5, 0.1, 10]::numeric[] @> ARRAY['[-10,-1]',
'[7,10]']::numrange[];
 ?column?
----------
 t
(1 row)

postgres=# SELECT ARRAY[-2, 5, 0.1, 10]::numeric[] @> ARRAY['[-10,-1]',
'[7,10)']::numrange[];
 ?column?
----------
 f
(1 row)

The other operators also correspond to those (ANYARRAY, ANYARRAY), except that
array elements are matched using
        ANYRANGE @> ANYELEMENT

The patch just adds the matching logic to GIN. It does not remove the original
partial match because text search depends on it.


Subtopic: GIN and cross-type operators
--------------------------------------

So far all the in-core operators in the GIN's opfamilies have oprleft equal to
oprright. When I tried to implement the (ANYARRAY, ANYRANGEARRAY) operators I
had to do some changes in the core code:

1. While GIN_COMPARE_PROC and GIN_EXTRACTVALUE_PROC support functions depend on
pg_opclass(opckeytype) and pg_opclass(opcintype) respectively (and thus are
universial for the whole opclass), the other ones can be specific for
pg_amproc(amproclefttype, amprocrighttype). That's why I moved some code from
ginbeginscan() to ginrescan().

(I think it'd make sense to only store GIN_COMPARE_PROC and
GIN_EXTRACTVALUE_PROC once per opclass, but that would require changes in CREATE
OPERATOR CLASS command.)

2. To let the GIN code find the appropriate support functions for cross-type
operators, I had to ensure that scan key's sk_subtype contains OID of particular
type as opposed to that of the pseudotype.


Is there any misconception in this patch proposal?

// Antonin Houska (Tony)


diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c
index cb17d38..9e1c665 100644
--- a/src/backend/access/gin/ginget.c
+++ b/src/backend/access/gin/ginget.c
@@ -194,7 +194,7 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack,
 	/* Initialize empty bitmap result */
 	scanEntry->matchBitmap = tbm_create(work_mem * 1024L);
 
-	/* Null query cannot partial-match anything */
+	/* Null query cannot partial/range-match anything */
 	if (scanEntry->isPartialMatch &&
 		scanEntry->queryCategory != GIN_CAT_NORM_KEY)
 		return true;
@@ -263,8 +263,34 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack,
 				stack->off++;
 				continue;
 			}
-		}
-		else if (scanEntry->searchMode == GIN_SEARCH_MODE_ALL)
+		} else if (scanEntry->isRange) {
+			int32		cmp;
+			Datum	lower = scanEntry->rangeLower.val;
+			bool	lowerIncl = scanEntry->rangeLower.inclusive;
+			Datum	upper = scanEntry->rangeUpper.val;
+			bool	upperIncl = scanEntry->rangeUpper.inclusive;
+
+			cmp = DatumGetInt32(FunctionCall2Coll(&btree->ginstate->compareFn[attnum - 1],
+					btree->ginstate->supportCollation[attnum - 1],
+					idatum, lower));
+
+			if ((lowerIncl && cmp < 0) || (!lowerIncl && cmp <= 0)) {
+				/* Matching idatum not reached yet. */
+				stack->off++;
+				continue;
+			}
+
+			cmp = DatumGetInt32(FunctionCall2Coll(&btree->ginstate->compareFn[attnum - 1],
+					btree->ginstate->supportCollation[attnum - 1],
+					idatum, upper));
+
+			if ((upperIncl && cmp > 0) || (!upperIncl && cmp >= 0))
+				/*
+				 * We're past the upper bound, no more matches
+				 * for the current range.
+				 */
+				return true;
+		} else if (scanEntry->searchMode == GIN_SEARCH_MODE_ALL)
 		{
 			/*
 			 * In ALL mode, we are not interested in null items, so we can
@@ -392,7 +418,7 @@ restartScanEntry:
 
 	entry->isFinished = TRUE;
 
-	if (entry->isPartialMatch ||
+	if (entry->isPartialMatch || entry->isRange ||
 		entry->queryCategory == GIN_CAT_EMPTY_QUERY)
 	{
 		/*
@@ -1531,7 +1557,11 @@ gingetbitmap(PG_FUNCTION_ARGS)
 	 * to scan the main index before the pending list, since concurrent
 	 * cleanup could then make us miss entries entirely.
 	 */
-	scanPendingInsert(scan, tbm, &ntids);
+	/*
+	 * TODO
+	 * enable when the match logic is adjusted.
+	 */
+	//scanPendingInsert(scan, tbm, &ntids);
 
 	/*
 	 * Now scan the main index.
diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c
index afee2db..b085f75 100644
--- a/src/backend/access/gin/ginscan.c
+++ b/src/backend/access/gin/ginscan.c
@@ -17,6 +17,7 @@
 #include "access/gin_private.h"
 #include "access/relscan.h"
 #include "pgstat.h"
+#include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
@@ -59,11 +60,98 @@ static GinScanEntry
 ginFillScanEntry(GinScanOpaque so, OffsetNumber attnum,
 				 StrategyNumber strategy, int32 searchMode,
 				 Datum queryKey, GinNullCategory queryCategory,
-				 bool isPartialMatch, Pointer extra_data)
+				 bool isPartialMatch, bool isRange, Pointer extra_data)
 {
 	GinState   *ginstate = &so->ginstate;
 	GinScanEntry scanEntry;
 	uint32		i;
+	RangeBound boundLower, boundUpper;
+
+	/*
+	 * TODO
+	 * Load FmgrInfo for all the range functions as soon as we
+	 * hit the first range entry and stop calling those functions
+	 * by Oid (anywhere in the patch).
+	 */
+
+	/*
+	 * Neither NULL nor empty range can match anything - treat it as a NULL
+	 * query.
+	 *
+	 * We should eliminate the empty ranges here, before looking for an
+	 * existing entry. There might be many empty but distinct ranges and
+	 * we don't want to create a separate entry for each.
+	 */
+	if (isRange)
+	{
+		Assert(queryCategory == GIN_CAT_NORM_KEY ||
+			queryCategory == GIN_CAT_NULL_KEY);
+
+		if (queryCategory == GIN_CAT_NORM_KEY) {
+			/* range_empty() */
+			if (DatumGetBool(OidFunctionCall1(3850, queryKey))) {
+				queryCategory = GIN_CAT_NULL_KEY;
+			}
+		}
+
+		if (queryCategory == GIN_CAT_NULL_KEY) {
+			isRange = false;
+			/* This shouldn't be necessary, anyway ... */
+			queryKey = (Datum) 0;
+		}
+	}
+
+	/* Extract attributes of the ranges, we may need them many times. */
+	if (isRange) {
+		/* Probably not necessary, but setting them doesn't hurt. */
+		boundLower.lower = true;
+		boundUpper.lower = false;
+
+		/* range_lower_inf() */
+		boundLower.infinite = DatumGetBool(OidFunctionCall1(3853, queryKey));
+		/* range_lower_inc() */
+		boundLower.inclusive = DatumGetBool(OidFunctionCall1(3851, queryKey));
+		/* range_lower() */
+		boundLower.val = OidFunctionCall1(3848, queryKey);
+
+		/* range_upper_inf() */
+		boundUpper.infinite = DatumGetBool(OidFunctionCall1(3854, queryKey));
+		/* range_upper_inc() */
+		boundUpper.inclusive = DatumGetBool(OidFunctionCall1(3852, queryKey));
+		/* range_upper() */
+		boundUpper.val = OidFunctionCall1(3849, queryKey);
+
+		/*
+		 * TODO
+		 * Lift the following restrictions.
+		 */
+		if (boundLower.infinite) {
+			elog(ERROR, "the lower value of the range must not be infinity");
+		}
+		if (boundUpper.infinite) {
+			elog(ERROR, "the upper value of the range must not be infinity");
+		}
+
+		if (!boundLower.infinite && !boundUpper.infinite &&
+				boundLower.inclusive && boundUpper.inclusive)
+		{
+			GinState *ginstate = &so->ginstate;
+			int cmp;
+
+			cmp = DatumGetInt32(FunctionCall2Coll(
+						&ginstate->compareFn[attnum - 1],
+					       	ginstate->supportCollation[attnum - 1],
+						boundLower.val, boundUpper.val));
+
+			if (cmp == 0) {
+				/* Range degenerated to a normal entry. */
+				isRange = false;
+				queryKey = boundLower.val;
+			}
+		}
+	}
+
+	/* Range might degenerate to a normal entry in some cases. */
 
 	/*
 	 * Look for an existing equivalent entry.
@@ -81,22 +169,47 @@ ginFillScanEntry(GinScanOpaque so, OffsetNumber attnum,
 				prevEntry->isPartialMatch == isPartialMatch &&
 				prevEntry->strategy == strategy &&
 				prevEntry->searchMode == searchMode &&
-				prevEntry->attnum == attnum &&
-				ginCompareEntries(ginstate, attnum,
+				prevEntry->isRange == isRange &&
+				prevEntry->attnum == attnum)
+			{
+
+				if (isRange)
+				{
+					if (queryCategory == prevEntry->queryCategory) {
+						if (queryCategory == GIN_CAT_NULL_KEY)
+							/* An entry for NULL range exists. */
+							return prevEntry;
+
+						/* Two regular ranges, need to compare. */
+						if (DatumGetBool(OidFunctionCall2(3855, queryKey,
+										prevEntry->range)))
+							return prevEntry;
+					}
+				} else if (ginCompareEntries(ginstate, attnum,
 								  prevEntry->queryKey,
 								  prevEntry->queryCategory,
 								  queryKey,
 								  queryCategory) == 0)
-			{
-				/* Successful match */
-				return prevEntry;
+						return prevEntry;
 			}
 		}
 	}
 
 	/* Nope, create a new entry */
 	scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData));
-	scanEntry->queryKey = queryKey;
+
+	scanEntry->isRange = isRange;
+	if (isRange) {
+		memcpy(&scanEntry->rangeLower, &boundLower, sizeof(RangeBound));
+		memcpy(&scanEntry->rangeUpper, &boundUpper, sizeof(RangeBound));
+		scanEntry->range = queryKey;
+		/* The lower bound is what we look for in the entry tree. */
+		scanEntry->queryKey = scanEntry->rangeLower.val;
+	} else {
+		scanEntry->range = (Datum) 0;
+		scanEntry->queryKey = queryKey;
+	}	
+
 	scanEntry->queryCategory = queryCategory;
 	scanEntry->isPartialMatch = isPartialMatch;
 	scanEntry->extra_data = extra_data;
@@ -135,7 +248,8 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
 			   StrategyNumber strategy, int32 searchMode,
 			   Datum query, uint32 nQueryValues,
 			   Datum *queryValues, GinNullCategory *queryCategories,
-			   bool *partial_matches, Pointer *extra_data)
+			   bool *partial_matches, Pointer *extra_data,
+			   bool ranges)
 {
 	GinScanKey	key = &(so->keys[so->nkeys++]);
 	GinState   *ginstate = &so->ginstate;
@@ -169,6 +283,7 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
 		Datum		queryKey;
 		GinNullCategory queryCategory;
 		bool		isPartialMatch;
+		Oid		isRange;
 		Pointer		this_extra;
 
 		if (i < nUserQueryValues)
@@ -179,6 +294,8 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
 			isPartialMatch =
 				(ginstate->canPartialMatch[attnum - 1] && partial_matches)
 				? partial_matches[i] : false;
+			/* All entries within a key are ranges or none. */
+			isRange = ranges;
 			this_extra = (extra_data) ? extra_data[i] : NULL;
 		}
 		else
@@ -202,6 +319,7 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
 					break;
 			}
 			isPartialMatch = false;
+			isRange = false;
 			this_extra = NULL;
 
 			/*
@@ -217,7 +335,8 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
 		key->scanEntry[i] = ginFillScanEntry(so, attnum,
 											 strategy, searchMode,
 											 queryKey, queryCategory,
-											 isPartialMatch, this_extra);
+											 isPartialMatch, isRange,
+											 this_extra);
 	}
 }
 
@@ -268,6 +387,7 @@ ginNewScanKey(IndexScanDesc scan)
 	GinScanOpaque so = (GinScanOpaque) scan->opaque;
 	int			i;
 	bool		hasNullQuery = false;
+	Relation        rel = scan->indexRelation;
 
 	/* if no scan keys provided, allocate extra EVERYTHING GinScanKey */
 	so->keys = (GinScanKey)
@@ -291,6 +411,7 @@ ginNewScanKey(IndexScanDesc scan)
 		Pointer    *extra_data = NULL;
 		bool	   *nullFlags = NULL;
 		int32		searchMode = GIN_SEARCH_MODE_DEFAULT;
+		bool	ranges = false;
 
 		/*
 		 * We assume that GIN-indexable operators are strict, so a null query
@@ -364,11 +485,42 @@ ginNewScanKey(IndexScanDesc scan)
 		}
 		/* now we can use the nullFlags as category codes */
 
+		if (skey->sk_subtype != rel->rd_opcintype[i] &&
+					skey->sk_subtype != InvalidOid)
+		{
+			Oid subType1 = InvalidOid;
+			Oid subType2 = InvalidOid;
+
+			/*
+			 * A special case of cross-type operator is
+			 * ANYARRAY op ANYRANGEARRAY
+			 */
+			subType1 = get_element_type(rel->rd_opcintype[i]);	
+			if (OidIsValid(subType1))
+				/* The left is an array. Is the right too? */
+				subType2 = get_element_type(skey->sk_subtype);
+			if (OidIsValid(subType1) && OidIsValid(subType2)) {
+				/* Both are arrays. */
+				subType2 = get_range_subtype(subType2);
+				/*
+				 * Do non-range elements of the left array
+				 * match the subtype of the right array's range
+				 * elements?
+				 */
+				if (subType1 == subType2)
+					ranges = true;
+				else
+					/* Should not happen as long as coercions work fine. */
+					ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR),
+								errmsg("array element type %u does not match range subtype %u",
+									subType1, subType2)));
+			}
+		}
 		ginFillScanKey(so, skey->sk_attno,
 					   skey->sk_strategy, searchMode,
 					   skey->sk_argument, nQueryValues,
 					   queryValues, (GinNullCategory *) nullFlags,
-					   partial_matches, extra_data);
+					   partial_matches, extra_data, ranges);
 	}
 
 	/*
@@ -381,7 +533,7 @@ ginNewScanKey(IndexScanDesc scan)
 		ginFillScanKey(so, FirstOffsetNumber,
 					   InvalidStrategy, GIN_SEARCH_MODE_EVERYTHING,
 					   (Datum) 0, 0,
-					   NULL, NULL, NULL, NULL);
+					   NULL, NULL, NULL, NULL,  InvalidOid);
 	}
 
 	/*
@@ -405,6 +557,59 @@ ginNewScanKey(IndexScanDesc scan)
 	pgstat_count_index_scan(scan->indexRelation);
 }
 
+/*
+ * Retrieve the desired support function, either from relcache or catcache.
+ *
+ * Return TRUE on success, FALSE when GIN_COMPARE_PARTIAL_PROC does not
+ * exist or error if any other kind is not there.
+ */
+static bool 
+loadSupportFunction(GinState *state, Relation indRel, ScanKey scankey,
+		uint16 procnum, FmgrInfo *fn, bool required)
+{
+	AttrNumber attno = scankey->sk_attno;
+	bool	defaultOperator;
+	FmgrInfo	*procinfo;
+	RegProcedure	proc = InvalidOid;;	
+
+	/*
+	 * The "default" operators should be in relcache, however the cross-type
+	 * ones need to be retrieved from catalog.
+	 */
+	defaultOperator = scankey->sk_subtype == indRel->rd_opcintype[attno - 1] ||
+					scankey->sk_subtype == InvalidOid;
+
+	if (defaultOperator) {
+		if (!required) {
+			proc = index_getprocid(indRel, attno, procnum);
+			if (!RegProcedureIsValid(proc))
+				return false;
+		}
+
+		procinfo = index_getprocinfo(indRel, attno, procnum);
+		fmgr_info_copy(fn, procinfo, CurrentMemoryContext);
+	} else {
+		proc = get_opfamily_proc(indRel->rd_opfamily[attno - 1],
+				indRel->rd_opcintype[attno - 1], scankey->sk_subtype,
+				procnum);
+
+		if (!RegProcedureIsValid(proc))
+		{
+			if (!required)
+				return false;
+			else
+				ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR),
+						errmsg("missing support function  %d(%u,%u) for attribute %d of index \"%s\"",
+							procnum, indRel->rd_opcintype[attno - 1],
+							scankey->sk_subtype,
+							scankey->sk_attno,
+							RelationGetRelationName(indRel))));
+		}
+		fmgr_info_cxt(proc, fn, CurrentMemoryContext);
+	}
+	return true;
+}
+
 Datum
 ginrescan(PG_FUNCTION_ARGS)
 {
@@ -413,13 +618,57 @@ ginrescan(PG_FUNCTION_ARGS)
 
 	/* remaining arguments are ignored */
 	GinScanOpaque so = (GinScanOpaque) scan->opaque;
+	Relation        rel = scan->indexRelation;
 
 	freeScanKeys(so);
 
 	if (scankey && scan->numberOfKeys > 0)
 	{
+		int i;
+		GinState	*state;
+
 		memmove(scan->keyData, scankey,
 				scan->numberOfKeys * sizeof(ScanKeyData));
+
+		state = &so->ginstate;
+		scankey = scan->keyData;
+
+		/*
+		 * Now that we have the keys, load the support functions.
+		 *
+		 * In most cases the left and right operand are equal, so we
+		 * can get the functions from relation cache. However that's
+		 * not always true. 
+		 */
+		/*
+		 * TODO
+		 * Consider flags to recognize whether the operator at given
+		 * key position changed to cross-type or back.
+		 * In some cases it may not be necessary to reload some/all functions.
+		 */
+		for (i = 0; i < scan->numberOfKeys; i++)
+		{
+			/*
+			 * While GIN_COMPARE_PROC and GIN_EXTRACTVALUE_PROC
+			 * depend on opckeytpye and ocintype of the corresponding
+			 * opclass respectively, the other support functions can
+			 * be different for different righttype of the operator. 
+			 */ 
+			loadSupportFunction(state, rel, scankey,
+					GIN_EXTRACTQUERY_PROC,
+					&(state->extractQueryFn[i]), true);
+			loadSupportFunction(state, rel, scankey,
+					GIN_CONSISTENT_PROC,
+					&(state->consistentFn[i]), true);
+			/* Partial match is not mandatory, FALSE can be returned. */
+			state->canPartialMatch[i] = loadSupportFunction(state,
+					rel, scankey,
+					GIN_COMPARE_PARTIAL_PROC,
+					&(state->comparePartialFn[i]), false);
+
+			scankey++;
+		}
+
 	}
 
 	PG_RETURN_VOID();
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index 8a71681..e0146ee 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -58,34 +58,23 @@ initGinState(GinState *state, Relation index)
 										origTupdesc->attrs[i]->attcollation);
 		}
 
+		/*
+		 * There should in fact be only one GIN_COMPARE_PROC throughout
+		 * the whole opclass. This function always deals with
+		 * pg_opclass(opckeytype).
+		 */
 		fmgr_info_copy(&(state->compareFn[i]),
-					   index_getprocinfo(index, i + 1, GIN_COMPARE_PROC),
-					   CurrentMemoryContext);
-		fmgr_info_copy(&(state->extractValueFn[i]),
-					   index_getprocinfo(index, i + 1, GIN_EXTRACTVALUE_PROC),
-					   CurrentMemoryContext);
-		fmgr_info_copy(&(state->extractQueryFn[i]),
-					   index_getprocinfo(index, i + 1, GIN_EXTRACTQUERY_PROC),
-					   CurrentMemoryContext);
-		fmgr_info_copy(&(state->consistentFn[i]),
-					   index_getprocinfo(index, i + 1, GIN_CONSISTENT_PROC),
-					   CurrentMemoryContext);
-
+						index_getprocinfo(index, i + 1, GIN_COMPARE_PROC),
+						CurrentMemoryContext);
 		/*
-		 * Check opclass capability to do partial match.
+		 * Likewise, all operators within the opclass can use the same
+		 * GIN_EXTRACTVALUE_PROC. The only type we need to process is
+		 * pg_opclass(opcintype).
 		 */
-		if (index_getprocid(index, i + 1, GIN_COMPARE_PARTIAL_PROC) != InvalidOid)
-		{
-			fmgr_info_copy(&(state->comparePartialFn[i]),
-				   index_getprocinfo(index, i + 1, GIN_COMPARE_PARTIAL_PROC),
-						   CurrentMemoryContext);
-			state->canPartialMatch[i] = true;
-		}
-		else
-		{
-			state->canPartialMatch[i] = false;
-		}
-
+		fmgr_info_copy(&(state->extractValueFn[i]),
+						index_getprocinfo(index, i + 1, GIN_EXTRACTVALUE_PROC),
+						CurrentMemoryContext);
+		
 		/*
 		 * If the index column has a specified collation, we should honor that
 		 * while doing comparisons.  However, we may have a collatable storage
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index f1062f1..ef43ed9 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -794,6 +794,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 			{
 				/* OK, simple constant comparison value */
 				scanvalue = ((Const *) rightop)->constvalue;
+				op_righttype = ((Const *) rightop)->consttype;
 				if (((Const *) rightop)->constisnull)
 					flags |= SK_ISNULL;
 			}
@@ -831,7 +832,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 								   flags,
 								   varattno,	/* attribute number to scan */
 								   op_strategy, /* op's strategy */
-								   op_righttype,		/* strategy subtype */
+								   op_righttype,	/* strategy subtype */
 								   ((OpExpr *) clause)->inputcollid,	/* collation */
 								   opfuncid,	/* reg proc to use */
 								   scanvalue);	/* constant */
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index b6df2c6..e3eebc3 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -159,13 +159,23 @@ coerce_type(ParseState *pstate, Node *node,
 	Node	   *result;
 	CoercionPathType pathtype;
 	Oid			funcId;
-
 	if (targetTypeId == inputTypeId ||
 		node == NULL)
 	{
 		/* no conversion needed */
 		return node;
 	}
+	if (targetTypeId == ANYRANGEARRAYOID) {
+		Oid elemtype, rngsubtype;
+
+		elemtype = get_element_type(inputTypeId);
+		if (OidIsValid(elemtype)) {
+			rngsubtype = get_range_subtype(elemtype);
+			if (OidIsValid(rngsubtype)) {
+				return node;
+			}
+		}
+	}
 	if (targetTypeId == ANYOID ||
 		targetTypeId == ANYELEMENTOID ||
 		targetTypeId == ANYNONARRAYOID)
@@ -1352,6 +1362,7 @@ check_generic_type_consistency(Oid *actual_arg_types,
 	Oid			array_typeid = InvalidOid;
 	Oid			array_typelem;
 	Oid			range_typeid = InvalidOid;
+	Oid			rangearray_typeid = InvalidOid;
 	Oid			range_typelem;
 	bool		have_anyelement = false;
 	bool		have_anynonarray = false;
@@ -1399,6 +1410,15 @@ check_generic_type_consistency(Oid *actual_arg_types,
 				return false;
 			range_typeid = actual_type;
 		}
+		else if (decl_type == ANYRANGEARRAYOID)
+		{
+			if (actual_type == UNKNOWNOID)
+				continue;
+			actual_type = getBaseType(actual_type);		/* flatten domains */
+			if (OidIsValid(rangearray_typeid) && actual_type != rangearray_typeid)
+				return false;
+			rangearray_typeid = actual_type;
+		}
 	}
 
 	/* Get the element type based on the array type, if we have one */
@@ -1451,6 +1471,31 @@ check_generic_type_consistency(Oid *actual_arg_types,
 		}
 	}
 
+	if (OidIsValid(rangearray_typeid))
+	{
+		array_typelem = get_element_type(rangearray_typeid);
+		if (!OidIsValid(array_typelem))
+			return false;		/* should be an array, but isn't */
+
+		range_typelem = get_range_subtype(array_typelem);
+		if (!OidIsValid(range_typelem))
+			return false;		/* should be a range, but isn't */
+
+
+		if (!OidIsValid(elem_typeid))
+		{
+			/*
+			 * if we don't have an element type yet, use the one we just got
+			 */
+			elem_typeid = range_typelem;
+		}
+		else if (range_typelem != elem_typeid)
+		{
+			/* otherwise, they better match */
+			return false;
+		}
+	}
+
 	if (have_anynonarray)
 	{
 		/* require the element type to not be an array or domain over array */
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 438c3d0..b1b74a5 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -3137,13 +3137,11 @@ array_eq(PG_FUNCTION_ARGS)
 	int			ndims2 = ARR_NDIM(array2);
 	int		   *dims1 = ARR_DIMS(array1);
 	int		   *dims2 = ARR_DIMS(array2);
-	Oid			element_type = ARR_ELEMTYPE(array1);
+	Oid			element_type1 = ARR_ELEMTYPE(array1);
+	Oid			element_type2 = ARR_ELEMTYPE(array2);
 	bool		result = true;
 	int			nitems;
-	TypeCacheEntry *typentry;
-	int			typlen;
-	bool		typbyval;
-	char		typalign;
+	TypeCacheEntry *typentry, *typentry_rng, *typentry1, *typentry2;
 	char	   *ptr1;
 	char	   *ptr2;
 	bits8	   *bitmap1;
@@ -3151,11 +3149,44 @@ array_eq(PG_FUNCTION_ARGS)
 	int			bitmask;
 	int			i;
 	FunctionCallInfoData locfcinfo;
+	bool	eltype1_is_range, eltype2_is_range;
+	Oid	rng_type, base_type;
 
-	if (element_type != ARR_ELEMTYPE(array2))
+	eltype1_is_range = type_is_range(element_type1);
+	eltype2_is_range = type_is_range(element_type2);
+
+	if (eltype1_is_range && eltype2_is_range)
 		ereport(ERROR,
-				(errcode(ERRCODE_DATATYPE_MISMATCH),
-				 errmsg("cannot compare arrays of different element types")));
+		(errcode(ERRCODE_DATATYPE_MISMATCH),
+		 errmsg("at maximum one array may contain ranges")));
+
+	rng_type = InvalidOid;
+
+	if (!eltype1_is_range && !eltype2_is_range) {
+		/* No range, so the type OIDs must be equal. */
+		if (element_type1 != element_type2)
+			ereport(ERROR,
+			(errcode(ERRCODE_DATATYPE_MISMATCH),
+			 errmsg("cannot compare arrays of different non-range element types")));
+
+		base_type = element_type1;
+	} else {
+		Oid	rng_subtype;
+
+		if (eltype1_is_range) {
+			rng_type = element_type1;
+			base_type = element_type2;
+		} else {
+			rng_type = element_type2;
+			base_type = element_type1;
+		}
+
+		rng_subtype = get_range_subtype(rng_type);
+		if (base_type != rng_subtype)
+			ereport(ERROR,
+			(errcode(ERRCODE_DATATYPE_MISMATCH),
+			 errmsg("non-range type must be equal to sub-type of the range type")));
+	}
 
 	/* fast path if the arrays do not have the same dimensionality */
 	if (ndims1 != ndims2 ||
@@ -3170,27 +3201,64 @@ array_eq(PG_FUNCTION_ARGS)
 		 * as an index support function.
 		 */
 		typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
-		if (typentry == NULL ||
-			typentry->type_id != element_type)
+
+		if (typentry == NULL || typentry->type_id != base_type)
 		{
-			typentry = lookup_type_cache(element_type,
-										 TYPECACHE_EQ_OPR_FINFO);
-			if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
-				ereport(ERROR,
+			typentry = lookup_type_cache(base_type, TYPECACHE_EQ_OPR_FINFO);
+
+			if (!eltype1_is_range && !eltype2_is_range && 
+				!OidIsValid(typentry->eq_opr_finfo.fn_oid))
+					ereport(ERROR,
 						(errcode(ERRCODE_UNDEFINED_FUNCTION),
-				errmsg("could not identify an equality operator for type %s",
-					   format_type_be(element_type))));
+						errmsg("could not identify an equality operator for type %s",
+						format_type_be(element_type1))));
 			fcinfo->flinfo->fn_extra = (void *) typentry;
-		}
-		typlen = typentry->typlen;
-		typbyval = typentry->typbyval;
-		typalign = typentry->typalign;
+		}	
 
 		/*
-		 * apply the operator to each pair of array elements.
+		 * TODO
+		 * Find out if/how typentry_rng can be saved across calls.
 		 */
-		InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
-								 collation, NULL, NULL);
+		typentry_rng = NULL;
+
+		if (OidIsValid(rng_type) &&
+			(typentry_rng == NULL || typentry_rng->type_id != rng_type))
+		{
+			/*
+			 * One array contains ranges - containment function needed.
+			 */
+			typentry_rng = lookup_type_cache(rng_type, TYPECACHE_RANGE_INFO);
+
+			if (!OidIsValid(typentry_rng->rng_cont_proc_finfo.fn_oid))
+				ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_FUNCTION),
+				errmsg("could not identify a containment operator for type %s",
+				format_type_be(rng_type))));
+
+		}
+
+		if (eltype1_is_range) {
+			typentry1 = typentry_rng;
+			typentry2 = typentry;
+		} else if (eltype2_is_range) {
+			typentry2 = typentry_rng;
+			typentry1 = typentry;
+		} else {
+			/* No range, both types are the same. */
+			typentry1 = typentry2 = typentry;
+		}
+
+		if (!eltype1_is_range && !eltype2_is_range)
+			/*
+			 * Apply the comparison operator to each pair of array elements.
+			 */
+			InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo,
+					2, collation, NULL, NULL);
+		else
+			/* Apply containment function instead. */
+			InitFunctionCallInfoData(locfcinfo,
+					&typentry_rng->rng_cont_proc_finfo, 2,
+					collation, NULL, NULL);
 
 		/* Loop over source data */
 		nitems = ArrayGetNItems(ndims1, dims1);
@@ -3217,9 +3285,13 @@ array_eq(PG_FUNCTION_ARGS)
 			else
 			{
 				isnull1 = false;
-				elt1 = fetch_att(ptr1, typbyval, typlen);
-				ptr1 = att_addlength_pointer(ptr1, typlen, ptr1);
-				ptr1 = (char *) att_align_nominal(ptr1, typalign);
+				elt1 = fetch_att(ptr1,
+						typentry1->typbyval,
+						typentry1->typlen);
+				ptr1 = att_addlength_pointer(ptr1,
+						typentry1->typlen, ptr1);
+				ptr1 = (char *) att_align_nominal(ptr1,
+						typentry1->typalign);
 			}
 
 			if (bitmap2 && (*bitmap2 & bitmask) == 0)
@@ -3230,9 +3302,13 @@ array_eq(PG_FUNCTION_ARGS)
 			else
 			{
 				isnull2 = false;
-				elt2 = fetch_att(ptr2, typbyval, typlen);
-				ptr2 = att_addlength_pointer(ptr2, typlen, ptr2);
-				ptr2 = (char *) att_align_nominal(ptr2, typalign);
+				elt2 = fetch_att(ptr2,
+						typentry2->typbyval,
+						typentry2->typlen);
+				ptr2 = att_addlength_pointer(ptr2,
+						typentry2->typlen, ptr2);
+				ptr2 = (char *) att_align_nominal(ptr2,
+						typentry2->typalign);
 			}
 
 			/* advance bitmap pointers if any */
@@ -3260,8 +3336,17 @@ array_eq(PG_FUNCTION_ARGS)
 			/*
 			 * Apply the operator to the element pair
 			 */
-			locfcinfo.arg[0] = elt1;
-			locfcinfo.arg[1] = elt2;
+			if (eltype2_is_range) {
+				/*
+				 * The containment operator expects the range
+				 * to be the first argument.
+				 */
+				locfcinfo.arg[0] = elt2;
+				locfcinfo.arg[1] = elt1;
+			} else {
+				locfcinfo.arg[0] = elt1;
+				locfcinfo.arg[1] = elt2;
+			}
 			locfcinfo.argnull[0] = false;
 			locfcinfo.argnull[1] = false;
 			locfcinfo.isnull = false;
@@ -3661,63 +3746,131 @@ array_contain_compare(ArrayType *array1, ArrayType *array2, Oid collation,
 					  bool matchall, void **fn_extra)
 {
 	bool		result = matchall;
-	Oid			element_type = ARR_ELEMTYPE(array1);
-	TypeCacheEntry *typentry;
+	Oid			element_type1 = ARR_ELEMTYPE(array1);
+	Oid			element_type2 = ARR_ELEMTYPE(array2);
+	TypeCacheEntry *typentry, *typentry_rng, *typentry1, *typentry2;
 	int			nelems1;
 	Datum	   *values2;
 	bool	   *nulls2;
 	int			nelems2;
-	int			typlen;
-	bool		typbyval;
-	char		typalign;
 	char	   *ptr1;
 	bits8	   *bitmap1;
 	int			bitmask;
 	int			i;
 	int			j;
 	FunctionCallInfoData locfcinfo;
+	bool	eltype1_is_range, eltype2_is_range;
+	Oid	rng_type, base_type;
 
-	if (element_type != ARR_ELEMTYPE(array2))
+	eltype1_is_range = type_is_range(element_type1);
+	eltype2_is_range = type_is_range(element_type2);
+
+	if (eltype1_is_range && eltype2_is_range)
 		ereport(ERROR,
-				(errcode(ERRCODE_DATATYPE_MISMATCH),
-				 errmsg("cannot compare arrays of different element types")));
+		(errcode(ERRCODE_DATATYPE_MISMATCH),
+		 errmsg("at maximum one array may contain ranges")));
+
+	rng_type = InvalidOid;
+
+	if (!eltype1_is_range && !eltype2_is_range) {
+		/* No range, so the type OIDs must be equal. */
+		if (element_type1 != element_type2)
+			ereport(ERROR,
+			(errcode(ERRCODE_DATATYPE_MISMATCH),
+			 errmsg("cannot compare arrays of different non-range element types")));
+
+		base_type = element_type1;
+	} else {
+		Oid	rng_subtype;
+
+		if (eltype1_is_range) {
+			rng_type = element_type1;
+			base_type = element_type2;
+		} else {
+			rng_type = element_type2;
+			base_type = element_type1;
+		}
+
+		rng_subtype = get_range_subtype(rng_type);
+		if (base_type != rng_subtype)
+			ereport(ERROR,
+			(errcode(ERRCODE_DATATYPE_MISMATCH),
+			 errmsg("non-range type must be equal to sub-type of the range type")));
+	}
 
 	/*
-	 * We arrange to look up the equality function only once per series of
+	 * We arrange to look up the match function only once per series of
 	 * calls, assuming the element type doesn't change underneath us.  The
 	 * typcache is used so that we have no memory leakage when being used as
 	 * an index support function.
 	 */
-	typentry = (TypeCacheEntry *) *fn_extra;
-	if (typentry == NULL ||
-		typentry->type_id != element_type)
+	typentry = (TypeCacheEntry *) *fn_extra;	
+
+	if (typentry == NULL || typentry->type_id != base_type)
 	{
-		typentry = lookup_type_cache(element_type,
-									 TYPECACHE_EQ_OPR_FINFO);
-		if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
+		typentry = lookup_type_cache(base_type, TYPECACHE_EQ_OPR_FINFO);
+
+		if (!eltype1_is_range && !eltype2_is_range &&
+				!OidIsValid(typentry->eq_opr_finfo.fn_oid))
 			ereport(ERROR,
-					(errcode(ERRCODE_UNDEFINED_FUNCTION),
+				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 				errmsg("could not identify an equality operator for type %s",
-					   format_type_be(element_type))));
+					   format_type_be(element_type1))));
 		*fn_extra = (void *) typentry;
 	}
-	typlen = typentry->typlen;
-	typbyval = typentry->typbyval;
-	typalign = typentry->typalign;
+
+	/*
+	 * TODO
+	 * Find out if/how typentry_rng can be saved across calls.
+	 */
+	typentry_rng = NULL;
+
+	if (OidIsValid(rng_type) &&
+			(typentry_rng == NULL || typentry_rng->type_id != rng_type))
+	{
+		/*
+		 * One array contains ranges - containment function needed.
+		 */
+		typentry_rng = lookup_type_cache(rng_type, TYPECACHE_RANGE_INFO);
+
+		if (!OidIsValid(typentry_rng->rng_cont_proc_finfo.fn_oid))
+			ereport(ERROR,
+			(errcode(ERRCODE_UNDEFINED_FUNCTION),
+			errmsg("could not identify a containment operator for type %s",
+				format_type_be(rng_type))));
+	}
+
+
+	if (eltype1_is_range) {
+		typentry1 = typentry_rng;
+		typentry2 = typentry;
+	} else if (eltype2_is_range) {
+		typentry2 = typentry_rng;
+		typentry1 = typentry;
+	} else {
+		/* No range, both types are the same. */
+		typentry1 = typentry2 = typentry;
+	}
 
 	/*
 	 * Since we probably will need to scan array2 multiple times, it's
 	 * worthwhile to use deconstruct_array on it.  We scan array1 the hard way
 	 * however, since we very likely won't need to look at all of it.
 	 */
-	deconstruct_array(array2, element_type, typlen, typbyval, typalign,
-					  &values2, &nulls2, &nelems2);
+	deconstruct_array(array2, element_type2,
+			typentry2->typlen, typentry2->typbyval, typentry2->typalign,
+			&values2, &nulls2, &nelems2);
 
-	/*
-	 * Apply the comparison operator to each pair of array elements.
-	 */
-	InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
+	if (!eltype1_is_range && !eltype2_is_range)
+		/*
+		 * Apply the comparison operator to each pair of array elements.
+		 */
+		InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
 							 collation, NULL, NULL);
+	else
+		/* Apply containment function instead. */
+		InitFunctionCallInfoData(locfcinfo, &typentry_rng->rng_cont_proc_finfo, 2,
+				collation, NULL, NULL);
 
 	/* Loop over source data */
 	nelems1 = ArrayGetNItems(ARR_NDIM(array1), ARR_DIMS(array1));
@@ -3739,9 +3892,9 @@ array_contain_compare(ArrayType *array1, ArrayType *array2, Oid collation,
 		else
 		{
 			isnull1 = false;
-			elt1 = fetch_att(ptr1, typbyval, typlen);
-			ptr1 = att_addlength_pointer(ptr1, typlen, ptr1);
-			ptr1 = (char *) att_align_nominal(ptr1, typalign);
+			elt1 = fetch_att(ptr1, typentry1->typbyval, typentry1->typlen);
+			ptr1 = att_addlength_pointer(ptr1, typentry1->typlen, ptr1);
+			ptr1 = (char *) att_align_nominal(ptr1, typentry1->typalign);
 		}
 
 		/* advance bitmap pointer if any */
@@ -3780,11 +3933,21 @@ array_contain_compare(ArrayType *array1, ArrayType *array2, Oid collation,
 			/*
 			 * Apply the operator to the element pair
 			 */
-			locfcinfo.arg[0] = elt1;
-			locfcinfo.arg[1] = elt2;
+			if (eltype2_is_range) {
+				/*
+				 * The containment operator expects the range
+				 * to be the first argument.
+				 */
+				locfcinfo.arg[0] = elt2;
+				locfcinfo.arg[1] = elt1;
+			} else {
+				locfcinfo.arg[0] = elt1;
+				locfcinfo.arg[1] = elt2;
+			}
 			locfcinfo.argnull[0] = false;
 			locfcinfo.argnull[1] = false;
 			locfcinfo.isnull = false;
+
 			oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
 			if (oprresult)
 				break;
diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c
index 04650d8..41fd4ec 100644
--- a/src/backend/utils/adt/pseudotypes.c
+++ b/src/backend/utils/adt/pseudotypes.c
@@ -213,6 +213,30 @@ anyrange_out(PG_FUNCTION_ARGS)
 }
 
 /*
+ * anyrangearray_in		- input routine for pseudo-type ANYRANGEARRAY.
+ */
+Datum
+anyrangearray_in(PG_FUNCTION_ARGS)
+{
+	ereport(ERROR,
+			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+			 errmsg("cannot accept a value of type anyrangearray")));
+
+	PG_RETURN_VOID();			/* keep compiler quiet */
+}
+
+/*
+ * anyrangearray_out		- output routine for pseudo-type ANYRANGEARRAY.
+ *
+ * We may as well allow this, since array_out will in fact work.
+ */
+Datum
+anyrangearray_out(PG_FUNCTION_ARGS)
+{
+	return array_out(fcinfo);
+}
+
+/*
  * void_in		- input routine for pseudo-type VOID.
  *
  * We allow this so that PL functions can return VOID without any special
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index da66f34..addc5fa 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -6750,7 +6750,7 @@ find_index_column(Node *op, IndexOptInfo *index)
  */
 static bool
 gincost_pattern(IndexOptInfo *index, int indexcol,
-				Oid clause_op, Datum query,
+				Oid clause_op, Datum query, Oid queryType,
 				GinQualCounts *counts)
 {
 	Oid			extractProcOid;
@@ -6775,14 +6775,14 @@ gincost_pattern(IndexOptInfo *index, int indexcol,
 							   &strategy_op, &lefttype, &righttype);
 
 	/*
-	 * GIN always uses the "default" support functions, which are those with
-	 * lefttype == righttype == the opclass' opcintype (see
-	 * IndexSupportInitialize in relcache.c).
-	 */
+	 * The particular types are needed so that we can retrieve any support
+	 * function.
+	 */ 
+	op_input_types(clause_op, &lefttype, &righttype);
+
 	extractProcOid = get_opfamily_proc(index->opfamily[indexcol],
-									   index->opcintype[indexcol],
-									   index->opcintype[indexcol],
-									   GIN_EXTRACTQUERY_PROC);
+			index->opcintype[indexcol], queryType,
+			GIN_EXTRACTQUERY_PROC);
 
 	if (!OidIsValid(extractProcOid))
 	{
@@ -6897,6 +6897,7 @@ gincost_opexpr(IndexOptInfo *index, OpExpr *clause, GinQualCounts *counts)
 	/* Otherwise, apply extractQuery and get the actual term counts */
 	return gincost_pattern(index, indexcol, clause_op,
 						   ((Const *) operand)->constvalue,
+						   ((Const *) operand)->consttype,
 						   counts);
 }
 
@@ -6982,6 +6983,7 @@ gincost_scalararrayopexpr(IndexOptInfo *index, ScalarArrayOpExpr *clause,
 		memset(&elemcounts, 0, sizeof(elemcounts));
 
 		if (gincost_pattern(index, indexcol, clause_op, elemValues[i],
+							ARR_ELEMTYPE(arrayval),
 							&elemcounts))
 		{
 			/* We ignore array elements that are unsatisfiable patterns */
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index 04cb74c..7301f03 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -52,6 +52,7 @@
 #include "catalog/indexing.h"
 #include "catalog/pg_enum.h"
 #include "catalog/pg_operator.h"
+#include "catalog/pg_proc.h"
 #include "catalog/pg_range.h"
 #include "catalog/pg_type.h"
 #include "commands/defrem.h"
@@ -539,6 +540,8 @@ load_rangetype_info(TypeCacheEntry *typentry)
 	/* set up cached fmgrinfo structs */
 	fmgr_info_cxt(cmpFnOid, &typentry->rng_cmp_proc_finfo,
 				  CacheMemoryContext);
+	fmgr_info_cxt(OID_RANGE_CONTAINS_ELEM_PROC, &typentry->rng_cont_proc_finfo,
+				  CacheMemoryContext);
 	if (OidIsValid(canonicalOid))
 		fmgr_info_cxt(canonicalOid, &typentry->rng_canonical_finfo,
 					  CacheMemoryContext);
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
index c603521..a67ca72 100644
--- a/src/include/access/gin_private.h
+++ b/src/include/access/gin_private.h
@@ -15,6 +15,7 @@
 #include "access/itup.h"
 #include "fmgr.h"
 #include "storage/bufmgr.h"
+#include "utils/rangetypes.h"
 #include "utils/rbtree.h"
 
 
@@ -583,6 +584,9 @@ typedef struct GinScanKeyData
 	/* array of GinScanEntry pointers, one per extracted search condition */
 	GinScanEntry *scanEntry;
 
+	/* TRUE means that all entries are ranges instead of simple values. */
+	bool ranges;
+
 	/* array of check flags, reported to consistentFn */
 	bool	   *entryRes;
 
@@ -620,6 +624,12 @@ typedef struct GinScanEntryData
 	int32		searchMode;
 	OffsetNumber attnum;
 
+	bool		isRange;
+	Datum	range;
+	/* Cache the bounds for easier use. */
+	RangeBound	rangeLower;
+	RangeBound	rangeUpper;
+
 	/* Current page in posting tree */
 	Buffer		buffer;
 
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index d200348..8f19c53 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -657,6 +657,12 @@ DATA(insert (	2745   2277 2277 2 s 2751 2742 0 ));
 DATA(insert (	2745   2277 2277 3 s 2752 2742 0 ));
 DATA(insert (	2745   2277 2277 4 s 1070 2742 0 ));
 
+/* ANYARRAY op ANYRANGEARRAY */
+DATA(insert (	2745   2277 3846 1 s	3968 2742 0 ));
+DATA(insert (	2745   2277 3846 2 s	3970 2742 0 ));
+DATA(insert (	2745   2277 3846 3 s	3972 2742 0 ));
+DATA(insert (	2745   2277 3846 4 s	3974 2742 0 ));
+
 /*
  * btree enum_ops
  */
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index 7155cb2..a3c04a0 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -355,6 +355,30 @@ DATA(insert (	3919   3831 3831 4 3878 ));
 DATA(insert (	3919   3831 3831 5 3879 ));
 DATA(insert (	3919   3831 3831 6 3880 ));
 DATA(insert (	3919   3831 3831 7 3881 ));
+DATA(insert (	2745   1007 3905 1 351 ));
+DATA(insert (	2745   1007 3905 2 2743 ));
+DATA(insert (	2745   1007 3905 3 2774 ));
+DATA(insert (	2745   1007 3905 4 2744 ));
+DATA(insert (	2745   1231 3907 1 1769 ));
+DATA(insert (	2745   1231 3907 2 2743 ));
+DATA(insert (	2745   1231 3907 3 2774 ));
+DATA(insert (	2745   1231 3907 4 2744 ));
+DATA(insert (	2745   1115 3909 1 2045 ));
+DATA(insert (	2745   1115 3909 2 2743 ));
+DATA(insert (	2745   1115 3909 3 2774 ));
+DATA(insert (	2745   1115 3909 4 2744 ));
+DATA(insert (	2745   1185 3911 1 1314 ));
+DATA(insert (	2745   1185 3911 2 2743 ));
+DATA(insert (	2745   1185 3911 3 2774 ));
+DATA(insert (	2745   1185 3911 4 2744 ));
+DATA(insert (	2745   1182 3913 1 1092 ));
+DATA(insert (	2745   1182 3913 2 2743 ));
+DATA(insert (	2745   1182 3913 3 2774 ));
+DATA(insert (	2745   1182 3913 4 2744 ));
+DATA(insert (	2745   1016 3927 1 842 ));
+DATA(insert (	2745   1016 3927 2 2743 ));
+DATA(insert (	2745   1016 3927 3 2774 ));
+DATA(insert (	2745   1016 3927 4 2744 ));
 
 
 /* sp-gist */
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 5f28fc3..43f5372 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1736,7 +1736,26 @@ DATA(insert OID = 3966 (  "#>"	   PGNSP PGUID b f f 114 1009 114 0 0 json_extrac
 DESCR("get value from json with path elements");
 DATA(insert OID = 3967 (  "#>>"    PGNSP PGUID b f f 114 1009 25 0 0 json_extract_path_text_op - - ));
 DESCR("get value from json as text with path elements");
-
+/*
+ * TODO
+ * oprrest, oprjoin
+ */
+DATA(insert OID = 3968 (  "&&"	   PGNSP PGUID b f f 2277 3846 16 3969 0 array_overlap_rngarray - - ));
+DESCR("array overlaps range array");
+DATA(insert OID = 3969 (  "&&"	   PGNSP PGUID b f f 3846 2277 16 3968 0 rngarray_overlap_array - - ));
+DESCR("range array overlaps array");
+DATA(insert OID = 3970 (  "@>"	   PGNSP PGUID b f f 2277 3846 16 3973 0 array_contains_rngarray - - ));
+DESCR("array contains range array");
+DATA(insert OID = 3971 (  "@>"	   PGNSP PGUID b f f 3846 2277 16 3972 0 rngarray_contains_array - - ));
+DESCR("range array contains array");
+DATA(insert OID = 3972 (  "<@"	   PGNSP PGUID b f f 2277 3846 16 3971 0 array_contained_by_rngarray - - ));
+DESCR("array is contained by range array");
+DATA(insert OID = 3973 (  "<@"	   PGNSP PGUID b f f 3846 2277 16 3970 0 rngarray_contained_by_array - - ));
+DESCR("range array is contained by array");
+DATA(insert OID = 3974 (  "="	   PGNSP PGUID b f f 2277 3846 16 3975 0 array_equals_rngarray - - ));
+DESCR("range array is equal to array");
+DATA(insert OID = 3975 (  "="	   PGNSP PGUID b f f 3846 2277 16 3974 0 rngarray_equals_array - - ));
+DESCR("range array is equal to array");
 
 
 /*
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 90aff3d..fd31744 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3514,6 +3514,10 @@ DATA(insert OID = 3116 (  fdw_handler_in	PGNSP PGUID 12 1 0 0 0 f f f f f f i 1
 DESCR("I/O");
 DATA(insert OID = 3117 (  fdw_handler_out	PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "3115" _null_ _null_ _null_ _null_ fdw_handler_out _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3186 (  anyrangearray_in	PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 3846 "2275" _null_ _null_ _null_ _null_ anyrangearray_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3187 (  anyrangearray_out	PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2275 "3846" _null_ _null_ _null_ _null_ anyrangearray_out _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* cryptographic */
 DATA(insert OID =  2311 (  md5	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "25" _null_ _null_ _null_ _null_ md5_text _null_ _null_ _null_ ));
@@ -3976,6 +3980,15 @@ DATA(insert OID = 2747 (  arrayoverlap		   PGNSP PGUID 12 1 0 0 0 f f f f t f i
 DATA(insert OID = 2748 (  arraycontains		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2277 2277" _null_ _null_ _null_ _null_ arraycontains _null_ _null_ _null_ ));
 DATA(insert OID = 2749 (  arraycontained	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2277 2277" _null_ _null_ _null_ _null_ arraycontained _null_ _null_ _null_ ));
 
+DATA(insert OID = 3178 (  array_overlap_rngarray	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2277 3846" _null_ _null_ _null_ _null_ arrayoverlap _null_ _null_ _null_ ));
+DATA(insert OID = 3179 (  rngarray_overlap_array	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3846 2277" _null_ _null_ _null_ _null_ arrayoverlap _null_ _null_ _null_ ));
+DATA(insert OID = 3180 (  array_contains_rngarray	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2277 3846" _null_ _null_ _null_ _null_ arraycontains _null_ _null_ _null_ ));
+DATA(insert OID = 3181 (  rngarray_contains_array	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3846 2277" _null_ _null_ _null_ _null_ arraycontains _null_ _null_ _null_ ));
+DATA(insert OID = 3182 (  array_contained_by_rngarray	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2277 3846" _null_ _null_ _null_ _null_ arraycontained _null_ _null_ _null_ ));
+DATA(insert OID = 3183 (  rngarray_contained_by_array	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3846 2277" _null_ _null_ _null_ _null_ arraycontained _null_ _null_ _null_ ));
+DATA(insert OID = 3184 (  array_equals_rngarray	 	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2277 3846" _null_ _null_ _null_ _null_ array_eq _null_ _null_ _null_ ));
+DATA(insert OID = 3185 (  rngarray_equals_array	 	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3846 2277" _null_ _null_ _null_ _null_ array_eq _null_ _null_ _null_ ));
+
 /* userlock replacements */
 DATA(insert OID = 2880 (  pg_advisory_lock				PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ pg_advisory_lock_int8 _null_ _null_ _null_ ));
 DESCR("obtain exclusive advisory lock");
@@ -4555,6 +4568,7 @@ DATA(insert OID = 3857 (  range_overlaps		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2
 DESCR("implementation of && operator");
 DATA(insert OID = 3858 (  range_contains_elem	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3831 2283" _null_ _null_ _null_ _null_ range_contains_elem _null_ _null_ _null_ ));
 DESCR("implementation of @> operator");
+#define OID_RANGE_CONTAINS_ELEM_PROC			3858
 DATA(insert OID = 3859 (  range_contains		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_contains _null_ _null_ _null_ ));
 DESCR("implementation of @> operator");
 DATA(insert OID = 3860 (  elem_contained_by_range	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2283 3831" _null_ _null_ _null_ _null_ elem_contained_by_range _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_range.h b/src/include/catalog/pg_range.h
index f9e3373..a262ba0 100644
--- a/src/include/catalog/pg_range.h
+++ b/src/include/catalog/pg_range.h
@@ -16,6 +16,11 @@
  *
  *	  XXX do NOT break up DATA() statements into multiple lines!
  *		  the scripts are not as smart as you might think...
+ *	  
+ *	  XXX When adding a new range for a subtype array of which already
+ *	  has default opclass for GIN, don't forget to add the appropriate
+ *	  cross-type entries to pg_amproc.
+ *	
  *
  *-------------------------------------------------------------------------
  */
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index e3822fa..b048c7a 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -669,7 +669,8 @@ DATA(insert OID = 3115 ( fdw_handler	PGNSP PGUID  4 t p P f t \054 0 0 0 fdw_han
 #define FDW_HANDLEROID	3115
 DATA(insert OID = 3831 ( anyrange		PGNSP PGUID  -1 f p P f t \054 0 0 0 anyrange_in anyrange_out - - - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
 #define ANYRANGEOID		3831
-
+DATA(insert OID = 3846 ( anyrangearray		PGNSP PGUID  -1 f p P f t \054 0 0 0 anyrangearray_in anyrangearray_out - - - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
+#define ANYRANGEARRAYOID	3846
 
 /*
  * macros
@@ -704,6 +705,7 @@ DATA(insert OID = 3831 ( anyrange		PGNSP PGUID  -1 f p P f t \054 0 0 0 anyrange
 	 (typid) == ANYARRAYOID || \
 	 (typid) == ANYNONARRAYOID || \
 	 (typid) == ANYENUMOID || \
-	 (typid) == ANYRANGEOID)
+	 (typid) == ANYRANGEOID || \
+	 (typid) == ANYRANGEARRAYOID)
 
 #endif   /* PG_TYPE_H */
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 667c58b..25e2ea9 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -531,6 +531,8 @@ extern Datum anyenum_in(PG_FUNCTION_ARGS);
 extern Datum anyenum_out(PG_FUNCTION_ARGS);
 extern Datum anyrange_in(PG_FUNCTION_ARGS);
 extern Datum anyrange_out(PG_FUNCTION_ARGS);
+extern Datum anyrangearray_in(PG_FUNCTION_ARGS);
+extern Datum anyrangearray_out(PG_FUNCTION_ARGS);
 extern Datum void_in(PG_FUNCTION_ARGS);
 extern Datum void_out(PG_FUNCTION_ARGS);
 extern Datum void_recv(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/typcache.h b/src/include/utils/typcache.h
index 20f510d..d6fbdab 100644
--- a/src/include/utils/typcache.h
+++ b/src/include/utils/typcache.h
@@ -81,6 +81,7 @@ typedef struct TypeCacheEntry
 	struct TypeCacheEntry *rngelemtype; /* range's element type */
 	Oid			rng_collation;	/* collation for comparisons, if any */
 	FmgrInfo	rng_cmp_proc_finfo;		/* comparison function */
+	FmgrInfo	rng_cont_proc_finfo;		/* range_contains_elem() function */
 	FmgrInfo	rng_canonical_finfo;	/* canonicalization function, if any */
 	FmgrInfo	rng_subdiff_finfo;		/* difference function, if any */
 
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to