From db5f98ab4fa44bc563ec62d7b1aada4fc276d9b2 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Thu, 7 May 2015 13:02:22 -0300
Subject: [PATCH] Improve BRIN infra, minmax opclass and regression test
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The minmax opclass was using the wrong support functions when
cross-datatypes queries were run.  Instead of trying to fix the
pg_amproc definitions (which apparently is not possible), use the
already correct pg_amop entries instead.  This requires jumping through
more hoops (read: extra syscache lookups) to obtain the underlying
functions to execute, but it is necessary for correctness.

Author: Emre Hasegeli, tweaked by Álvaro
Review: Andreas Karlsson

Also change BrinOpcInfo to record each stored type's typecache entry
instead of just the OID.  Turns out that the full type cache is
necessary in brin_deform_tuple: the original code used the indexed
type's byval and typlen properties to extract the stored tuple, which is
correct in Minmax; but in other implementations that want to store
something different, that's wrong.  The realization that this is a bug
comes from Emre also, but I did not use his patch.

I also adopted Emre's regression test code (with smallish changes),
which is more complete.
---
 contrib/pageinspect/brinfuncs.c       |   2 +-
 doc/src/sgml/brin.sgml                |   4 +-
 src/backend/access/brin/brin_minmax.c | 154 ++++++++++++---------
 src/backend/access/brin/brin_tuple.c  |   6 +-
 src/include/access/brin_internal.h    |   7 +-
 src/include/catalog/catversion.h      |   2 +-
 src/include/catalog/pg_amproc.h       | 164 ----------------------
 src/include/catalog/pg_opclass.h      |  54 ++++----
 src/test/regress/expected/brin.out    | 188 ++++++++++++++++---------
 src/test/regress/sql/brin.sql         | 192 ++++++++++++++++----------
 10 files changed, 369 insertions(+), 404 deletions(-)

diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 1b15a7bdfe3..bd3191d5d28 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -181,7 +181,7 @@ brin_page_items(PG_FUNCTION_ARGS)
 			column->nstored = opcinfo->oi_nstored;
 			for (i = 0; i < opcinfo->oi_nstored; i++)
 			{
-				getTypeOutputInfo(opcinfo->oi_typids[i], &output, &isVarlena);
+				getTypeOutputInfo(opcinfo->oi_typcache[i]->type_id, &output, &isVarlena);
 				fmgr_info(output, &column->outputFn[i]);
 			}
 
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index 1ac282c57a6..92dac7c60b5 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -428,8 +428,8 @@ typedef struct BrinOpcInfo
     /* Opaque pointer for the opclass' private use */
     void       *oi_opaque;
 
-    /* Type IDs of the stored columns */
-    Oid         oi_typids[FLEXIBLE_ARRAY_MEMBER];
+    /* Type cache entries of the stored columns */
+    TypeCacheEntry *oi_typcache[FLEXIBLE_ARRAY_MEMBER];
 } BrinOpcInfo;
 </programlisting>
       <structname>BrinOpcInfo</>.<structfield>oi_opaque</> can be used by the
diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c
index 299d6f7bf6e..d9fa9cd5976 100644
--- a/src/backend/access/brin/brin_minmax.c
+++ b/src/backend/access/brin/brin_minmax.c
@@ -15,35 +15,21 @@
 #include "access/brin_tuple.h"
 #include "access/skey.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_amop.h"
 #include "utils/datum.h"
 #include "utils/lsyscache.h"
+#include "utils/rel.h"
 #include "utils/syscache.h"
 
 
-/*
- * Procedure numbers must not collide with BRIN_PROCNUM defines in
- * brin_internal.h.  Note we only need inequality functions.
- */
-#define		MINMAX_NUM_PROCNUMS		4	/* # support procs we need */
-#define		PROCNUM_LESS			11
-#define		PROCNUM_LESSEQUAL		12
-#define		PROCNUM_GREATEREQUAL	13
-#define		PROCNUM_GREATER			14
-
-/*
- * Subtract this from procnum to obtain index in MinmaxOpaque arrays
- * (Must be equal to minimum of private procnums)
- */
-#define		PROCNUM_BASE			11
-
 typedef struct MinmaxOpaque
 {
-	FmgrInfo	operators[MINMAX_NUM_PROCNUMS];
-	bool		inited[MINMAX_NUM_PROCNUMS];
+	Oid			cached_subtype;
+	FmgrInfo	strategy_procinfos[BTMaxStrategyNumber];
 } MinmaxOpaque;
 
-static FmgrInfo *minmax_get_procinfo(BrinDesc *bdesc, uint16 attno,
-					uint16 procnum);
+static FmgrInfo *minmax_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno,
+					Oid subtype, uint16 strategynum);
 
 
 Datum
@@ -53,8 +39,8 @@ brin_minmax_opcinfo(PG_FUNCTION_ARGS)
 	BrinOpcInfo *result;
 
 	/*
-	 * opaque->operators is initialized lazily, as indicated by 'inited' which
-	 * is initialized to all false by palloc0.
+	 * opaque->strategy_procinfos is initialized lazily; here it is set to
+	 * all-uninitialized by palloc0 which sets fn_oid to InvalidOid.
 	 */
 
 	result = palloc0(MAXALIGN(SizeofBrinOpcInfo(2)) +
@@ -62,8 +48,8 @@ brin_minmax_opcinfo(PG_FUNCTION_ARGS)
 	result->oi_nstored = 2;
 	result->oi_opaque = (MinmaxOpaque *)
 		MAXALIGN((char *) result + SizeofBrinOpcInfo(2));
-	result->oi_typids[0] = typoid;
-	result->oi_typids[1] = typoid;
+	result->oi_typcache[0] = result->oi_typcache[1] =
+		lookup_type_cache(typoid, 0);
 
 	PG_RETURN_POINTER(result);
 }
@@ -122,7 +108,8 @@ brin_minmax_add_value(PG_FUNCTION_ARGS)
 	 * and update them accordingly.  First check if it's less than the
 	 * existing minimum.
 	 */
-	cmpFn = minmax_get_procinfo(bdesc, attno, PROCNUM_LESS);
+	cmpFn = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid,
+										 BTLessStrategyNumber);
 	compar = FunctionCall2Coll(cmpFn, colloid, newval, column->bv_values[0]);
 	if (DatumGetBool(compar))
 	{
@@ -135,7 +122,8 @@ brin_minmax_add_value(PG_FUNCTION_ARGS)
 	/*
 	 * And now compare it to the existing maximum.
 	 */
-	cmpFn = minmax_get_procinfo(bdesc, attno, PROCNUM_GREATER);
+	cmpFn = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid,
+										 BTGreaterStrategyNumber);
 	compar = FunctionCall2Coll(cmpFn, colloid, newval, column->bv_values[1]);
 	if (DatumGetBool(compar))
 	{
@@ -159,10 +147,12 @@ brin_minmax_consistent(PG_FUNCTION_ARGS)
 	BrinDesc   *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
 	BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
 	ScanKey		key = (ScanKey) PG_GETARG_POINTER(2);
-	Oid			colloid = PG_GET_COLLATION();
+	Oid			colloid = PG_GET_COLLATION(),
+				subtype;
 	AttrNumber	attno;
 	Datum		value;
 	Datum		matches;
+	FmgrInfo   *finfo;
 
 	Assert(key->sk_attno == column->bv_attno);
 
@@ -189,18 +179,16 @@ brin_minmax_consistent(PG_FUNCTION_ARGS)
 		PG_RETURN_BOOL(false);
 
 	attno = key->sk_attno;
+	subtype = key->sk_subtype;
 	value = key->sk_argument;
 	switch (key->sk_strategy)
 	{
 		case BTLessStrategyNumber:
-			matches = FunctionCall2Coll(minmax_get_procinfo(bdesc, attno,
-															PROCNUM_LESS),
-										colloid, column->bv_values[0], value);
-			break;
 		case BTLessEqualStrategyNumber:
-			matches = FunctionCall2Coll(minmax_get_procinfo(bdesc, attno,
-														  PROCNUM_LESSEQUAL),
-										colloid, column->bv_values[0], value);
+			finfo = minmax_get_strategy_procinfo(bdesc, attno, subtype,
+												 key->sk_strategy);
+			matches = FunctionCall2Coll(finfo, colloid, column->bv_values[0],
+										value);
 			break;
 		case BTEqualStrategyNumber:
 
@@ -209,25 +197,24 @@ brin_minmax_consistent(PG_FUNCTION_ARGS)
 			 * the current page range if the minimum value in the range <=
 			 * scan key, and the maximum value >= scan key.
 			 */
-			matches = FunctionCall2Coll(minmax_get_procinfo(bdesc, attno,
-														  PROCNUM_LESSEQUAL),
-										colloid, column->bv_values[0], value);
+			finfo = minmax_get_strategy_procinfo(bdesc, attno, subtype,
+												 BTLessEqualStrategyNumber);
+			matches = FunctionCall2Coll(finfo, colloid, column->bv_values[0],
+										value);
 			if (!DatumGetBool(matches))
 				break;
 			/* max() >= scankey */
-			matches = FunctionCall2Coll(minmax_get_procinfo(bdesc, attno,
-													   PROCNUM_GREATEREQUAL),
-										colloid, column->bv_values[1], value);
+			finfo = minmax_get_strategy_procinfo(bdesc, attno, subtype,
+												 BTGreaterEqualStrategyNumber);
+			matches = FunctionCall2Coll(finfo, colloid, column->bv_values[1],
+										value);
 			break;
 		case BTGreaterEqualStrategyNumber:
-			matches = FunctionCall2Coll(minmax_get_procinfo(bdesc, attno,
-													   PROCNUM_GREATEREQUAL),
-										colloid, column->bv_values[1], value);
-			break;
 		case BTGreaterStrategyNumber:
-			matches = FunctionCall2Coll(minmax_get_procinfo(bdesc, attno,
-															PROCNUM_GREATER),
-										colloid, column->bv_values[1], value);
+			finfo = minmax_get_strategy_procinfo(bdesc, attno, subtype,
+												 key->sk_strategy);
+			matches = FunctionCall2Coll(finfo, colloid, column->bv_values[1],
+										value);
 			break;
 		default:
 			/* shouldn't happen */
@@ -252,6 +239,7 @@ brin_minmax_union(PG_FUNCTION_ARGS)
 	Oid			colloid = PG_GET_COLLATION();
 	AttrNumber	attno;
 	Form_pg_attribute attr;
+	FmgrInfo   *finfo;
 	bool		needsadj;
 
 	Assert(col_a->bv_attno == col_b->bv_attno);
@@ -284,9 +272,10 @@ brin_minmax_union(PG_FUNCTION_ARGS)
 	}
 
 	/* Adjust minimum, if B's min is less than A's min */
-	needsadj = FunctionCall2Coll(minmax_get_procinfo(bdesc, attno,
-													 PROCNUM_LESS),
-						  colloid, col_b->bv_values[0], col_a->bv_values[0]);
+	finfo = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid,
+										 BTLessStrategyNumber);
+	needsadj = FunctionCall2Coll(finfo, colloid, col_b->bv_values[0],
+								 col_a->bv_values[0]);
 	if (needsadj)
 	{
 		if (!attr->attbyval)
@@ -296,9 +285,10 @@ brin_minmax_union(PG_FUNCTION_ARGS)
 	}
 
 	/* Adjust maximum, if B's max is greater than A's max */
-	needsadj = FunctionCall2Coll(minmax_get_procinfo(bdesc, attno,
-													 PROCNUM_GREATER),
-						  colloid, col_b->bv_values[1], col_a->bv_values[1]);
+	finfo = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid,
+										 BTGreaterStrategyNumber);
+	needsadj = FunctionCall2Coll(finfo, colloid, col_b->bv_values[1],
+								 col_a->bv_values[1]);
 	if (needsadj)
 	{
 		if (!attr->attbyval)
@@ -311,27 +301,61 @@ brin_minmax_union(PG_FUNCTION_ARGS)
 }
 
 /*
- * Return the procedure corresponding to the given function support number.
+ * Cache and return the procedure for the given strategy.
  */
-static FmgrInfo *
-minmax_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
+FmgrInfo *
+minmax_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype,
+							 uint16 strategynum)
 {
 	MinmaxOpaque *opaque;
-	uint16		basenum = procnum - PROCNUM_BASE;
+
+	Assert(strategynum >= 1 &&
+		   strategynum <= BTMaxStrategyNumber);
 
 	opaque = (MinmaxOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
 
 	/*
-	 * We cache these in the opaque struct, to avoid repetitive syscache
-	 * lookups.
+	 * We cache the procedures for the previous subtype in the opaque struct,
+	 * to avoid repetitive syscache lookups.  If the subtype changed,
+	 * invalidate all the cached entries.
 	 */
-	if (!opaque->inited[basenum])
+	if (opaque->cached_subtype != subtype)
+	{
+		uint16		i;
+
+		for (i = 1; i <= BTMaxStrategyNumber; i++)
+			opaque->strategy_procinfos[i - 1].fn_oid = InvalidOid;
+		opaque->cached_subtype = subtype;
+	}
+
+	if (opaque->strategy_procinfos[strategynum - 1].fn_oid == InvalidOid)
 	{
-		fmgr_info_copy(&opaque->operators[basenum],
-					   index_getprocinfo(bdesc->bd_index, attno, procnum),
-					   bdesc->bd_context);
-		opaque->inited[basenum] = true;
+		Form_pg_attribute attr;
+		HeapTuple	tuple;
+		Oid			opfamily,
+					oprid;
+		bool		isNull;
+
+		opfamily = bdesc->bd_index->rd_opfamily[attno - 1];
+		attr = bdesc->bd_tupdesc->attrs[attno - 1];
+		tuple = SearchSysCache4(AMOPSTRATEGY, ObjectIdGetDatum(opfamily),
+								ObjectIdGetDatum(attr->atttypid),
+								ObjectIdGetDatum(subtype),
+								Int16GetDatum(strategynum));
+
+		if (!HeapTupleIsValid(tuple))
+			elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
+				 strategynum, attr->atttypid, subtype, opfamily);
+
+		oprid = DatumGetObjectId(SysCacheGetAttr(AMOPSTRATEGY, tuple,
+												 Anum_pg_amop_amopopr, &isNull));
+		ReleaseSysCache(tuple);
+		Assert(!isNull && RegProcedureIsValid(oprid));
+
+		fmgr_info_cxt(get_opcode(oprid),
+					  &opaque->strategy_procinfos[strategynum - 1],
+					  bdesc->bd_context);
 	}
 
-	return &opaque->operators[basenum];
+	return &opaque->strategy_procinfos[strategynum - 1];
 }
diff --git a/src/backend/access/brin/brin_tuple.c b/src/backend/access/brin/brin_tuple.c
index 08fa998a525..22ce74a4f43 100644
--- a/src/backend/access/brin/brin_tuple.c
+++ b/src/backend/access/brin/brin_tuple.c
@@ -68,7 +68,7 @@ brtuple_disk_tupdesc(BrinDesc *brdesc)
 		{
 			for (j = 0; j < brdesc->bd_info[i]->oi_nstored; j++)
 				TupleDescInitEntry(tupdesc, attno++, NULL,
-								   brdesc->bd_info[i]->oi_typids[j],
+								   brdesc->bd_info[i]->oi_typcache[j]->type_id,
 								   -1, 0);
 		}
 
@@ -444,8 +444,8 @@ brin_deform_tuple(BrinDesc *brdesc, BrinTuple *tuple)
 		for (i = 0; i < brdesc->bd_info[keyno]->oi_nstored; i++)
 			dtup->bt_columns[keyno].bv_values[i] =
 				datumCopy(values[valueno++],
-						  brdesc->bd_tupdesc->attrs[keyno]->attbyval,
-						  brdesc->bd_tupdesc->attrs[keyno]->attlen);
+						  brdesc->bd_info[keyno]->oi_typcache[i]->typbyval,
+						  brdesc->bd_info[keyno]->oi_typcache[i]->typlen);
 
 		dtup->bt_columns[keyno].bv_hasnulls = hasnulls[keyno];
 		dtup->bt_columns[keyno].bv_allnulls = false;
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
index 84eed6127dd..1486d046935 100644
--- a/src/include/access/brin_internal.h
+++ b/src/include/access/brin_internal.h
@@ -16,6 +16,7 @@
 #include "storage/bufpage.h"
 #include "storage/off.h"
 #include "utils/relcache.h"
+#include "utils/typcache.h"
 
 
 /*
@@ -32,13 +33,13 @@ typedef struct BrinOpcInfo
 	/* Opaque pointer for the opclass' private use */
 	void	   *oi_opaque;
 
-	/* Type IDs of the stored columns */
-	Oid			oi_typids[FLEXIBLE_ARRAY_MEMBER];
+	/* Type cache entries of the stored columns */
+	TypeCacheEntry *oi_typcache[FLEXIBLE_ARRAY_MEMBER];
 } BrinOpcInfo;
 
 /* the size of a BrinOpcInfo for the given number of columns */
 #define SizeofBrinOpcInfo(ncols) \
-	(offsetof(BrinOpcInfo, oi_typids) + sizeof(Oid) * ncols)
+	(offsetof(BrinOpcInfo, oi_typcache) + sizeof(TypeCacheEntry *) * ncols)
 
 typedef struct BrinDesc
 {
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index e8320daedbb..2444e543a70 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	201505051
+#define CATALOG_VERSION_NO	201505071
 
 #endif
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index a54d11fdbda..e3de3b57e79 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -443,360 +443,196 @@ DATA(insert (   4064    17    17  1  3383 ));
 DATA(insert (   4064    17    17  2  3384 ));
 DATA(insert (   4064    17    17  3  3385 ));
 DATA(insert (   4064    17    17  4  3386 ));
-DATA(insert (   4064    17    17  11 1949 ));
-DATA(insert (   4064    17    17  12 1950 ));
-DATA(insert (   4064    17    17  13 1952 ));
-DATA(insert (   4064    17    17  14 1951 ));
 /* minmax "char" */
 DATA(insert (   4062    18    18  1  3383 ));
 DATA(insert (   4062    18    18  2  3384 ));
 DATA(insert (   4062    18    18  3  3385 ));
 DATA(insert (   4062    18    18  4  3386 ));
-DATA(insert (   4062    18    18  11 1246 ));
-DATA(insert (   4062    18    18  12   72 ));
-DATA(insert (   4062    18    18  13   74 ));
-DATA(insert (   4062    18    18  14   73 ));
 /* minmax name */
 DATA(insert (   4065    19    19  1  3383 ));
 DATA(insert (   4065    19    19  2  3384 ));
 DATA(insert (   4065    19    19  3  3385 ));
 DATA(insert (   4065    19    19  4  3386 ));
-DATA(insert (   4065    19    19  11  655 ));
-DATA(insert (   4065    19    19  12  656 ));
-DATA(insert (   4065    19    19  13  658 ));
-DATA(insert (   4065    19    19  14  657 ));
 /* minmax integer: int2, int4, int8 */
 DATA(insert (   4054    20    20  1  3383 ));
 DATA(insert (   4054    20    20  2  3384 ));
 DATA(insert (   4054    20    20  3  3385 ));
 DATA(insert (   4054    20    20  4  3386 ));
-DATA(insert (   4054    20    20  11  469 ));
-DATA(insert (   4054    20    20  12  471 ));
-DATA(insert (   4054    20    20  13  472 ));
-DATA(insert (   4054    20    20  14  470 ));
 DATA(insert (   4054    20    21  1  3383 ));
 DATA(insert (   4054    20    21  2  3384 ));
 DATA(insert (   4054    20    21  3  3385 ));
 DATA(insert (   4054    20    21  4  3386 ));
-DATA(insert (   4054    20    21  11 1858 ));
-DATA(insert (   4054    20    21  12 1860 ));
-DATA(insert (   4054    20    21  13 1861 ));
-DATA(insert (   4054    20    21  14 1859 ));
 DATA(insert (   4054    20    23  1  3383 ));
 DATA(insert (   4054    20    23  2  3384 ));
 DATA(insert (   4054    20    23  3  3385 ));
 DATA(insert (   4054    20    23  4  3386 ));
-DATA(insert (   4054    20    23  11  476 ));
-DATA(insert (   4054    20    23  12  478 ));
-DATA(insert (   4054    20    23  13  479 ));
-DATA(insert (   4054    20    23  14  477 ));
 
 DATA(insert (   4054    21    21  1  3383 ));
 DATA(insert (   4054    21    21  2  3384 ));
 DATA(insert (   4054    21    21  3  3385 ));
 DATA(insert (   4054    21    21  4  3386 ));
-DATA(insert (   4054    21    21  11   64 ));
-DATA(insert (   4054    21    21  12  148 ));
-DATA(insert (   4054    21    21  13  151 ));
-DATA(insert (   4054    21    21  14  146 ));
 DATA(insert (   4054    21    20  1  3383 ));
 DATA(insert (   4054    21    20  2  3384 ));
 DATA(insert (   4054    21    20  3  3385 ));
 DATA(insert (   4054    21    20  4  3386 ));
-DATA(insert (   4054    21    20  11 1852 ));
-DATA(insert (   4054    21    20  12 1854 ));
-DATA(insert (   4054    21    20  13 1855 ));
-DATA(insert (   4054    21    20  14 1853 ));
 DATA(insert (   4054    21    23  1  3383 ));
 DATA(insert (   4054    21    23  2  3384 ));
 DATA(insert (   4054    21    23  3  3385 ));
 DATA(insert (   4054    21    23  4  3386 ));
-DATA(insert (   4054    21    23  11  160 ));
-DATA(insert (   4054    21    23  12  166 ));
-DATA(insert (   4054    21    23  13  168 ));
-DATA(insert (   4054    21    23  14  162 ));
 
 DATA(insert (   4054    23    23  1  3383 ));
 DATA(insert (   4054    23    23  2  3384 ));
 DATA(insert (   4054    23    23  3  3385 ));
 DATA(insert (   4054    23    23  4  3386 ));
-DATA(insert (   4054    23    23  11   66 ));
-DATA(insert (   4054    23    23  12  149 ));
-DATA(insert (   4054    23    23  13  150 ));
-DATA(insert (   4054    23    23  14  147 ));
 DATA(insert (   4054    23    20  1  3383 ));
 DATA(insert (   4054    23    20  2  3384 ));
 DATA(insert (   4054    23    20  3  3385 ));
 DATA(insert (   4054    23    20  4  3386 ));
-DATA(insert (   4054    23    20  11  854 ));
-DATA(insert (   4054    23    20  12  856 ));
-DATA(insert (   4054    23    20  13  857 ));
-DATA(insert (   4054    23    20  14  855 ));
 DATA(insert (   4054    23    21  1  3383 ));
 DATA(insert (   4054    23    21  2  3384 ));
 DATA(insert (   4054    23    21  3  3385 ));
 DATA(insert (   4054    23    21  4  3386 ));
-DATA(insert (   4054    23    21  11  161 ));
-DATA(insert (   4054    23    21  12  167 ));
-DATA(insert (   4054    23    21  13  169 ));
-DATA(insert (   4054    23    21  14  163 ));
 
 /* minmax text */
 DATA(insert (   4056    25    25  1  3383 ));
 DATA(insert (   4056    25    25  2  3384 ));
 DATA(insert (   4056    25    25  3  3385 ));
 DATA(insert (   4056    25    25  4  3386 ));
-DATA(insert (   4056    25    25  11  740 ));
-DATA(insert (   4056    25    25  12  741 ));
-DATA(insert (   4056    25    25  13  743 ));
-DATA(insert (   4056    25    25  14  742 ));
 /* minmax oid */
 DATA(insert (   4068    26    26  1  3383 ));
 DATA(insert (   4068    26    26  2  3384 ));
 DATA(insert (   4068    26    26  3  3385 ));
 DATA(insert (   4068    26    26  4  3386 ));
-DATA(insert (   4068    26    26  11  716 ));
-DATA(insert (   4068    26    26  12  717 ));
-DATA(insert (   4068    26    26  13 1639 ));
-DATA(insert (   4068    26    26  14 1638 ));
 /* minmax tid */
 DATA(insert (   4069    27    27  1  3383 ));
 DATA(insert (   4069    27    27  2  3384 ));
 DATA(insert (   4069    27    27  3  3385 ));
 DATA(insert (   4069    27    27  4  3386 ));
-DATA(insert (   4069    27    27  11 2791 ));
-DATA(insert (   4069    27    27  12 2793 ));
-DATA(insert (   4069    27    27  13 2792 ));
-DATA(insert (   4069    27    27  14 2790 ));
 /* minmax float */
 DATA(insert (   4070   700   700  1  3383 ));
 DATA(insert (   4070   700   700  2  3384 ));
 DATA(insert (   4070   700   700  3  3385 ));
 DATA(insert (   4070   700   700  4  3386 ));
-DATA(insert (   4070   700   700  11  289 ));
-DATA(insert (   4070   700   700  12  290 ));
-DATA(insert (   4070   700   700  13  292 ));
-DATA(insert (   4070   700   700  14  291 ));
 
 DATA(insert (   4070   700   701  1  3383 ));
 DATA(insert (   4070   700   701  2  3384 ));
 DATA(insert (   4070   700   701  3  3385 ));
 DATA(insert (   4070   700   701  4  3386 ));
-DATA(insert (   4070   700   701  11  301 ));
-DATA(insert (   4070   700   701  12  303 ));
-DATA(insert (   4070   700   701  13  304 ));
-DATA(insert (   4070   700   701  14  303 ));
 
 DATA(insert (   4070   701   701  1  3383 ));
 DATA(insert (   4070   701   701  2  3384 ));
 DATA(insert (   4070   701   701  3  3385 ));
 DATA(insert (   4070   701   701  4  3386 ));
-DATA(insert (   4070   701   701  11  295 ));
-DATA(insert (   4070   701   701  12  296 ));
-DATA(insert (   4070   701   701  13  298 ));
-DATA(insert (   4070   701   701  14  297 ));
 
 DATA(insert (   4070   701   700  1  3383 ));
 DATA(insert (   4070   701   700  2  3384 ));
 DATA(insert (   4070   701   700  3  3385 ));
 DATA(insert (   4070   701   700  4  3386 ));
-DATA(insert (   4070   701   700  11  307 ));
-DATA(insert (   4070   701   700  12  308 ));
-DATA(insert (   4070   701   700  13  310 ));
-DATA(insert (   4070   701   700  14  309 ));
 
 /* minmax abstime */
 DATA(insert (   4072   702   702  1  3383 ));
 DATA(insert (   4072   702   702  2  3384 ));
 DATA(insert (   4072   702   702  3  3385 ));
 DATA(insert (   4072   702   702  4  3386 ));
-DATA(insert (   4072   702   702  11  253 ));
-DATA(insert (   4072   702   702  12  255 ));
-DATA(insert (   4072   702   702  13  256 ));
-DATA(insert (   4072   702   702  14  254 ));
 /* minmax reltime */
 DATA(insert (   4073   703   703  1  3383 ));
 DATA(insert (   4073   703   703  2  3384 ));
 DATA(insert (   4073   703   703  3  3385 ));
 DATA(insert (   4073   703   703  4  3386 ));
-DATA(insert (   4073   703   703  11  259 ));
-DATA(insert (   4073   703   703  12  261 ));
-DATA(insert (   4073   703   703  13  262 ));
-DATA(insert (   4073   703   703  14  260 ));
 /* minmax macaddr */
 DATA(insert (   4074   829   829  1  3383 ));
 DATA(insert (   4074   829   829  2  3384 ));
 DATA(insert (   4074   829   829  3  3385 ));
 DATA(insert (   4074   829   829  4  3386 ));
-DATA(insert (   4074   829   829  11  831 ));
-DATA(insert (   4074   829   829  12  832 ));
-DATA(insert (   4074   829   829  13  834 ));
-DATA(insert (   4074   829   829  14  833 ));
 /* minmax inet */
 DATA(insert (   4075   869   869  1  3383 ));
 DATA(insert (   4075   869   869  2  3384 ));
 DATA(insert (   4075   869   869  3  3385 ));
 DATA(insert (   4075   869   869  4  3386 ));
-DATA(insert (   4075   869   869  11  921 ));
-DATA(insert (   4075   869   869  12  922 ));
-DATA(insert (   4075   869   869  13  924 ));
-DATA(insert (   4075   869   869  14  923 ));
 /* minmax character */
 DATA(insert (   4076  1042  1042  1  3383 ));
 DATA(insert (   4076  1042  1042  2  3384 ));
 DATA(insert (   4076  1042  1042  3  3385 ));
 DATA(insert (   4076  1042  1042  4  3386 ));
-DATA(insert (   4076  1042  1042  11 1049 ));
-DATA(insert (   4076  1042  1042  12 1050 ));
-DATA(insert (   4076  1042  1042  13 1052 ));
-DATA(insert (   4076  1042  1042  14 1051 ));
 /* minmax time without time zone */
 DATA(insert (   4077  1083  1083  1  3383 ));
 DATA(insert (   4077  1083  1083  2  3384 ));
 DATA(insert (   4077  1083  1083  3  3385 ));
 DATA(insert (   4077  1083  1083  4  3386 ));
-DATA(insert (   4077  1083  1083  11 1102 ));
-DATA(insert (   4077  1083  1083  12 1103 ));
-DATA(insert (   4077  1083  1083  13 1105 ));
-DATA(insert (   4077  1083  1083  14 1104 ));
 /* minmax datetime (date, timestamp, timestamptz) */
 DATA(insert (   4059  1114  1114  1  3383 ));
 DATA(insert (   4059  1114  1114  2  3384 ));
 DATA(insert (   4059  1114  1114  3  3385 ));
 DATA(insert (   4059  1114  1114  4  3386 ));
-DATA(insert (   4059  1114  1114  11 2054 ));
-DATA(insert (   4059  1114  1114  12 2055 ));
-DATA(insert (   4059  1114  1114  13 2056 ));
-DATA(insert (   4059  1114  1114  14 2057 ));
 DATA(insert (   4059  1114  1184  1  3383 ));
 DATA(insert (   4059  1114  1184  2  3384 ));
 DATA(insert (   4059  1114  1184  3  3385 ));
 DATA(insert (   4059  1114  1184  4  3386 ));
-DATA(insert (   4059  1114  1184  11 2520 ));
-DATA(insert (   4059  1114  1184  12 2521 ));
-DATA(insert (   4059  1114  1184  13 2524 ));
-DATA(insert (   4059  1114  1184  14 2523 ));
 DATA(insert (   4059  1114  1082  1  3383 ));
 DATA(insert (   4059  1114  1082  2  3384 ));
 DATA(insert (   4059  1114  1082  3  3385 ));
 DATA(insert (   4059  1114  1082  4  3386 ));
-DATA(insert (   4059  1114  1082  11 2364 ));
-DATA(insert (   4059  1114  1082  12 2365 ));
-DATA(insert (   4059  1114  1082  13 2368 ));
-DATA(insert (   4059  1114  1082  14 2367 ));
 
 DATA(insert (   4059  1184  1184  1  3383 ));
 DATA(insert (   4059  1184  1184  2  3384 ));
 DATA(insert (   4059  1184  1184  3  3385 ));
 DATA(insert (   4059  1184  1184  4  3386 ));
-DATA(insert (   4059  1184  1184  11 1154 ));
-DATA(insert (   4059  1184  1184  12 1155 ));
-DATA(insert (   4059  1184  1184  13 1156 ));
-DATA(insert (   4059  1184  1184  14 1157 ));
 DATA(insert (   4059  1184  1114  1  3383 ));
 DATA(insert (   4059  1184  1114  2  3384 ));
 DATA(insert (   4059  1184  1114  3  3385 ));
 DATA(insert (   4059  1184  1114  4  3386 ));
-DATA(insert (   4059  1184  1114  11 2527 ));
-DATA(insert (   4059  1184  1114  12 2528 ));
-DATA(insert (   4059  1184  1114  13 2531 ));
-DATA(insert (   4059  1184  1114  14 2530 ));
 DATA(insert (   4059  1184  1082  1  3383 ));
 DATA(insert (   4059  1184  1082  2  3384 ));
 DATA(insert (   4059  1184  1082  3  3385 ));
 DATA(insert (   4059  1184  1082  4  3386 ));
-DATA(insert (   4059  1184  1082  11 2377 ));
-DATA(insert (   4059  1184  1082  12 2378 ));
-DATA(insert (   4059  1184  1082  13 2381 ));
-DATA(insert (   4059  1184  1082  14 2379 ));
 
 DATA(insert (   4059  1082  1082  1  3383 ));
 DATA(insert (   4059  1082  1082  2  3384 ));
 DATA(insert (   4059  1082  1082  3  3385 ));
 DATA(insert (   4059  1082  1082  4  3386 ));
-DATA(insert (   4059  1082  1082  11 1087 ));
-DATA(insert (   4059  1082  1082  12 1088 ));
-DATA(insert (   4059  1082  1082  13 1090 ));
-DATA(insert (   4059  1082  1082  14 1089 ));
 DATA(insert (   4059  1082  1114  1  3383 ));
 DATA(insert (   4059  1082  1114  2  3384 ));
 DATA(insert (   4059  1082  1114  3  3385 ));
 DATA(insert (   4059  1082  1114  4  3386 ));
-DATA(insert (   4059  1082  1114  11 2338 ));
-DATA(insert (   4059  1082  1114  12 2339 ));
-DATA(insert (   4059  1082  1114  13 2342 ));
-DATA(insert (   4059  1082  1114  14 2341 ));
 DATA(insert (   4059  1082  1184  1  3383 ));
 DATA(insert (   4059  1082  1184  2  3384 ));
 DATA(insert (   4059  1082  1184  3  3385 ));
 DATA(insert (   4059  1082  1184  4  3386 ));
-DATA(insert (   4059  1082  1184  11 2351 ));
-DATA(insert (   4059  1082  1184  12 2352 ));
-DATA(insert (   4059  1082  1184  13 2354 ));
-DATA(insert (   4059  1082  1184  14 2353 ));
 
 /* minmax interval */
 DATA(insert (   4078  1186  1186  1  3383 ));
 DATA(insert (   4078  1186  1186  2  3384 ));
 DATA(insert (   4078  1186  1186  3  3385 ));
 DATA(insert (   4078  1186  1186  4  3386 ));
-DATA(insert (   4078  1186  1186  11 1164 ));
-DATA(insert (   4078  1186  1186  12 1165 ));
-DATA(insert (   4078  1186  1186  13 1166 ));
-DATA(insert (   4078  1186  1186  14 1167 ));
 /* minmax time with time zone */
 DATA(insert (   4058  1266  1266  1  3383 ));
 DATA(insert (   4058  1266  1266  2  3384 ));
 DATA(insert (   4058  1266  1266  3  3385 ));
 DATA(insert (   4058  1266  1266  4  3386 ));
-DATA(insert (   4058  1266  1266  11 1354 ));
-DATA(insert (   4058  1266  1266  12 1355 ));
-DATA(insert (   4058  1266  1266  13 1356 ));
-DATA(insert (   4058  1266  1266  14 1357 ));
 /* minmax bit */
 DATA(insert (   4079  1560  1560  1  3383 ));
 DATA(insert (   4079  1560  1560  2  3384 ));
 DATA(insert (   4079  1560  1560  3  3385 ));
 DATA(insert (   4079  1560  1560  4  3386 ));
-DATA(insert (   4079  1560  1560  11 1595 ));
-DATA(insert (   4079  1560  1560  12 1594 ));
-DATA(insert (   4079  1560  1560  13 1592 ));
-DATA(insert (   4079  1560  1560  14 1593 ));
 /* minmax bit varying */
 DATA(insert (   4080  1562  1562  1  3383 ));
 DATA(insert (   4080  1562  1562  2  3384 ));
 DATA(insert (   4080  1562  1562  3  3385 ));
 DATA(insert (   4080  1562  1562  4  3386 ));
-DATA(insert (   4080  1562  1562  11 1671 ));
-DATA(insert (   4080  1562  1562  12 1670 ));
-DATA(insert (   4080  1562  1562  13 1668 ));
-DATA(insert (   4080  1562  1562  14 1669 ));
 /* minmax numeric */
 DATA(insert (   4055  1700  1700  1  3383 ));
 DATA(insert (   4055  1700  1700  2  3384 ));
 DATA(insert (   4055  1700  1700  3  3385 ));
 DATA(insert (   4055  1700  1700  4  3386 ));
-DATA(insert (   4055  1700  1700  11 1722 ));
-DATA(insert (   4055  1700  1700  12 1723 ));
-DATA(insert (   4055  1700  1700  13 1721 ));
-DATA(insert (   4055  1700  1700  14 1720 ));
 /* minmax uuid */
 DATA(insert (   4081  2950  2950  1  3383 ));
 DATA(insert (   4081  2950  2950  2  3384 ));
 DATA(insert (   4081  2950  2950  3  3385 ));
 DATA(insert (   4081  2950  2950  4  3386 ));
-DATA(insert (   4081  2950  2950  11 2954 ));
-DATA(insert (   4081  2950  2950  12 2955 ));
-DATA(insert (   4081  2950  2950  13 2957 ));
-DATA(insert (   4081  2950  2950  14 2958 ));
 /* minmax pg_lsn */
 DATA(insert (   4082  3220  3220  1  3383 ));
 DATA(insert (   4082  3220  3220  2  3384 ));
 DATA(insert (   4082  3220  3220  3  3385 ));
 DATA(insert (   4082  3220  3220  4  3386 ));
-DATA(insert (   4082  3220  3220  11 3231 ));
-DATA(insert (   4082  3220  3220  12 3232 ));
-DATA(insert (   4082  3220  3220  13 3234 ));
-DATA(insert (   4082  3220  3220  14 3235 ));
 
 #endif   /* PG_AMPROC_H */
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index b3acef66de2..f9469375bea 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -238,34 +238,34 @@ DATA(insert (	2742	jsonb_path_ops		PGNSP PGUID 4037  3802 f 23 ));
 
 /* BRIN operator classes */
 /* no brin opclass for bool */
-DATA(insert (	3580	bytea_minmax_ops		PGNSP PGUID 4064    17 t 0 ));
-DATA(insert (	3580	char_minmax_ops			PGNSP PGUID 4062    18 t 0 ));
-DATA(insert (	3580	name_minmax_ops			PGNSP PGUID 4065    19 t 0 ));
-DATA(insert (	3580	int8_minmax_ops			PGNSP PGUID 4054    20 t 0 ));
-DATA(insert (	3580	int2_minmax_ops			PGNSP PGUID 4054    21 t 0 ));
-DATA(insert (	3580	int4_minmax_ops			PGNSP PGUID 4054    23 t 0 ));
-DATA(insert (	3580	text_minmax_ops			PGNSP PGUID 4056    25 t 0 ));
-DATA(insert (	3580	oid_minmax_ops			PGNSP PGUID 4068    26 t 0 ));
-DATA(insert (	3580	tid_minmax_ops			PGNSP PGUID 4069    27 t 0 ));
-DATA(insert (	3580	float4_minmax_ops		PGNSP PGUID 4070   700 t 0 ));
-DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 0 ));
-DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 0 ));
-DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 0 ));
-DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 0 ));
-DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 0 ));
-DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 0 ));
-DATA(insert (	3580	time_minmax_ops			PGNSP PGUID 4077  1083 t 0 ));
-DATA(insert (	3580	date_minmax_ops			PGNSP PGUID 4059  1082 t 0 ));
-DATA(insert (	3580	timestamp_minmax_ops	PGNSP PGUID 4059  1114 t 0 ));
-DATA(insert (	3580	timestamptz_minmax_ops	PGNSP PGUID 4059  1184 t 0 ));
-DATA(insert (	3580	interval_minmax_ops		PGNSP PGUID 4078  1186 t 0 ));
-DATA(insert (	3580	timetz_minmax_ops		PGNSP PGUID 4058  1266 t 0 ));
-DATA(insert (	3580	bit_minmax_ops			PGNSP PGUID 4079  1560 t 0 ));
-DATA(insert (	3580	varbit_minmax_ops		PGNSP PGUID 4080  1562 t 0 ));
-DATA(insert (	3580	numeric_minmax_ops		PGNSP PGUID 4055  1700 t 0 ));
+DATA(insert (	3580	bytea_minmax_ops		PGNSP PGUID 4064    17 t 17 ));
+DATA(insert (	3580	char_minmax_ops			PGNSP PGUID 4062    18 t 18 ));
+DATA(insert (	3580	name_minmax_ops			PGNSP PGUID 4065    19 t 19 ));
+DATA(insert (	3580	int8_minmax_ops			PGNSP PGUID 4054    20 t 20 ));
+DATA(insert (	3580	int2_minmax_ops			PGNSP PGUID 4054    21 t 21 ));
+DATA(insert (	3580	int4_minmax_ops			PGNSP PGUID 4054    23 t 23 ));
+DATA(insert (	3580	text_minmax_ops			PGNSP PGUID 4056    25 t 25 ));
+DATA(insert (	3580	oid_minmax_ops			PGNSP PGUID 4068    26 t 26 ));
+DATA(insert (	3580	tid_minmax_ops			PGNSP PGUID 4069    27 t 27 ));
+DATA(insert (	3580	float4_minmax_ops		PGNSP PGUID 4070   700 t 700 ));
+DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
+DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
+DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
+DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
+DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
+DATA(insert (	3580	time_minmax_ops			PGNSP PGUID 4077  1083 t 1083 ));
+DATA(insert (	3580	date_minmax_ops			PGNSP PGUID 4059  1082 t 1082 ));
+DATA(insert (	3580	timestamp_minmax_ops	PGNSP PGUID 4059  1114 t 1114 ));
+DATA(insert (	3580	timestamptz_minmax_ops	PGNSP PGUID 4059  1184 t 1184 ));
+DATA(insert (	3580	interval_minmax_ops		PGNSP PGUID 4078  1186 t 1186 ));
+DATA(insert (	3580	timetz_minmax_ops		PGNSP PGUID 4058  1266 t 1266 ));
+DATA(insert (	3580	bit_minmax_ops			PGNSP PGUID 4079  1560 t 1560 ));
+DATA(insert (	3580	varbit_minmax_ops		PGNSP PGUID 4080  1562 t 1562 ));
+DATA(insert (	3580	numeric_minmax_ops		PGNSP PGUID 4055  1700 t 1700 ));
 /* no brin opclass for record, anyarray */
-DATA(insert (	3580	uuid_minmax_ops			PGNSP PGUID 4081  2950 t 0 ));
-DATA(insert (	3580	pg_lsn_minmax_ops		PGNSP PGUID 4082  3220 t 0 ));
+DATA(insert (	3580	uuid_minmax_ops			PGNSP PGUID 4081  2950 t 2950 ));
+DATA(insert (	3580	pg_lsn_minmax_ops		PGNSP PGUID 4082  3220 t 3220 ));
 /* no brin opclass for enum, tsvector, tsquery, jsonb, range */
 
 #endif   /* PG_OPCLASS_H */
diff --git a/src/test/regress/expected/brin.out b/src/test/regress/expected/brin.out
index f47f3663759..4fe6f071942 100644
--- a/src/test/regress/expected/brin.out
+++ b/src/test/regress/expected/brin.out
@@ -11,6 +11,7 @@ CREATE TABLE brintest (byteacol bytea,
 	float8col double precision,
 	macaddrcol macaddr,
 	inetcol inet,
+	cidrcol cidr,
 	bpcharcol character,
 	datecol date,
 	timecol time without time zone,
@@ -23,35 +24,39 @@ CREATE TABLE brintest (byteacol bytea,
 	numericcol numeric,
 	uuidcol uuid,
 	lsncol pg_lsn
-) WITH (fillfactor=10);
+) WITH (fillfactor=10, autovacuum_enabled=off);
 INSERT INTO brintest SELECT
-	repeat(stringu1, 42)::bytea,
+	repeat(stringu1, 8)::bytea,
 	substr(stringu1, 1, 1)::"char",
 	stringu1::name, 142857 * tenthous,
 	thousand,
 	twothousand,
-	repeat(stringu1, 42),
+	repeat(stringu1, 8),
 	unique1::oid,
 	format('(%s,%s)', tenthous, twenty)::tid,
 	(four + 1.0)/(hundred+1),
 	odd::float8 / (tenthous + 1),
 	format('%s:00:%s:00:%s:00', to_hex(odd), to_hex(even), to_hex(hundred))::macaddr,
-	inet '10.2.3.4' + tenthous,
+	inet '10.2.3.4/24' + tenthous,
+	cidr '10.2.3/24' + tenthous,
 	substr(stringu1, 1, 1)::bpchar,
 	date '1995-08-15' + tenthous,
 	time '01:20:30' + thousand * interval '18.5 second',
 	timestamp '1942-07-23 03:05:09' + tenthous * interval '36.38 hours',
 	timestamptz '1972-10-10 03:00' + thousand * interval '1 hour',
 	justify_days(justify_hours(tenthous * interval '12 minutes')),
-	timetz '01:30:20' + hundred * interval '15 seconds',
+	timetz '01:30:20+02' + hundred * interval '15 seconds',
 	thousand::bit(10),
 	tenthous::bit(16)::varbit,
 	tenthous::numeric(36,30) * fivethous * even / (hundred + 1),
 	format('%s%s-%s-%s-%s-%s%s%s', to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'))::uuid,
 	format('%s/%s%s', odd, even, tenthous)::pg_lsn
-FROM tenk1 LIMIT 5;
--- throw in some NULL-only tuples too
-INSERT INTO brintest SELECT NULL FROM tenk1 LIMIT 25;
+FROM tenk1 LIMIT 25;
+-- throw in some NULL's and different values
+INSERT INTO brintest (inetcol, cidrcol) SELECT
+	inet 'fe80::6e40:8ff:fea9:8c46' + tenthous,
+	cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous
+FROM tenk1 LIMIT 25;
 CREATE INDEX brinidx ON brintest USING brin (
 	byteacol,
 	charcol,
@@ -79,72 +84,118 @@ CREATE INDEX brinidx ON brintest USING brin (
 	uuidcol,
 	lsncol
 ) with (pages_per_range = 1);
-BEGIN;
-CREATE TABLE brinopers (colname name, op text[], value text[],
+CREATE TABLE brinopers (colname name, typ text, op text[], value text[],
 	check (cardinality(op) = cardinality(value)));
-INSERT INTO brinopers VALUES ('byteacol', '{>, >=, =, <=, <}', '{ZZAAAA, ZZAAAA, AAAAAA, AAAAAA, AAAAAA}');
-INSERT INTO brinopers VALUES ('charcol', '{>, >=, =, <=, <}', '{Z, Z, A, A, A}');
-INSERT INTO brinopers VALUES ('namecol', '{>, >=, =, <=, <}', '{ZZAAAA, ZZAAAA, AAAAAA, AAAAAA, AAAAAA}');
-INSERT INTO brinopers VALUES ('int8col', '{>, >=, =, <=, <}', '{1428427143, 1428427143, 0, 0, 0}');
-INSERT INTO brinopers VALUES ('int2col', '{>, >=, =, <=, <}', '{999, 999, 0, 0, 0}');
-INSERT INTO brinopers VALUES ('int4col', '{>, >=, =, <=, <}', '{1999, 1999, 0, 0, 0}');
-INSERT INTO brinopers VALUES ('textcol', '{>, >=, =, <=, <}', '{ZZAAAA, ZZAAAA, AAAAA, AAAAA, AAAAA}');
-INSERT INTO brinopers VALUES ('oidcol', '{>, >=, =, <=, <}', '{9999, 9999, 0, 0, 0}');
-INSERT INTO brinopers VALUES ('tidcol', '{>, >=, =, <=, <}', '{"(9999,19)", "(9999,19)", "(0,0)", "(0,0)", "(0,0)"}');
-INSERT INTO brinopers VALUES ('float4col', '{>, >=, =, <=, <}', '{1, 1, 0.0103093, 0.0103093, 0.0103093}');
-INSERT INTO brinopers VALUES ('float8col', '{>, >=, =, <=, <}', '{1.98, 1.98, 0, 0, 0}');
-INSERT INTO brinopers VALUES ('inetcol', '{>, >=, =, <=, <}', '{10.2.42.19, 10.2.42.19, 10.2.3.4, 10.2.3.4, 10.2.3.4}');
-INSERT INTO brinopers VALUES ('bpcharcol', '{>, >=, =, <=, <}', '{Z, Z, A, A, A}');
-INSERT INTO brinopers VALUES ('datecol', '{>, >=, =, <=, <}', '{2022-12-30, 2022-12-30, 1995-08-15, 1995-08-15, 1995-08-15}');
-INSERT INTO brinopers VALUES ('timecol', '{>, >=, =, <=, <}', '{06:28:31.5, 06:28:31.5, 01:20:30, 01:20:30, 01:20:30}');
-INSERT INTO brinopers VALUES ('timestampcol', '{>, >=, =, <=, <}', '{1984-01-20 22:42:21, 1984-01-20 22:42:21, 1942-07-23 03:05:09, 1942-07-23 03:05:09, 1942-07-23 03:05:09}');
-INSERT INTO brinopers VALUES ('timestamptzcol', '{>, >=, =, <=, <}', '{1972-11-20 19:00:00-03, 1972-11-20 19:00:00-03, 1972-10-10 03:00:00-04, 1972-10-10 03:00:00-04, 1972-10-10 03:00:00-04}');
-INSERT INTO brinopers VALUES ('intervalcol', '{>, >=, =, <=, <}', '{2 mons 23 days 07:48:00, 2 mons 23 days 07:48:00, 00:00:00, 00:00:00, 00:00:00}');
-INSERT INTO brinopers VALUES ('timetzcol', '{>, >=, =, <=, <}', '{01:55:05-03, 01:55:05-03, 01:30:20-03, 01:30:20-03, 01:30:20-03}');
-INSERT INTO brinopers VALUES ('numericcol', '{>, >=, =, <=, <}', '{99470151.9, 99470151.9, 0.00, 0.01, 0.01}');
-INSERT INTO brinopers VALUES ('macaddrcol', '{>, >=, =, <=, <}', '{ff:fe:00:00:00:00, ff:fe:00:00:00:00, 00:00:01:00:00:00, 00:00:01:00:00:00, 00:00:01:00:00:00}');
-INSERT INTO brinopers VALUES ('bitcol', '{>, >=, =, <=, <}', '{1111111000, 1111111000, 0000000010, 0000000010, 0000000010}');
-INSERT INTO brinopers VALUES ('varbitcol', '{>, >=, =, <=, <}', '{1111111111111000, 1111111111111000, 0000000000000100, 0000000000000100, 0000000000000100}');
-INSERT INTO brinopers VALUES ('uuidcol', '{>, >=, =, <=, <}', '{99989998-9998-9998-9998-999899989998, 99989998-9998-9998-9998-999899989998, 00040004-0004-0004-0004-000400040004, 00040004-0004-0004-0004-000400040004, 00040004-0004-0004-0004-000400040005}');
-INSERT INTO brinopers VALUES ('lsncol', '{>, >=, =, <=, <, IS, IS NOT}', '{198/1999799, 198/1999799, 30/312815, 0/1200, 0/1200, NULL, NULL}');
-COMMIT;
+INSERT INTO brinopers VALUES
+	('byteacol', 'bytea', '{>, >=, =, <=, <}', '{AAAAAA, AAAAAA, BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA, ZZZZZZ, ZZZZZZ}'),
+	('charcol', 'char', '{>, >=, =, <=, <}', '{A, A, M, Z, Z}'),
+	('namecol', 'name', '{>, >=, =, <=, <}', '{AAAAAA, AAAAAA, MAAAAA, ZZAAAA, ZZAAAA}'),
+	('int2col', 'int2', '{>, >=, =, <=, <}', '{0, 0, 800, 999, 999}'),
+	('int2col', 'int4', '{>, >=, =, <=, <}', '{0, 0, 800, 999, 1999}'),
+	('int2col', 'int8', '{>, >=, =, <=, <}', '{0, 0, 800, 999, 1428427143}'),
+	('int4col', 'int2', '{>, >=, =, <=, <}', '{0, 0, 800, 1999, 1999}'),
+	('int4col', 'int4', '{>, >=, =, <=, <}', '{0, 0, 800, 1999, 1999}'),
+	('int4col', 'int8', '{>, >=, =, <=, <}', '{0, 0, 800, 1999, 1428427143}'),
+	('int8col', 'int2', '{>, >=}', '{0, 0}'),
+	('int8col', 'int4', '{>, >=}', '{0, 0}'),
+	('int8col', 'int8', '{>, >=, =, <=, <}', '{0, 0, 1257141600, 1428427143, 1428427143}'),
+	('textcol', 'text', '{>, >=, =, <=, <}', '{AAAAAA, AAAAAA, BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA, ZZAAAA, ZZAAAA}'),
+	('oidcol', 'oid', '{>, >=, =, <=, <}', '{0, 0, 8800, 9999, 9999}'),
+	('tidcol', 'tid', '{>, >=, =, <=, <}', '{"(0,0)", "(0,0)", "(8800,0)", "(9999,19)", "(9999,19)"}'),
+	('float4col', 'float4', '{>, >=, =, <=, <}', '{0.0103093, 0.0103093, 1, 1, 1}'),
+	('float4col', 'float8', '{>, >=, =, <=, <}', '{0.0103093, 0.0103093, 1, 1, 1}'),
+	('float8col', 'float4', '{>, >=, =, <=, <}', '{0, 0, 0, 1.98, 1.98}'),
+	('float8col', 'float8', '{>, >=, =, <=, <}', '{0, 0, 0, 1.98, 1.98}'),
+	('macaddrcol', 'macaddr', '{>, >=, =, <=, <}', '{00:00:01:00:00:00, 00:00:01:00:00:00, 2c:00:2d:00:16:00, ff:fe:00:00:00:00, ff:fe:00:00:00:00}'),
+	('inetcol', 'inet', '{&&, =, <, <=, >, >=, >>=, >>, <<=, <<}', '{10/8, 10.2.14.231/24, 255.255.255.255, 255.255.255.255, 0.0.0.0, 0.0.0.0, 10.2.14.231/24, 10.2.14.231/25, 10.2.14.231/8, 0/0}'),
+	('inetcol', 'inet', '{&&, >>=, <<=, =}', '{fe80::6e40:8ff:fea9:a673/32, fe80::6e40:8ff:fea9:8c46, fe80::6e40:8ff:fea9:a673/32, fe80::6e40:8ff:fea9:8c46}'),
+	('inetcol', 'cidr', '{&&, <, <=, >, >=, >>=, >>, <<=, <<}', '{10/8, 255.255.255.255, 255.255.255.255, 0.0.0.0, 0.0.0.0, 10.2.14/24, 10.2.14/25, 10/8, 0/0}'),
+	('inetcol', 'cidr', '{&&, >>=, <<=, =}', '{fe80::/32, fe80::6e40:8ff:fea9:8c46, fe80::/32, fe80::6e40:8ff:fea9:8c46}'),
+	('cidrcol', 'inet', '{&&, =, <, <=, >, >=, >>=, >>, <<=, <<}', '{10/8, 10.2.14/24, 255.255.255.255, 255.255.255.255, 0.0.0.0, 0.0.0.0, 10.2.14.231/24, 10.2.14.231/25, 10.2.14.231/8, 0/0}'),
+	('cidrcol', 'inet', '{&&, >>=, <<=, =}', '{fe80::6e40:8ff:fea9:a673/32, fe80::6e40:8ff:fea9:8c46, fe80::6e40:8ff:fea9:a673/32, fe80::6e40:8ff:fea9:8c46}'),
+	('cidrcol', 'cidr', '{&&, =, <, <=, >, >=, >>=, >>, <<=, <<}', '{10/8, 10.2.14/24, 255.255.255.255, 255.255.255.255, 0.0.0.0, 0.0.0.0, 10.2.14/24, 10.2.14/25, 10/8, 0/0}'),
+	('cidrcol', 'cidr', '{&&, >>=, <<=, =}', '{fe80::/32, fe80::6e40:8ff:fea9:8c46, fe80::/32, fe80::6e40:8ff:fea9:8c46}'),
+	('bpcharcol', 'bpchar', '{>, >=, =, <=, <}', '{A, A, W, Z, Z}'),
+	('datecol', 'date', '{>, >=, =, <=, <}', '{1995-08-15, 1995-08-15, 2009-12-01, 2022-12-30, 2022-12-30}'),
+	('timecol', 'time', '{>, >=, =, <=, <}', '{01:20:30, 01:20:30, 02:28:57, 06:28:31.5, 06:28:31.5}'),
+	('timestampcol', 'timestamp', '{>, >=, =, <=, <}', '{1942-07-23 03:05:09, 1942-07-23 03:05:09, 1964-03-24 19:26:45, 1984-01-20 22:42:21, 1984-01-20 22:42:21}'),
+	('timestampcol', 'timestamptz', '{>, >=, =, <=, <}', '{1942-07-23 03:05:09, 1942-07-23 03:05:09, 1964-03-24 19:26:45, 1984-01-20 22:42:21, 1984-01-20 22:42:21}'),
+	('timestampcol', 'timestamptz', '{>, >=, =, <=, <}', '{1942-07-23 03:05:09, 1942-07-23 03:05:09, 1964-03-24 19:26:45, 1984-01-20 22:42:21, 1984-01-20 22:42:21}'),
+	('timestamptzcol', 'timestamptz', '{>, >=, =, <=, <}', '{1972-10-10 03:00:00-04, 1972-10-10 03:00:00-04, 1972-10-19 09:00:00-07, 1972-11-20 19:00:00-03, 1972-11-20 19:00:00-03}'),
+	('intervalcol', 'interval', '{>, >=, =, <=, <}', '{00:00:00, 00:00:00, 1 mons 13 days 12:24, 2 mons 23 days 07:48:00, 1 year}'),
+	('timetzcol', 'timetz', '{>, >=, =, <=, <}', '{01:30:20+02, 01:30:20+02, 01:35:50+02, 23:55:05+02, 23:55:05+02}'),
+	('bitcol', 'bit(10)', '{>, >=, =, <=, <}', '{0000000010, 0000000010, 0011011110, 1111111000, 1111111000}'),
+	('varbitcol', 'varbit(16)', '{>, >=, =, <=, <}', '{0000000000000100, 0000000000000100, 0001010001100110, 1111111111111000, 1111111111111000}'),
+	('numericcol', 'numeric', '{>, >=, =, <=, <}', '{0.00, 0.01, 2268164.347826086956521739130434782609, 99470151.9, 99470151.9}'),
+	('uuidcol', 'uuid', '{>, >=, =, <=, <}', '{00040004-0004-0004-0004-000400040004, 00040004-0004-0004-0004-000400040004, 52225222-5222-5222-5222-522252225222, 99989998-9998-9998-9998-999899989998, 99989998-9998-9998-9998-999899989998}'),
+	('lsncol', 'pg_lsn', '{>, >=, =, <=, <, IS, IS NOT}', '{0/1200, 0/1200, 44/455222, 198/1999799, 198/1999799, NULL, NULL}');
 DO $x$
 DECLARE
-        r record;
-        tabname text;
-        tabname_ss text;
-		count int;
-		query text;
-		plan text;
+	r record;
+	r2 record;
+	cond text;
+	count int;
+	mismatch bool;
 BEGIN
-        FOR r IN SELECT row_number() OVER (), colname, oper, value[ordinality] FROM brinopers, unnest(op) WITH ORDINALITY AS oper LOOP
-                tabname := format('qry_%s', r.row_number);
-                tabname_ss := tabname || '_ss';
-				query = format($y$INSERT INTO %s SELECT ctid FROM brintest WHERE %s %s %L $y$,
-                        tabname, r.colname, r.oper, r.value);
-				-- run the query using the brin index
-                SET enable_seqscan = 0;
-                SET enable_bitmapscan = 1;
-                EXECUTE format('create temp table %s (tid tid) ON COMMIT DROP', tabname);
-                EXECUTE query;
+	FOR r IN SELECT colname, oper, typ, value[ordinality] FROM brinopers, unnest(op) WITH ORDINALITY AS oper LOOP
+		mismatch := false;
+
+		-- prepare the condition
+		IF r.value IS NULL THEN
+			cond := format('%I %s %L', r.colname, r.oper, r.value);
+		ELSE
+			cond := format('%I %s %L::%s', r.colname, r.oper, r.value, r.typ);
+		END IF;
+
+		-- run the query using the brin index
+		CREATE TEMP TABLE brin_result (cid tid);
+		SET enable_seqscan = 0;
+		SET enable_bitmapscan = 1;
+		EXECUTE format($y$INSERT INTO brin_result SELECT ctid FROM brintest WHERE %s $y$, cond);
+
+		-- run the query using a seqscan
+		CREATE TEMP TABLE brin_result_ss (cid tid);
+		SET enable_seqscan = 1;
+		SET enable_bitmapscan = 0;
+		EXECUTE format($y$INSERT INTO brin_result_ss SELECT ctid FROM brintest WHERE %s $y$, cond);
+
+		-- make sure both return the same results
+		PERFORM * FROM brin_result EXCEPT ALL SELECT * FROM brin_result_ss;
+		GET DIAGNOSTICS count = ROW_COUNT;
+		IF count <> 0 THEN
+			mismatch = true;
+		END IF;
+		PERFORM * FROM brin_result_ss EXCEPT ALL SELECT * FROM brin_result;
+		GET DIAGNOSTICS count = ROW_COUNT;
+		IF count <> 0 THEN
+			mismatch = true;
+		END IF;
+
+		-- report the results of each scan to make the differences obvious
+		IF mismatch THEN
+			RAISE WARNING 'something not right in %: count %', r, count;
+			SET enable_seqscan = 1;
+			SET enable_bitmapscan = 0;
+			FOR r2 IN EXECUTE 'SELECT ' || r.colname || ' FROM brintest WHERE ' || cond LOOP
+				RAISE NOTICE 'seqscan: %', r2;
+			END LOOP;
+
+			SET enable_seqscan = 0;
+			SET enable_bitmapscan = 1;
+			FOR r2 IN EXECUTE 'SELECT ' || r.colname || ' FROM brintest WHERE ' || cond LOOP
+				RAISE NOTICE 'bitmapscan: %', r2;
+			END LOOP;
+		END IF;
 
-				-- run the query using a seqscan
-                SET enable_seqscan = 1;
-                SET enable_bitmapscan = 0;
-				query = format($y$INSERT INTO %s SELECT ctid FROM brintest WHERE %s %s %L $y$,
-                        tabname_ss, r.colname, r.oper, r.value);
-                EXECUTE format('create temp table %s (tid tid) ON COMMIT DROP', tabname_ss);
-                EXECUTE query;
+		-- make sure it was a sensible test case
+		SELECT count(*) INTO count FROM brin_result;
+		IF count = 0 THEN RAISE WARNING 'no results for %', r; END IF;
 
-				-- make sure both return the same results
-                EXECUTE format('SELECT * from %s EXCEPT ALL SELECT * FROM %s', tabname, tabname_ss);
-				GET DIAGNOSTICS count = ROW_COUNT;
-                IF count <> 0 THEN RAISE EXCEPTION 'something not right in %: count %', r, count; END IF;
-                EXECUTE format('SELECT * from %s EXCEPT ALL SELECT * FROM %s', tabname_ss, tabname);
-				GET DIAGNOSTICS count = ROW_COUNT;
-                IF count <> 0 THEN RAISE EXCEPTION 'something not right in %: count %', r, count; END IF;
-        end loop;
-end;
+		-- drop the temporary tables
+		DROP TABLE brin_result;
+		DROP TABLE brin_result_ss;
+	END LOOP;
+END;
 $x$;
 INSERT INTO brintest SELECT
 	repeat(stringu1, 42)::bytea,
@@ -159,6 +210,7 @@ INSERT INTO brintest SELECT
 	odd::float8 / (tenthous + 1),
 	format('%s:00:%s:00:%s:00', to_hex(odd), to_hex(even), to_hex(hundred))::macaddr,
 	inet '10.2.3.4' + tenthous,
+	cidr '10.2.3/24' + tenthous,
 	substr(stringu1, 1, 1)::bpchar,
 	date '1995-08-15' + tenthous,
 	time '01:20:30' + thousand * interval '18.5 second',
diff --git a/src/test/regress/sql/brin.sql b/src/test/regress/sql/brin.sql
index 3aff92529a1..6a695bbd204 100644
--- a/src/test/regress/sql/brin.sql
+++ b/src/test/regress/sql/brin.sql
@@ -11,6 +11,7 @@ CREATE TABLE brintest (byteacol bytea,
 	float8col double precision,
 	macaddrcol macaddr,
 	inetcol inet,
+	cidrcol cidr,
 	bpcharcol character,
 	datecol date,
 	timecol time without time zone,
@@ -23,37 +24,41 @@ CREATE TABLE brintest (byteacol bytea,
 	numericcol numeric,
 	uuidcol uuid,
 	lsncol pg_lsn
-) WITH (fillfactor=10);
+) WITH (fillfactor=10, autovacuum_enabled=off);
 
 INSERT INTO brintest SELECT
-	repeat(stringu1, 42)::bytea,
+	repeat(stringu1, 8)::bytea,
 	substr(stringu1, 1, 1)::"char",
 	stringu1::name, 142857 * tenthous,
 	thousand,
 	twothousand,
-	repeat(stringu1, 42),
+	repeat(stringu1, 8),
 	unique1::oid,
 	format('(%s,%s)', tenthous, twenty)::tid,
 	(four + 1.0)/(hundred+1),
 	odd::float8 / (tenthous + 1),
 	format('%s:00:%s:00:%s:00', to_hex(odd), to_hex(even), to_hex(hundred))::macaddr,
-	inet '10.2.3.4' + tenthous,
+	inet '10.2.3.4/24' + tenthous,
+	cidr '10.2.3/24' + tenthous,
 	substr(stringu1, 1, 1)::bpchar,
 	date '1995-08-15' + tenthous,
 	time '01:20:30' + thousand * interval '18.5 second',
 	timestamp '1942-07-23 03:05:09' + tenthous * interval '36.38 hours',
 	timestamptz '1972-10-10 03:00' + thousand * interval '1 hour',
 	justify_days(justify_hours(tenthous * interval '12 minutes')),
-	timetz '01:30:20' + hundred * interval '15 seconds',
+	timetz '01:30:20+02' + hundred * interval '15 seconds',
 	thousand::bit(10),
 	tenthous::bit(16)::varbit,
 	tenthous::numeric(36,30) * fivethous * even / (hundred + 1),
 	format('%s%s-%s-%s-%s-%s%s%s', to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'))::uuid,
 	format('%s/%s%s', odd, even, tenthous)::pg_lsn
-FROM tenk1 LIMIT 5;
+FROM tenk1 LIMIT 25;
 
--- throw in some NULL-only tuples too
-INSERT INTO brintest SELECT NULL FROM tenk1 LIMIT 25;
+-- throw in some NULL's and different values
+INSERT INTO brintest (inetcol, cidrcol) SELECT
+	inet 'fe80::6e40:8ff:fea9:8c46' + tenthous,
+	cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous
+FROM tenk1 LIMIT 25;
 
 CREATE INDEX brinidx ON brintest USING brin (
 	byteacol,
@@ -83,74 +88,120 @@ CREATE INDEX brinidx ON brintest USING brin (
 	lsncol
 ) with (pages_per_range = 1);
 
-BEGIN;
-CREATE TABLE brinopers (colname name, op text[], value text[],
+CREATE TABLE brinopers (colname name, typ text, op text[], value text[],
 	check (cardinality(op) = cardinality(value)));
 
-INSERT INTO brinopers VALUES ('byteacol', '{>, >=, =, <=, <}', '{ZZAAAA, ZZAAAA, AAAAAA, AAAAAA, AAAAAA}');
-INSERT INTO brinopers VALUES ('charcol', '{>, >=, =, <=, <}', '{Z, Z, A, A, A}');
-INSERT INTO brinopers VALUES ('namecol', '{>, >=, =, <=, <}', '{ZZAAAA, ZZAAAA, AAAAAA, AAAAAA, AAAAAA}');
-INSERT INTO brinopers VALUES ('int8col', '{>, >=, =, <=, <}', '{1428427143, 1428427143, 0, 0, 0}');
-INSERT INTO brinopers VALUES ('int2col', '{>, >=, =, <=, <}', '{999, 999, 0, 0, 0}');
-INSERT INTO brinopers VALUES ('int4col', '{>, >=, =, <=, <}', '{1999, 1999, 0, 0, 0}');
-INSERT INTO brinopers VALUES ('textcol', '{>, >=, =, <=, <}', '{ZZAAAA, ZZAAAA, AAAAA, AAAAA, AAAAA}');
-INSERT INTO brinopers VALUES ('oidcol', '{>, >=, =, <=, <}', '{9999, 9999, 0, 0, 0}');
-INSERT INTO brinopers VALUES ('tidcol', '{>, >=, =, <=, <}', '{"(9999,19)", "(9999,19)", "(0,0)", "(0,0)", "(0,0)"}');
-INSERT INTO brinopers VALUES ('float4col', '{>, >=, =, <=, <}', '{1, 1, 0.0103093, 0.0103093, 0.0103093}');
-INSERT INTO brinopers VALUES ('float8col', '{>, >=, =, <=, <}', '{1.98, 1.98, 0, 0, 0}');
-INSERT INTO brinopers VALUES ('inetcol', '{>, >=, =, <=, <}', '{10.2.42.19, 10.2.42.19, 10.2.3.4, 10.2.3.4, 10.2.3.4}');
-INSERT INTO brinopers VALUES ('bpcharcol', '{>, >=, =, <=, <}', '{Z, Z, A, A, A}');
-INSERT INTO brinopers VALUES ('datecol', '{>, >=, =, <=, <}', '{2022-12-30, 2022-12-30, 1995-08-15, 1995-08-15, 1995-08-15}');
-INSERT INTO brinopers VALUES ('timecol', '{>, >=, =, <=, <}', '{06:28:31.5, 06:28:31.5, 01:20:30, 01:20:30, 01:20:30}');
-INSERT INTO brinopers VALUES ('timestampcol', '{>, >=, =, <=, <}', '{1984-01-20 22:42:21, 1984-01-20 22:42:21, 1942-07-23 03:05:09, 1942-07-23 03:05:09, 1942-07-23 03:05:09}');
-INSERT INTO brinopers VALUES ('timestamptzcol', '{>, >=, =, <=, <}', '{1972-11-20 19:00:00-03, 1972-11-20 19:00:00-03, 1972-10-10 03:00:00-04, 1972-10-10 03:00:00-04, 1972-10-10 03:00:00-04}');
-INSERT INTO brinopers VALUES ('intervalcol', '{>, >=, =, <=, <}', '{2 mons 23 days 07:48:00, 2 mons 23 days 07:48:00, 00:00:00, 00:00:00, 00:00:00}');
-INSERT INTO brinopers VALUES ('timetzcol', '{>, >=, =, <=, <}', '{01:55:05-03, 01:55:05-03, 01:30:20-03, 01:30:20-03, 01:30:20-03}');
-INSERT INTO brinopers VALUES ('numericcol', '{>, >=, =, <=, <}', '{99470151.9, 99470151.9, 0.00, 0.01, 0.01}');
-INSERT INTO brinopers VALUES ('macaddrcol', '{>, >=, =, <=, <}', '{ff:fe:00:00:00:00, ff:fe:00:00:00:00, 00:00:01:00:00:00, 00:00:01:00:00:00, 00:00:01:00:00:00}');
-INSERT INTO brinopers VALUES ('bitcol', '{>, >=, =, <=, <}', '{1111111000, 1111111000, 0000000010, 0000000010, 0000000010}');
-INSERT INTO brinopers VALUES ('varbitcol', '{>, >=, =, <=, <}', '{1111111111111000, 1111111111111000, 0000000000000100, 0000000000000100, 0000000000000100}');
-INSERT INTO brinopers VALUES ('uuidcol', '{>, >=, =, <=, <}', '{99989998-9998-9998-9998-999899989998, 99989998-9998-9998-9998-999899989998, 00040004-0004-0004-0004-000400040004, 00040004-0004-0004-0004-000400040004, 00040004-0004-0004-0004-000400040005}');
-INSERT INTO brinopers VALUES ('lsncol', '{>, >=, =, <=, <, IS, IS NOT}', '{198/1999799, 198/1999799, 30/312815, 0/1200, 0/1200, NULL, NULL}');
-COMMIT;
+INSERT INTO brinopers VALUES
+	('byteacol', 'bytea', '{>, >=, =, <=, <}', '{AAAAAA, AAAAAA, BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA, ZZZZZZ, ZZZZZZ}'),
+	('charcol', 'char', '{>, >=, =, <=, <}', '{A, A, M, Z, Z}'),
+	('namecol', 'name', '{>, >=, =, <=, <}', '{AAAAAA, AAAAAA, MAAAAA, ZZAAAA, ZZAAAA}'),
+	('int2col', 'int2', '{>, >=, =, <=, <}', '{0, 0, 800, 999, 999}'),
+	('int2col', 'int4', '{>, >=, =, <=, <}', '{0, 0, 800, 999, 1999}'),
+	('int2col', 'int8', '{>, >=, =, <=, <}', '{0, 0, 800, 999, 1428427143}'),
+	('int4col', 'int2', '{>, >=, =, <=, <}', '{0, 0, 800, 1999, 1999}'),
+	('int4col', 'int4', '{>, >=, =, <=, <}', '{0, 0, 800, 1999, 1999}'),
+	('int4col', 'int8', '{>, >=, =, <=, <}', '{0, 0, 800, 1999, 1428427143}'),
+	('int8col', 'int2', '{>, >=}', '{0, 0}'),
+	('int8col', 'int4', '{>, >=}', '{0, 0}'),
+	('int8col', 'int8', '{>, >=, =, <=, <}', '{0, 0, 1257141600, 1428427143, 1428427143}'),
+	('textcol', 'text', '{>, >=, =, <=, <}', '{AAAAAA, AAAAAA, BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA, ZZAAAA, ZZAAAA}'),
+	('oidcol', 'oid', '{>, >=, =, <=, <}', '{0, 0, 8800, 9999, 9999}'),
+	('tidcol', 'tid', '{>, >=, =, <=, <}', '{"(0,0)", "(0,0)", "(8800,0)", "(9999,19)", "(9999,19)"}'),
+	('float4col', 'float4', '{>, >=, =, <=, <}', '{0.0103093, 0.0103093, 1, 1, 1}'),
+	('float4col', 'float8', '{>, >=, =, <=, <}', '{0.0103093, 0.0103093, 1, 1, 1}'),
+	('float8col', 'float4', '{>, >=, =, <=, <}', '{0, 0, 0, 1.98, 1.98}'),
+	('float8col', 'float8', '{>, >=, =, <=, <}', '{0, 0, 0, 1.98, 1.98}'),
+	('macaddrcol', 'macaddr', '{>, >=, =, <=, <}', '{00:00:01:00:00:00, 00:00:01:00:00:00, 2c:00:2d:00:16:00, ff:fe:00:00:00:00, ff:fe:00:00:00:00}'),
+	('inetcol', 'inet', '{&&, =, <, <=, >, >=, >>=, >>, <<=, <<}', '{10/8, 10.2.14.231/24, 255.255.255.255, 255.255.255.255, 0.0.0.0, 0.0.0.0, 10.2.14.231/24, 10.2.14.231/25, 10.2.14.231/8, 0/0}'),
+	('inetcol', 'inet', '{&&, >>=, <<=, =}', '{fe80::6e40:8ff:fea9:a673/32, fe80::6e40:8ff:fea9:8c46, fe80::6e40:8ff:fea9:a673/32, fe80::6e40:8ff:fea9:8c46}'),
+	('inetcol', 'cidr', '{&&, <, <=, >, >=, >>=, >>, <<=, <<}', '{10/8, 255.255.255.255, 255.255.255.255, 0.0.0.0, 0.0.0.0, 10.2.14/24, 10.2.14/25, 10/8, 0/0}'),
+	('inetcol', 'cidr', '{&&, >>=, <<=, =}', '{fe80::/32, fe80::6e40:8ff:fea9:8c46, fe80::/32, fe80::6e40:8ff:fea9:8c46}'),
+	('cidrcol', 'inet', '{&&, =, <, <=, >, >=, >>=, >>, <<=, <<}', '{10/8, 10.2.14/24, 255.255.255.255, 255.255.255.255, 0.0.0.0, 0.0.0.0, 10.2.14.231/24, 10.2.14.231/25, 10.2.14.231/8, 0/0}'),
+	('cidrcol', 'inet', '{&&, >>=, <<=, =}', '{fe80::6e40:8ff:fea9:a673/32, fe80::6e40:8ff:fea9:8c46, fe80::6e40:8ff:fea9:a673/32, fe80::6e40:8ff:fea9:8c46}'),
+	('cidrcol', 'cidr', '{&&, =, <, <=, >, >=, >>=, >>, <<=, <<}', '{10/8, 10.2.14/24, 255.255.255.255, 255.255.255.255, 0.0.0.0, 0.0.0.0, 10.2.14/24, 10.2.14/25, 10/8, 0/0}'),
+	('cidrcol', 'cidr', '{&&, >>=, <<=, =}', '{fe80::/32, fe80::6e40:8ff:fea9:8c46, fe80::/32, fe80::6e40:8ff:fea9:8c46}'),
+	('bpcharcol', 'bpchar', '{>, >=, =, <=, <}', '{A, A, W, Z, Z}'),
+	('datecol', 'date', '{>, >=, =, <=, <}', '{1995-08-15, 1995-08-15, 2009-12-01, 2022-12-30, 2022-12-30}'),
+	('timecol', 'time', '{>, >=, =, <=, <}', '{01:20:30, 01:20:30, 02:28:57, 06:28:31.5, 06:28:31.5}'),
+	('timestampcol', 'timestamp', '{>, >=, =, <=, <}', '{1942-07-23 03:05:09, 1942-07-23 03:05:09, 1964-03-24 19:26:45, 1984-01-20 22:42:21, 1984-01-20 22:42:21}'),
+	('timestampcol', 'timestamptz', '{>, >=, =, <=, <}', '{1942-07-23 03:05:09, 1942-07-23 03:05:09, 1964-03-24 19:26:45, 1984-01-20 22:42:21, 1984-01-20 22:42:21}'),
+	('timestampcol', 'timestamptz', '{>, >=, =, <=, <}', '{1942-07-23 03:05:09, 1942-07-23 03:05:09, 1964-03-24 19:26:45, 1984-01-20 22:42:21, 1984-01-20 22:42:21}'),
+	('timestamptzcol', 'timestamptz', '{>, >=, =, <=, <}', '{1972-10-10 03:00:00-04, 1972-10-10 03:00:00-04, 1972-10-19 09:00:00-07, 1972-11-20 19:00:00-03, 1972-11-20 19:00:00-03}'),
+	('intervalcol', 'interval', '{>, >=, =, <=, <}', '{00:00:00, 00:00:00, 1 mons 13 days 12:24, 2 mons 23 days 07:48:00, 1 year}'),
+	('timetzcol', 'timetz', '{>, >=, =, <=, <}', '{01:30:20+02, 01:30:20+02, 01:35:50+02, 23:55:05+02, 23:55:05+02}'),
+	('bitcol', 'bit(10)', '{>, >=, =, <=, <}', '{0000000010, 0000000010, 0011011110, 1111111000, 1111111000}'),
+	('varbitcol', 'varbit(16)', '{>, >=, =, <=, <}', '{0000000000000100, 0000000000000100, 0001010001100110, 1111111111111000, 1111111111111000}'),
+	('numericcol', 'numeric', '{>, >=, =, <=, <}', '{0.00, 0.01, 2268164.347826086956521739130434782609, 99470151.9, 99470151.9}'),
+	('uuidcol', 'uuid', '{>, >=, =, <=, <}', '{00040004-0004-0004-0004-000400040004, 00040004-0004-0004-0004-000400040004, 52225222-5222-5222-5222-522252225222, 99989998-9998-9998-9998-999899989998, 99989998-9998-9998-9998-999899989998}'),
+	('lsncol', 'pg_lsn', '{>, >=, =, <=, <, IS, IS NOT}', '{0/1200, 0/1200, 44/455222, 198/1999799, 198/1999799, NULL, NULL}');
 
 DO $x$
 DECLARE
-        r record;
-        tabname text;
-        tabname_ss text;
-		count int;
-		query text;
-		plan text;
+	r record;
+	r2 record;
+	cond text;
+	count int;
+	mismatch bool;
 BEGIN
-        FOR r IN SELECT row_number() OVER (), colname, oper, value[ordinality] FROM brinopers, unnest(op) WITH ORDINALITY AS oper LOOP
-                tabname := format('qry_%s', r.row_number);
-                tabname_ss := tabname || '_ss';
-				query = format($y$INSERT INTO %s SELECT ctid FROM brintest WHERE %s %s %L $y$,
-                        tabname, r.colname, r.oper, r.value);
-				-- run the query using the brin index
-                SET enable_seqscan = 0;
-                SET enable_bitmapscan = 1;
-                EXECUTE format('create temp table %s (tid tid) ON COMMIT DROP', tabname);
-                EXECUTE query;
-
-				-- run the query using a seqscan
-                SET enable_seqscan = 1;
-                SET enable_bitmapscan = 0;
-				query = format($y$INSERT INTO %s SELECT ctid FROM brintest WHERE %s %s %L $y$,
-                        tabname_ss, r.colname, r.oper, r.value);
-                EXECUTE format('create temp table %s (tid tid) ON COMMIT DROP', tabname_ss);
-                EXECUTE query;
-
-				-- make sure both return the same results
-                EXECUTE format('SELECT * from %s EXCEPT ALL SELECT * FROM %s', tabname, tabname_ss);
-				GET DIAGNOSTICS count = ROW_COUNT;
-                IF count <> 0 THEN RAISE EXCEPTION 'something not right in %: count %', r, count; END IF;
-                EXECUTE format('SELECT * from %s EXCEPT ALL SELECT * FROM %s', tabname_ss, tabname);
-				GET DIAGNOSTICS count = ROW_COUNT;
-                IF count <> 0 THEN RAISE EXCEPTION 'something not right in %: count %', r, count; END IF;
-        end loop;
-end;
+	FOR r IN SELECT colname, oper, typ, value[ordinality] FROM brinopers, unnest(op) WITH ORDINALITY AS oper LOOP
+		mismatch := false;
+
+		-- prepare the condition
+		IF r.value IS NULL THEN
+			cond := format('%I %s %L', r.colname, r.oper, r.value);
+		ELSE
+			cond := format('%I %s %L::%s', r.colname, r.oper, r.value, r.typ);
+		END IF;
+
+		-- run the query using the brin index
+		CREATE TEMP TABLE brin_result (cid tid);
+		SET enable_seqscan = 0;
+		SET enable_bitmapscan = 1;
+		EXECUTE format($y$INSERT INTO brin_result SELECT ctid FROM brintest WHERE %s $y$, cond);
+
+		-- run the query using a seqscan
+		CREATE TEMP TABLE brin_result_ss (cid tid);
+		SET enable_seqscan = 1;
+		SET enable_bitmapscan = 0;
+		EXECUTE format($y$INSERT INTO brin_result_ss SELECT ctid FROM brintest WHERE %s $y$, cond);
+
+		-- make sure both return the same results
+		PERFORM * FROM brin_result EXCEPT ALL SELECT * FROM brin_result_ss;
+		GET DIAGNOSTICS count = ROW_COUNT;
+		IF count <> 0 THEN
+			mismatch = true;
+		END IF;
+		PERFORM * FROM brin_result_ss EXCEPT ALL SELECT * FROM brin_result;
+		GET DIAGNOSTICS count = ROW_COUNT;
+		IF count <> 0 THEN
+			mismatch = true;
+		END IF;
+
+		-- report the results of each scan to make the differences obvious
+		IF mismatch THEN
+			RAISE WARNING 'something not right in %: count %', r, count;
+			SET enable_seqscan = 1;
+			SET enable_bitmapscan = 0;
+			FOR r2 IN EXECUTE 'SELECT ' || r.colname || ' FROM brintest WHERE ' || cond LOOP
+				RAISE NOTICE 'seqscan: %', r2;
+			END LOOP;
+
+			SET enable_seqscan = 0;
+			SET enable_bitmapscan = 1;
+			FOR r2 IN EXECUTE 'SELECT ' || r.colname || ' FROM brintest WHERE ' || cond LOOP
+				RAISE NOTICE 'bitmapscan: %', r2;
+			END LOOP;
+		END IF;
+
+		-- make sure it was a sensible test case
+		SELECT count(*) INTO count FROM brin_result;
+		IF count = 0 THEN RAISE WARNING 'no results for %', r; END IF;
+
+		-- drop the temporary tables
+		DROP TABLE brin_result;
+		DROP TABLE brin_result_ss;
+	END LOOP;
+END;
 $x$;
 
 INSERT INTO brintest SELECT
@@ -166,6 +217,7 @@ INSERT INTO brintest SELECT
 	odd::float8 / (tenthous + 1),
 	format('%s:00:%s:00:%s:00', to_hex(odd), to_hex(even), to_hex(hundred))::macaddr,
 	inet '10.2.3.4' + tenthous,
+	cidr '10.2.3/24' + tenthous,
 	substr(stringu1, 1, 1)::bpchar,
 	date '1995-08-15' + tenthous,
 	time '01:20:30' + thousand * interval '18.5 second',
-- 
GitLab