diff --git a/doc/src/sgml/gin.sgml b/doc/src/sgml/gin.sgml
new file mode 100644
index 9ffa8be..c8a6b50
*** a/doc/src/sgml/gin.sgml
--- b/doc/src/sgml/gin.sgml
***************
*** 216,221 ****
--- 216,230 ----
         arrays previously returned by <function>extractQuery</>.
         <literal>extra_data</> is the extra-data array returned by
         <function>extractQuery</>, or <symbol>NULL</symbol> if none.
+        <function>consistent</> can be declared as either 1st or 6th support
+        function of opclass. If it's declared as 6th then it must support
+        tri-state logic can be used for fast scan technique which accelerating
+        gin index scan by skipping parts of large posting-trees. Tri-state
+        version of <function>consistent</> accepts <literal>UNKNOWN</> values
+        in <literal>check</> array. These values means that indexed item can
+        either contain or not contain corresponding query key. Consistent
+        might return <literal>UNKNOWN</> values as well when given information
+        is lacking for exact answer.
        </para>
  
        <para>
diff --git a/src/backend/access/gin/ginarrayproc.c b/src/backend/access/gin/ginarrayproc.c
new file mode 100644
index e02a91b..9e58656
*** a/src/backend/access/gin/ginarrayproc.c
--- b/src/backend/access/gin/ginarrayproc.c
*************** ginqueryarrayextract(PG_FUNCTION_ARGS)
*** 141,147 ****
  Datum
  ginarrayconsistent(PG_FUNCTION_ARGS)
  {
! 	bool	   *check = (bool *) PG_GETARG_POINTER(0);
  	StrategyNumber strategy = PG_GETARG_UINT16(1);
  
  	/* ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2); */
--- 141,147 ----
  Datum
  ginarrayconsistent(PG_FUNCTION_ARGS)
  {
! 	GinLogicValue *check = (GinLogicValue *) PG_GETARG_POINTER(0);
  	StrategyNumber strategy = PG_GETARG_UINT16(1);
  
  	/* ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2); */
*************** ginarrayconsistent(PG_FUNCTION_ARGS)
*** 152,158 ****
  
  	/* Datum	   *queryKeys = (Datum *) PG_GETARG_POINTER(6); */
  	bool	   *nullFlags = (bool *) PG_GETARG_POINTER(7);
! 	bool		res;
  	int32		i;
  
  	switch (strategy)
--- 152,158 ----
  
  	/* Datum	   *queryKeys = (Datum *) PG_GETARG_POINTER(6); */
  	bool	   *nullFlags = (bool *) PG_GETARG_POINTER(7);
! 	GinLogicValue	res;
  	int32		i;
  
  	switch (strategy)
*************** ginarrayconsistent(PG_FUNCTION_ARGS)
*** 161,173 ****
  			/* result is not lossy */
  			*recheck = false;
  			/* must have a match for at least one non-null element */
! 			res = false;
  			for (i = 0; i < nkeys; i++)
  			{
! 				if (check[i] && !nullFlags[i])
  				{
! 					res = true;
! 					break;
  				}
  			}
  			break;
--- 161,180 ----
  			/* result is not lossy */
  			*recheck = false;
  			/* must have a match for at least one non-null element */
! 			res = GIN_FALSE;
  			for (i = 0; i < nkeys; i++)
  			{
! 				if (!nullFlags[i])
  				{
! 					if (check[i] == GIN_TRUE)
! 					{
! 						res = GIN_TRUE;
! 						break;
! 					}
! 					else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
! 					{
! 						res = GIN_MAYBE;
! 					}
  				}
  			}
  			break;
*************** ginarrayconsistent(PG_FUNCTION_ARGS)
*** 175,195 ****
  			/* result is not lossy */
  			*recheck = false;
  			/* must have all elements in check[] true, and no nulls */
! 			res = true;
  			for (i = 0; i < nkeys; i++)
  			{
! 				if (!check[i] || nullFlags[i])
  				{
! 					res = false;
  					break;
  				}
  			}
  			break;
  		case GinContainedStrategy:
  			/* we will need recheck */
  			*recheck = true;
  			/* can't do anything else useful here */
! 			res = true;
  			break;
  		case GinEqualStrategy:
  			/* we will need recheck */
--- 182,206 ----
  			/* result is not lossy */
  			*recheck = false;
  			/* must have all elements in check[] true, and no nulls */
! 			res = GIN_TRUE;
  			for (i = 0; i < nkeys; i++)
  			{
! 				if (check[i] == GIN_FALSE || nullFlags[i])
  				{
! 					res = GIN_FALSE;
  					break;
  				}
+ 				if (check[i] == GIN_MAYBE)
+ 				{
+ 					res = GIN_MAYBE;
+ 				}
  			}
  			break;
  		case GinContainedStrategy:
  			/* we will need recheck */
  			*recheck = true;
  			/* can't do anything else useful here */
! 			res = GIN_TRUE;
  			break;
  		case GinEqualStrategy:
  			/* we will need recheck */
*************** ginarrayconsistent(PG_FUNCTION_ARGS)
*** 200,213 ****
  			 * against nulls here.	This is because array_contain_compare and
  			 * array_eq handle nulls differently ...
  			 */
! 			res = true;
  			for (i = 0; i < nkeys; i++)
  			{
! 				if (!check[i])
  				{
! 					res = false;
  					break;
  				}
  			}
  			break;
  		default:
--- 211,228 ----
  			 * against nulls here.	This is because array_contain_compare and
  			 * array_eq handle nulls differently ...
  			 */
! 			res = GIN_TRUE;
  			for (i = 0; i < nkeys; i++)
  			{
! 				if (check[i] == GIN_FALSE)
  				{
! 					res = GIN_FALSE;
  					break;
  				}
+ 				else if (check[i] == GIN_MAYBE)
+ 				{
+ 					res = GIN_MAYBE;
+ 				}
  			}
  			break;
  		default:
diff --git a/src/backend/access/gin/ginlogic.c b/src/backend/access/gin/ginlogic.c
new file mode 100644
index dc8e630..4fb84c1
*** a/src/backend/access/gin/ginlogic.c
--- b/src/backend/access/gin/ginlogic.c
*************** ginInitConsistentFunction(GinState *gins
*** 177,182 ****
  		key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
  		key->collation = ginstate->supportCollation[key->attnum - 1];
  		key->boolConsistentFn = normalBoolConsistentFn;
! 		key->triConsistentFn = shimTriConsistentFn;
  	}
  }
--- 177,185 ----
  		key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
  		key->collation = ginstate->supportCollation[key->attnum - 1];
  		key->boolConsistentFn = normalBoolConsistentFn;
! 		if (ginstate->consistentSupportMaybe[key->attnum - 1])
! 			key->triConsistentFn =  normalBoolConsistentFn;
! 		else
! 			key->triConsistentFn =  shimTriConsistentFn;
  	}
  }
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
new file mode 100644
index 486f2ef..d561d60
*** a/src/backend/access/gin/ginutil.c
--- b/src/backend/access/gin/ginutil.c
*************** initGinState(GinState *state, Relation i
*** 67,75 ****
  		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);
  
  		/*
  		 * Check opclass capability to do partial match.
--- 67,89 ----
  		fmgr_info_copy(&(state->extractQueryFn[i]),
  					   index_getprocinfo(index, i + 1, GIN_EXTRACTQUERY_PROC),
  					   CurrentMemoryContext);
! 		/*
! 		 * Check opclass capability to do tri-state logic consistent check.
! 		 */
! 		if (index_getprocid(index, i + 1, GIN_CONSISTENT_TRISTATE_PROC) != InvalidOid)
! 		{
! 			fmgr_info_copy(&(state->consistentFn[i]),
! 			   index_getprocinfo(index, i + 1, GIN_CONSISTENT_TRISTATE_PROC),
! 						   CurrentMemoryContext);
! 			state->consistentSupportMaybe[i] = true;
! 		}
! 		else
! 		{
! 			fmgr_info_copy(&(state->consistentFn[i]),
! 						   index_getprocinfo(index, i + 1, GIN_CONSISTENT_PROC),
! 						   CurrentMemoryContext);
! 			state->consistentSupportMaybe[i] = false;
! 		}
  
  		/*
  		 * Check opclass capability to do partial match.
diff --git a/src/backend/utils/adt/tsginidx.c b/src/backend/utils/adt/tsginidx.c
new file mode 100644
index 9f6e8e9..c78bf2b
*** a/src/backend/utils/adt/tsginidx.c
--- b/src/backend/utils/adt/tsginidx.c
***************
*** 15,20 ****
--- 15,21 ----
  
  #include "access/gin.h"
  #include "access/skey.h"
+ #include "miscadmin.h"
  #include "tsearch/ts_type.h"
  #include "tsearch/ts_utils.h"
  #include "utils/builtins.h"
*************** gin_extract_tsquery(PG_FUNCTION_ARGS)
*** 172,183 ****
  typedef struct
  {
  	QueryItem  *first_item;
! 	bool	   *check;
  	int		   *map_item_operand;
  	bool	   *need_recheck;
  } GinChkVal;
  
! static bool
  checkcondition_gin(void *checkval, QueryOperand *val)
  {
  	GinChkVal  *gcv = (GinChkVal *) checkval;
--- 173,184 ----
  typedef struct
  {
  	QueryItem  *first_item;
! 	GinLogicValue *check;
  	int		   *map_item_operand;
  	bool	   *need_recheck;
  } GinChkVal;
  
! static GinLogicValue
  checkcondition_gin(void *checkval, QueryOperand *val)
  {
  	GinChkVal  *gcv = (GinChkVal *) checkval;
*************** checkcondition_gin(void *checkval, Query
*** 194,203 ****
  	return gcv->check[j];
  }
  
  Datum
  gin_tsquery_consistent(PG_FUNCTION_ARGS)
  {
! 	bool	   *check = (bool *) PG_GETARG_POINTER(0);
  
  	/* StrategyNumber strategy = PG_GETARG_UINT16(1); */
  	TSQuery		query = PG_GETARG_TSQUERY(2);
--- 195,264 ----
  	return gcv->check[j];
  }
  
+ /*
+  * Evaluate tsquery boolean expression using ternary login.
+  *
+  * chkcond is a callback function used to evaluate each VAL node in the query.
+  * checkval can be used to pass information to the callback. TS_execute doesn't
+  * do anything with it.
+  */
+ static GinLogicValue
+ TS_execute_ternary(QueryItem *curitem, void *checkval,
+ 		GinLogicValue (*chkcond) (void *checkval, QueryOperand *val))
+ {
+ 	GinLogicValue val1, val2, result;
+ 	/* since this function recurses, it could be driven to stack overflow */
+ 	check_stack_depth();
+ 
+ 	if (curitem->type == QI_VAL)
+ 		return chkcond(checkval, (QueryOperand *) curitem);
+ 
+ 	switch (curitem->qoperator.oper)
+ 	{
+ 		case OP_NOT:
+ 			result = TS_execute_ternary(curitem + 1, checkval, chkcond);
+ 			if (result == GIN_MAYBE)
+ 				return result;
+ 			return !result;
+ 
+ 		case OP_AND:
+ 			val1 = TS_execute_ternary(curitem + curitem->qoperator.left,
+ 															checkval, chkcond);
+ 			if (val1 == GIN_FALSE)
+ 				return GIN_FALSE;
+ 			val2 = TS_execute_ternary(curitem + 1, checkval, chkcond);
+ 			if (val2 == GIN_FALSE)
+ 				return GIN_FALSE;
+ 			if (val1 == GIN_TRUE && val2 == GIN_TRUE)
+ 				return GIN_TRUE;
+ 			else
+ 				return GIN_MAYBE;
+ 
+ 		case OP_OR:
+ 			val1 = TS_execute_ternary(curitem + curitem->qoperator.left,
+ 															checkval, chkcond);
+ 			if (val1 == GIN_TRUE)
+ 				return GIN_TRUE;
+ 			val2 = TS_execute_ternary(curitem + 1, checkval, chkcond);
+ 			if (val2 == GIN_TRUE)
+ 				return GIN_TRUE;
+ 			if (val1 == GIN_FALSE && val2 == GIN_FALSE)
+ 				return GIN_FALSE;
+ 			else
+ 				return GIN_MAYBE;
+ 
+ 		default:
+ 			elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper);
+ 	}
+ 
+ 	/* not reachable, but keep compiler quiet */
+ 	return false;
+ }
+ 
  Datum
  gin_tsquery_consistent(PG_FUNCTION_ARGS)
  {
! 	GinLogicValue *check = (bool *) PG_GETARG_POINTER(0);
  
  	/* StrategyNumber strategy = PG_GETARG_UINT16(1); */
  	TSQuery		query = PG_GETARG_TSQUERY(2);
*************** gin_tsquery_consistent(PG_FUNCTION_ARGS)
*** 205,211 ****
  	/* int32	nkeys = PG_GETARG_INT32(3); */
  	Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4);
  	bool	   *recheck = (bool *) PG_GETARG_POINTER(5);
! 	bool		res = FALSE;
  
  	/* The query requires recheck only if it involves weights */
  	*recheck = false;
--- 266,272 ----
  	/* int32	nkeys = PG_GETARG_INT32(3); */
  	Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4);
  	bool	   *recheck = (bool *) PG_GETARG_POINTER(5);
! 	GinLogicValue res = GIN_FALSE;
  
  	/* The query requires recheck only if it involves weights */
  	*recheck = false;
*************** gin_tsquery_consistent(PG_FUNCTION_ARGS)
*** 224,233 ****
  		gcv.map_item_operand = (int *) (extra_data[0]);
  		gcv.need_recheck = recheck;
  
! 		res = TS_execute(GETQUERY(query),
! 						 &gcv,
! 						 true,
! 						 checkcondition_gin);
  	}
  
  	PG_RETURN_BOOL(res);
--- 285,293 ----
  		gcv.map_item_operand = (int *) (extra_data[0]);
  		gcv.need_recheck = recheck;
  
! 		res = TS_execute_ternary(GETQUERY(query),
! 								   &gcv,
! 								   checkcondition_gin);
  	}
  
  	PG_RETURN_BOOL(res);
diff --git a/src/include/access/gin.h b/src/include/access/gin.h
new file mode 100644
index 03e58c9..afa13a0
*** a/src/include/access/gin.h
--- b/src/include/access/gin.h
***************
*** 23,29 ****
  #define GIN_EXTRACTQUERY_PROC		   3
  #define GIN_CONSISTENT_PROC			   4
  #define GIN_COMPARE_PARTIAL_PROC	   5
! #define GINNProcs					   5
  
  /*
   * searchMode settings for extractQueryFn.
--- 23,30 ----
  #define GIN_EXTRACTQUERY_PROC		   3
  #define GIN_CONSISTENT_PROC			   4
  #define GIN_COMPARE_PARTIAL_PROC	   5
! #define GIN_CONSISTENT_TRISTATE_PROC   6
! #define GINNProcs					   6
  
  /*
   * searchMode settings for extractQueryFn.
*************** typedef struct GinStatsData
*** 46,51 ****
--- 47,63 ----
  	int32		ginVersion;
  } GinStatsData;
  
+ /* ginlogic.c */
+ enum
+ {
+ 	GIN_FALSE = 0,			/* item is present / matches */
+ 	GIN_TRUE = 1,			/* item is not present / does not match */
+ 	GIN_MAYBE = 2			/* don't know if item is present / don't know if
+ 							 * matches */
+ } GinLogicValueEnum;
+ 
+ typedef char GinLogicValue;
+ 
  /* GUC parameter */
  extern PGDLLIMPORT int GinFuzzySearchLimit;
  
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
new file mode 100644
index 2cf042a..5e195f0
*** a/src/include/access/gin_private.h
--- b/src/include/access/gin_private.h
*************** typedef struct GinState
*** 353,358 ****
--- 353,360 ----
  	bool		canPartialMatch[INDEX_MAX_KEYS];
  	/* Collations to pass to the support functions */
  	Oid			supportCollation[INDEX_MAX_KEYS];
+ 	/* Consistent function supportsunknown values? */
+ 	bool            consistentSupportMaybe[INDEX_MAX_KEYS];
  } GinState;
  
  
*************** extern void ginNewScanKey(IndexScanDesc 
*** 850,866 ****
  extern Datum gingetbitmap(PG_FUNCTION_ARGS);
  
  /* ginlogic.c */
- 
- enum
- {
- 	GIN_FALSE = 0,			/* item is present / matches */
- 	GIN_TRUE = 1,			/* item is not present / does not match */
- 	GIN_MAYBE = 2			/* don't know if item is present / don't know if
- 							 * matches */
- } GinLogicValueEnum;
- 
- typedef char GinLogicValue;
- 
  extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key);
  
  /* ginvacuum.c */
--- 852,857 ----
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
new file mode 100644
index 4f46ddd..759ea70
*** a/src/include/catalog/pg_am.h
--- b/src/include/catalog/pg_am.h
*************** DESCR("hash index access method");
*** 126,132 ****
  DATA(insert OID = 783 (  gist		0 8 f t f f t t f t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup - gistcostestimate gistoptions ));
  DESCR("GiST index access method");
  #define GIST_AM_OID 783
! DATA(insert OID = 2742 (  gin		0 5 f f f f t t f f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbuildempty ginbulkdelete ginvacuumcleanup - gincostestimate ginoptions ));
  DESCR("GIN index access method");
  #define GIN_AM_OID 2742
  DATA(insert OID = 4000 (  spgist	0 5 f f f f f t f t f f f 0 spginsert spgbeginscan spggettuple spggetbitmap spgrescan spgendscan spgmarkpos spgrestrpos spgbuild spgbuildempty spgbulkdelete spgvacuumcleanup spgcanreturn spgcostestimate spgoptions ));
--- 126,132 ----
  DATA(insert OID = 783 (  gist		0 8 f t f f t t f t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup - gistcostestimate gistoptions ));
  DESCR("GiST index access method");
  #define GIST_AM_OID 783
! DATA(insert OID = 2742 (  gin		0 6 f f f f t t f f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbuildempty ginbulkdelete ginvacuumcleanup - gincostestimate ginoptions ));
  DESCR("GIN index access method");
  #define GIN_AM_OID 2742
  DATA(insert OID = 4000 (  spgist	0 5 f f f f f t f t f f f 0 spginsert spgbeginscan spggettuple spggetbitmap spgrescan spgendscan spgmarkpos spgrestrpos spgbuild spgbuildempty spgbulkdelete spgvacuumcleanup spgcanreturn spgcostestimate spgoptions ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
new file mode 100644
index 66bd765..636847b
*** a/src/include/catalog/pg_amproc.h
--- b/src/include/catalog/pg_amproc.h
*************** DATA(insert (	3919   3831 3831 7 3881 ))
*** 234,360 ****
  DATA(insert (	2745   1007 1007 1	351 ));
  DATA(insert (	2745   1007 1007 2 2743 ));
  DATA(insert (	2745   1007 1007 3 2774 ));
! DATA(insert (	2745   1007 1007 4 2744 ));
  DATA(insert (	2745   1009 1009 1	360 ));
  DATA(insert (	2745   1009 1009 2 2743 ));
  DATA(insert (	2745   1009 1009 3 2774 ));
! DATA(insert (	2745   1009 1009 4 2744 ));
  DATA(insert (	2745   1015 1015 1	360 ));
  DATA(insert (	2745   1015 1015 2 2743 ));
  DATA(insert (	2745   1015 1015 3 2774 ));
! DATA(insert (	2745   1015 1015 4 2744 ));
  DATA(insert (	2745   1023 1023 1 357 ));
  DATA(insert (	2745   1023 1023 2 2743 ));
  DATA(insert (	2745   1023 1023 3 2774 ));
! DATA(insert (	2745   1023 1023 4 2744 ));
  DATA(insert (	2745   1561 1561 1 1596 ));
  DATA(insert (	2745   1561 1561 2 2743 ));
  DATA(insert (	2745   1561 1561 3 2774 ));
! DATA(insert (	2745   1561 1561 4 2744 ));
  DATA(insert (	2745   1000 1000 1 1693 ));
  DATA(insert (	2745   1000 1000 2 2743 ));
  DATA(insert (	2745   1000 1000 3 2774 ));
! DATA(insert (	2745   1000 1000 4 2744 ));
  DATA(insert (	2745   1014 1014 1 1078 ));
  DATA(insert (	2745   1014 1014 2 2743 ));
  DATA(insert (	2745   1014 1014 3 2774 ));
! DATA(insert (	2745   1014 1014 4 2744 ));
  DATA(insert (	2745   1001 1001 1 1954 ));
  DATA(insert (	2745   1001 1001 2 2743 ));
  DATA(insert (	2745   1001 1001 3 2774 ));
! DATA(insert (	2745   1001 1001 4 2744 ));
  DATA(insert (	2745   1002 1002 1 358 ));
  DATA(insert (	2745   1002 1002 2 2743 ));
  DATA(insert (	2745   1002 1002 3 2774 ));
! DATA(insert (	2745   1002 1002 4 2744 ));
  DATA(insert (	2745   1182 1182 1 1092 ));
  DATA(insert (	2745   1182 1182 2 2743 ));
  DATA(insert (	2745   1182 1182 3 2774 ));
! DATA(insert (	2745   1182 1182 4 2744 ));
  DATA(insert (	2745   1021 1021 1 354 ));
  DATA(insert (	2745   1021 1021 2 2743 ));
  DATA(insert (	2745   1021 1021 3 2774 ));
! DATA(insert (	2745   1021 1021 4 2744 ));
  DATA(insert (	2745   1022 1022 1 355 ));
  DATA(insert (	2745   1022 1022 2 2743 ));
  DATA(insert (	2745   1022 1022 3 2774 ));
! DATA(insert (	2745   1022 1022 4 2744 ));
  DATA(insert (	2745   1041 1041 1 926 ));
  DATA(insert (	2745   1041 1041 2 2743 ));
  DATA(insert (	2745   1041 1041 3 2774 ));
! DATA(insert (	2745   1041 1041 4 2744 ));
  DATA(insert (	2745   651 651 1 926 ));
  DATA(insert (	2745   651 651 2 2743 ));
  DATA(insert (	2745   651 651 3 2774 ));
! DATA(insert (	2745   651 651 4 2744 ));
  DATA(insert (	2745   1005 1005 1 350 ));
  DATA(insert (	2745   1005 1005 2 2743 ));
  DATA(insert (	2745   1005 1005 3 2774 ));
! DATA(insert (	2745   1005 1005 4 2744 ));
  DATA(insert (	2745   1016 1016 1 842 ));
  DATA(insert (	2745   1016 1016 2 2743 ));
  DATA(insert (	2745   1016 1016 3 2774 ));
! DATA(insert (	2745   1016 1016 4 2744 ));
  DATA(insert (	2745   1187 1187 1 1315 ));
  DATA(insert (	2745   1187 1187 2 2743 ));
  DATA(insert (	2745   1187 1187 3 2774 ));
! DATA(insert (	2745   1187 1187 4 2744 ));
  DATA(insert (	2745   1040 1040 1 836 ));
  DATA(insert (	2745   1040 1040 2 2743 ));
  DATA(insert (	2745   1040 1040 3 2774 ));
! DATA(insert (	2745   1040 1040 4 2744 ));
  DATA(insert (	2745   1003 1003 1 359 ));
  DATA(insert (	2745   1003 1003 2 2743 ));
  DATA(insert (	2745   1003 1003 3 2774 ));
! DATA(insert (	2745   1003 1003 4 2744 ));
  DATA(insert (	2745   1231 1231 1 1769 ));
  DATA(insert (	2745   1231 1231 2 2743 ));
  DATA(insert (	2745   1231 1231 3 2774 ));
! DATA(insert (	2745   1231 1231 4 2744 ));
  DATA(insert (	2745   1028 1028 1 356 ));
  DATA(insert (	2745   1028 1028 2 2743 ));
  DATA(insert (	2745   1028 1028 3 2774 ));
! DATA(insert (	2745   1028 1028 4 2744 ));
  DATA(insert (	2745   1013 1013 1 404 ));
  DATA(insert (	2745   1013 1013 2 2743 ));
  DATA(insert (	2745   1013 1013 3 2774 ));
! DATA(insert (	2745   1013 1013 4 2744 ));
  DATA(insert (	2745   1183 1183 1 1107 ));
  DATA(insert (	2745   1183 1183 2 2743 ));
  DATA(insert (	2745   1183 1183 3 2774 ));
! DATA(insert (	2745   1183 1183 4 2744 ));
  DATA(insert (	2745   1185 1185 1 1314 ));
  DATA(insert (	2745   1185 1185 2 2743 ));
  DATA(insert (	2745   1185 1185 3 2774 ));
! DATA(insert (	2745   1185 1185 4 2744 ));
  DATA(insert (	2745   1270 1270 1 1358 ));
  DATA(insert (	2745   1270 1270 2 2743 ));
  DATA(insert (	2745   1270 1270 3 2774 ));
! DATA(insert (	2745   1270 1270 4 2744 ));
  DATA(insert (	2745   1563 1563 1 1672 ));
  DATA(insert (	2745   1563 1563 2 2743 ));
  DATA(insert (	2745   1563 1563 3 2774 ));
! DATA(insert (	2745   1563 1563 4 2744 ));
  DATA(insert (	2745   1115 1115 1 2045 ));
  DATA(insert (	2745   1115 1115 2 2743 ));
  DATA(insert (	2745   1115 1115 3 2774 ));
! DATA(insert (	2745   1115 1115 4 2744 ));
  DATA(insert (	2745   791 791 1 377 ));
  DATA(insert (	2745   791 791 2 2743 ));
  DATA(insert (	2745   791 791 3 2774 ));
! DATA(insert (	2745   791 791 4 2744 ));
  DATA(insert (	2745   1024 1024 1 380 ));
  DATA(insert (	2745   1024 1024 2 2743 ));
  DATA(insert (	2745   1024 1024 3 2774 ));
! DATA(insert (	2745   1024 1024 4 2744 ));
  DATA(insert (	2745   1025 1025 1 381 ));
  DATA(insert (	2745   1025 1025 2 2743 ));
  DATA(insert (	2745   1025 1025 3 2774 ));
! DATA(insert (	2745   1025 1025 4 2744 ));
  DATA(insert (	3659   3614 3614 1 3724 ));
  DATA(insert (	3659   3614 3614 2 3656 ));
  DATA(insert (	3659   3614 3614 3 3657 ));
! DATA(insert (	3659   3614 3614 4 3658 ));
  DATA(insert (	3659   3614 3614 5 2700 ));
  
  
--- 234,360 ----
  DATA(insert (	2745   1007 1007 1	351 ));
  DATA(insert (	2745   1007 1007 2 2743 ));
  DATA(insert (	2745   1007 1007 3 2774 ));
! DATA(insert (	2745   1007 1007 6 2744 ));
  DATA(insert (	2745   1009 1009 1	360 ));
  DATA(insert (	2745   1009 1009 2 2743 ));
  DATA(insert (	2745   1009 1009 3 2774 ));
! DATA(insert (	2745   1009 1009 6 2744 ));
  DATA(insert (	2745   1015 1015 1	360 ));
  DATA(insert (	2745   1015 1015 2 2743 ));
  DATA(insert (	2745   1015 1015 3 2774 ));
! DATA(insert (	2745   1015 1015 6 2744 ));
  DATA(insert (	2745   1023 1023 1 357 ));
  DATA(insert (	2745   1023 1023 2 2743 ));
  DATA(insert (	2745   1023 1023 3 2774 ));
! DATA(insert (	2745   1023 1023 6 2744 ));
  DATA(insert (	2745   1561 1561 1 1596 ));
  DATA(insert (	2745   1561 1561 2 2743 ));
  DATA(insert (	2745   1561 1561 3 2774 ));
! DATA(insert (	2745   1561 1561 6 2744 ));
  DATA(insert (	2745   1000 1000 1 1693 ));
  DATA(insert (	2745   1000 1000 2 2743 ));
  DATA(insert (	2745   1000 1000 3 2774 ));
! DATA(insert (	2745   1000 1000 6 2744 ));
  DATA(insert (	2745   1014 1014 1 1078 ));
  DATA(insert (	2745   1014 1014 2 2743 ));
  DATA(insert (	2745   1014 1014 3 2774 ));
! DATA(insert (	2745   1014 1014 6 2744 ));
  DATA(insert (	2745   1001 1001 1 1954 ));
  DATA(insert (	2745   1001 1001 2 2743 ));
  DATA(insert (	2745   1001 1001 3 2774 ));
! DATA(insert (	2745   1001 1001 6 2744 ));
  DATA(insert (	2745   1002 1002 1 358 ));
  DATA(insert (	2745   1002 1002 2 2743 ));
  DATA(insert (	2745   1002 1002 3 2774 ));
! DATA(insert (	2745   1002 1002 6 2744 ));
  DATA(insert (	2745   1182 1182 1 1092 ));
  DATA(insert (	2745   1182 1182 2 2743 ));
  DATA(insert (	2745   1182 1182 3 2774 ));
! DATA(insert (	2745   1182 1182 6 2744 ));
  DATA(insert (	2745   1021 1021 1 354 ));
  DATA(insert (	2745   1021 1021 2 2743 ));
  DATA(insert (	2745   1021 1021 3 2774 ));
! DATA(insert (	2745   1021 1021 6 2744 ));
  DATA(insert (	2745   1022 1022 1 355 ));
  DATA(insert (	2745   1022 1022 2 2743 ));
  DATA(insert (	2745   1022 1022 3 2774 ));
! DATA(insert (	2745   1022 1022 6 2744 ));
  DATA(insert (	2745   1041 1041 1 926 ));
  DATA(insert (	2745   1041 1041 2 2743 ));
  DATA(insert (	2745   1041 1041 3 2774 ));
! DATA(insert (	2745   1041 1041 6 2744 ));
  DATA(insert (	2745   651 651 1 926 ));
  DATA(insert (	2745   651 651 2 2743 ));
  DATA(insert (	2745   651 651 3 2774 ));
! DATA(insert (	2745   651 651 6 2744 ));
  DATA(insert (	2745   1005 1005 1 350 ));
  DATA(insert (	2745   1005 1005 2 2743 ));
  DATA(insert (	2745   1005 1005 3 2774 ));
! DATA(insert (	2745   1005 1005 6 2744 ));
  DATA(insert (	2745   1016 1016 1 842 ));
  DATA(insert (	2745   1016 1016 2 2743 ));
  DATA(insert (	2745   1016 1016 3 2774 ));
! DATA(insert (	2745   1016 1016 6 2744 ));
  DATA(insert (	2745   1187 1187 1 1315 ));
  DATA(insert (	2745   1187 1187 2 2743 ));
  DATA(insert (	2745   1187 1187 3 2774 ));
! DATA(insert (	2745   1187 1187 6 2744 ));
  DATA(insert (	2745   1040 1040 1 836 ));
  DATA(insert (	2745   1040 1040 2 2743 ));
  DATA(insert (	2745   1040 1040 3 2774 ));
! DATA(insert (	2745   1040 1040 6 2744 ));
  DATA(insert (	2745   1003 1003 1 359 ));
  DATA(insert (	2745   1003 1003 2 2743 ));
  DATA(insert (	2745   1003 1003 3 2774 ));
! DATA(insert (	2745   1003 1003 6 2744 ));
  DATA(insert (	2745   1231 1231 1 1769 ));
  DATA(insert (	2745   1231 1231 2 2743 ));
  DATA(insert (	2745   1231 1231 3 2774 ));
! DATA(insert (	2745   1231 1231 6 2744 ));
  DATA(insert (	2745   1028 1028 1 356 ));
  DATA(insert (	2745   1028 1028 2 2743 ));
  DATA(insert (	2745   1028 1028 3 2774 ));
! DATA(insert (	2745   1028 1028 6 2744 ));
  DATA(insert (	2745   1013 1013 1 404 ));
  DATA(insert (	2745   1013 1013 2 2743 ));
  DATA(insert (	2745   1013 1013 3 2774 ));
! DATA(insert (	2745   1013 1013 6 2744 ));
  DATA(insert (	2745   1183 1183 1 1107 ));
  DATA(insert (	2745   1183 1183 2 2743 ));
  DATA(insert (	2745   1183 1183 3 2774 ));
! DATA(insert (	2745   1183 1183 6 2744 ));
  DATA(insert (	2745   1185 1185 1 1314 ));
  DATA(insert (	2745   1185 1185 2 2743 ));
  DATA(insert (	2745   1185 1185 3 2774 ));
! DATA(insert (	2745   1185 1185 6 2744 ));
  DATA(insert (	2745   1270 1270 1 1358 ));
  DATA(insert (	2745   1270 1270 2 2743 ));
  DATA(insert (	2745   1270 1270 3 2774 ));
! DATA(insert (	2745   1270 1270 6 2744 ));
  DATA(insert (	2745   1563 1563 1 1672 ));
  DATA(insert (	2745   1563 1563 2 2743 ));
  DATA(insert (	2745   1563 1563 3 2774 ));
! DATA(insert (	2745   1563 1563 6 2744 ));
  DATA(insert (	2745   1115 1115 1 2045 ));
  DATA(insert (	2745   1115 1115 2 2743 ));
  DATA(insert (	2745   1115 1115 3 2774 ));
! DATA(insert (	2745   1115 1115 6 2744 ));
  DATA(insert (	2745   791 791 1 377 ));
  DATA(insert (	2745   791 791 2 2743 ));
  DATA(insert (	2745   791 791 3 2774 ));
! DATA(insert (	2745   791 791 6 2744 ));
  DATA(insert (	2745   1024 1024 1 380 ));
  DATA(insert (	2745   1024 1024 2 2743 ));
  DATA(insert (	2745   1024 1024 3 2774 ));
! DATA(insert (	2745   1024 1024 6 2744 ));
  DATA(insert (	2745   1025 1025 1 381 ));
  DATA(insert (	2745   1025 1025 2 2743 ));
  DATA(insert (	2745   1025 1025 3 2774 ));
! DATA(insert (	2745   1025 1025 6 2744 ));
  DATA(insert (	3659   3614 3614 1 3724 ));
  DATA(insert (	3659   3614 3614 2 3656 ));
  DATA(insert (	3659   3614 3614 3 3657 ));
! DATA(insert (	3659   3614 3614 6 3658 ));
  DATA(insert (	3659   3614 3614 5 2700 ));
  
  
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
new file mode 100644
index 26abe8a..3b91877
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p2.opfmethod = p1.oid AND p3.ampro
*** 1306,1312 ****
             p4.amproclefttype = p3.amproclefttype AND
             p4.amprocrighttype = p3.amprocrighttype)
      NOT BETWEEN
!       (CASE WHEN p1.amname IN ('btree', 'gist', 'gin') THEN p1.amsupport - 1
              ELSE p1.amsupport END)
        AND p1.amsupport;
   amname | opfname | amproclefttype | amprocrighttype 
--- 1306,1313 ----
             p4.amproclefttype = p3.amproclefttype AND
             p4.amprocrighttype = p3.amprocrighttype)
      NOT BETWEEN
!       (CASE WHEN p1.amname IN ('btree', 'gist') THEN p1.amsupport - 1
!             WHEN p1.amname = 'gin' THEN p1.amsupport - 2
              ELSE p1.amsupport END)
        AND p1.amsupport;
   amname | opfname | amproclefttype | amprocrighttype 
*************** FROM pg_am am JOIN pg_opclass op ON opcm
*** 1333,1339 ****
           amproclefttype = amprocrighttype AND amproclefttype = opcintype
  WHERE am.amname = 'btree' OR am.amname = 'gist' OR am.amname = 'gin'
  GROUP BY amname, amsupport, opcname, amprocfamily
! HAVING (count(*) != amsupport AND count(*) != amsupport - 1)
      OR amprocfamily IS NULL;
   amname | opcname | count 
  --------+---------+-------
--- 1334,1341 ----
           amproclefttype = amprocrighttype AND amproclefttype = opcintype
  WHERE am.amname = 'btree' OR am.amname = 'gist' OR am.amname = 'gin'
  GROUP BY amname, amsupport, opcname, amprocfamily
! HAVING (count(*) != amsupport AND count(*) != amsupport - 1 AND
!        (count(*) != amsupport - 2 OR am.amname <> 'gin'))
      OR amprocfamily IS NULL;
   amname | opcname | count 
  --------+---------+-------
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
new file mode 100644
index 40e1be2..6dd93f9
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p2.opfmethod = p1.oid AND p3.ampro
*** 1002,1008 ****
             p4.amproclefttype = p3.amproclefttype AND
             p4.amprocrighttype = p3.amprocrighttype)
      NOT BETWEEN
!       (CASE WHEN p1.amname IN ('btree', 'gist', 'gin') THEN p1.amsupport - 1
              ELSE p1.amsupport END)
        AND p1.amsupport;
  
--- 1002,1009 ----
             p4.amproclefttype = p3.amproclefttype AND
             p4.amprocrighttype = p3.amprocrighttype)
      NOT BETWEEN
!       (CASE WHEN p1.amname IN ('btree', 'gist') THEN p1.amsupport - 1
!             WHEN p1.amname = 'gin' THEN p1.amsupport - 2
              ELSE p1.amsupport END)
        AND p1.amsupport;
  
*************** FROM pg_am am JOIN pg_opclass op ON opcm
*** 1024,1030 ****
           amproclefttype = amprocrighttype AND amproclefttype = opcintype
  WHERE am.amname = 'btree' OR am.amname = 'gist' OR am.amname = 'gin'
  GROUP BY amname, amsupport, opcname, amprocfamily
! HAVING (count(*) != amsupport AND count(*) != amsupport - 1)
      OR amprocfamily IS NULL;
  
  -- Unfortunately, we can't check the amproc link very well because the
--- 1025,1032 ----
           amproclefttype = amprocrighttype AND amproclefttype = opcintype
  WHERE am.amname = 'btree' OR am.amname = 'gist' OR am.amname = 'gin'
  GROUP BY amname, amsupport, opcname, amprocfamily
! HAVING (count(*) != amsupport AND count(*) != amsupport - 1 AND
!        (count(*) != amsupport - 2 OR am.amname <> 'gin'))
      OR amprocfamily IS NULL;
  
  -- Unfortunately, we can't check the amproc link very well because the
