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/README b/src/backend/access/gin/README
new file mode 100644
index 3f0c3e2..6750769
*** a/src/backend/access/gin/README
--- b/src/backend/access/gin/README
*************** page-deletions safe; it stamps the delet
*** 335,340 ****
--- 335,346 ----
  deleted pages around with the right-link intact until all concurrent scans
  have finished.)
  
+ Fast scan
+ ---------
+ 
+ Fast scan is technique which allows to skip parts of large posting-trees during
+ gin index scan. 
+ 
  Compatibility
  -------------
  
*************** posting list fits in the space occupied 
*** 365,370 ****
--- 371,400 ----
  assume that the compressed version of the page, with the dead items removed,
  takes less space than the old uncompressed version.
  
+ Fast scan
+ ---------
+ 
+ Fast scan is technique allowing to skip parts of large posting trees during
+ gin index scans. Fast scan is based on tri-state consistent function. Tri-state
+ consistent function must support following values:
+ 1) TRUE
+ 2) FALSE
+ 3) UNKNOWN
+ GIN passes UNKNOWN into check array for those keys which parts of posting trees
+ it tries to skip. If consistent function returns false then it can actually
+ skip part of posting tree.
+ 
+ In more details fast scans works following:
+ 1) Keep entries sorted by their current TIDs descending.
+ 2) Tries to skip some of entries at the end of sorted order. It passes
+    TRUE for the first part of entries and UNKNOWN for others. It moves the
+    border splitting TRUE and UNKNOWN until finds where consistent begins to
+    return FALSE.
+ 3) If tri-state consistent returns FALSE, it skips part of shortest entry which
+    was UNKNOWN (other entries could be skipped later for greater value). 
+ 4) If tri-state consistent doesn't return FALSE then it calls exact consistent
+    and moves entries TIDs like regular gin index scan.
+ 
  Limitations
  -----------
  
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..e50278b
*** 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,254 ----
  	return gcv->check[j];
  }
  
+ /*
+  * Evaluate tsquery boolean expression.
+  *
+  * 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.
+  * if calcnot is false, NOT expressions are always evaluated to be true. This
+  * is used in ranking.
+  */
+ static GinLogicValue
+ TS_execute_tri_state(QueryItem *curitem, void *checkval, bool calcnot,
+ 		GinLogicValue (*chkcond) (void *checkval, QueryOperand *val))
+ {
+ 	GinLogicValue 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(curitem + 1, checkval, calcnot, chkcond);
+ 			if (result == GIN_MAYBE)
+ 				return result;
+ 			return !result;
+ 
+ 		case OP_AND:
+ 			result = TS_execute(curitem + curitem->qoperator.left, checkval, calcnot, chkcond);
+ 			if (result == GIN_TRUE)
+ 				return TS_execute(curitem + 1, checkval, calcnot, chkcond);
+ 			else
+ 				return result;
+ 
+ 		case OP_OR:
+ 			result = TS_execute(curitem + curitem->qoperator.left, checkval, calcnot, chkcond);
+ 			if (result == GIN_FALSE)
+ 				return TS_execute(curitem + 1, checkval, calcnot, chkcond);
+ 			else
+ 				return result;
+ 
+ 		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;
--- 256,262 ----
  	/* int32	nkeys = PG_GETARG_INT32(3); */
  	Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4);
  	bool	   *recheck = (bool *) PG_GETARG_POINTER(5);
! 	GinLogicValue res = 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);
--- 275,284 ----
  		gcv.map_item_operand = (int *) (extra_data[0]);
  		gcv.need_recheck = recheck;
  
! 		res = TS_execute_tri_state(GETQUERY(query),
! 								   &gcv,
! 								   true,
! 								   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..9c77a0e
*** 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,61 ----
  	int32		ginVersion;
  } GinStatsData;
  
+ enum
+ {
+ 	GIN_FALSE = 0,
+ 	GIN_TRUE = 1,
+ 	GIN_MAYBE = 2
+ } 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 6d6a49a..8f83137
*** a/src/include/access/gin_private.h
--- b/src/include/access/gin_private.h
*************** typedef struct GinState
*** 355,360 ****
--- 355,362 ----
  	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 Datum gintuple_get_key(GinState *
*** 592,606 ****
  
  /* ginlogic.c */
  
- enum
- {
- 	GIN_FALSE = 0,
- 	GIN_TRUE = 1,
- 	GIN_MAYBE = 2
- } GinLogicValueEnum;
- 
- typedef char GinLogicValue;
- 
  extern void GinInitConsistentMethod(GinState *ginstate, GinScanKey key);
  
  /* gininsert.c */
--- 594,599 ----
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 c090be4..ce09c64
*** a/src/include/catalog/pg_amproc.h
--- b/src/include/catalog/pg_amproc.h
*************** DATA(insert (	1029   600 600 8 3064 ));
*** 223,349 ****
  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 ));
  DATA(insert (	3626   3614 3614 1 3622 ));
  DATA(insert (	3683   3615 3615 1 3668 ));
--- 223,349 ----
  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 ));
  DATA(insert (	3626   3614 3614 1 3622 ));
  DATA(insert (	3683   3615 3615 1 3668 ));
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
