From 0083b31ed3d11748d46c025198ae396f61b4fd87 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Thu, 7 May 2015 21:02:52 +0200
Subject: [PATCH 6/7] inclusion opclasses

---
 doc/src/sgml/brin.sgml                   |  72 +++-
 src/backend/access/brin/Makefile         |   2 +-
 src/backend/access/brin/brin_inclusion.c | 647 +++++++++++++++++++++++++++++++
 src/backend/access/brin/brin_minmax.c    |   3 +
 src/include/access/brin_internal.h       |   6 +
 src/include/catalog/pg_am.h              |   3 +-
 src/include/catalog/pg_amop.h            |  53 +++
 src/include/catalog/pg_amproc.h          |  31 ++
 src/include/catalog/pg_opclass.h         |   7 +-
 src/include/catalog/pg_opfamily.h        |   3 +
 src/include/catalog/pg_proc.h            |  10 +
 src/test/regress/expected/brin.out       |  35 +-
 src/test/regress/expected/opr_sanity.out |  30 +-
 src/test/regress/sql/brin.sql            |  35 +-
 14 files changed, 918 insertions(+), 19 deletions(-)
 create mode 100644 src/backend/access/brin/brin_inclusion.c

diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index 92dac7c..b26bcf3 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -65,21 +65,23 @@
 
  <para>
   The core <productname>PostgreSQL</productname> distribution
   includes the <acronym>BRIN</acronym> operator classes shown in 
   <xref linkend="brin-builtin-opclasses-table">.
  </para>
 
  <para>
   The <firstterm>minmax</>
   operator classes store the minimum and the maximum values appearing
-  in the indexed column within the range.
+  in the indexed column within the range.  The <firstterm>inclusion</>
+  operator classes store a value which includes the values in the indexed
+  column within the range.
  </para>
 
  <table id="brin-builtin-opclasses-table">
   <title>Built-in <acronym>BRIN</acronym> Operator Classes</title>
   <tgroup cols="3">
    <thead>
     <row>
      <entry>Name</entry>
      <entry>Indexed Data Type</entry>
      <entry>Indexable Operators</entry>
@@ -245,20 +247,32 @@
      <entry><type>inet</type></entry>
      <entry>
       <literal>&lt;</literal>
       <literal>&lt;=</literal>
       <literal>=</literal>
       <literal>&gt;=</literal>
       <literal>&gt;</literal>
      </entry>
     </row>
     <row>
+     <entry><literal>inet_inclusion_ops</literal></entry>
+     <entry><type>inet</type></entry>
+     <entry>
+      <literal>&amp;&amp;</>
+      <literal>&gt;&gt;</>
+      <literal>&gt;&gt;=</>
+      <literal>&lt;&lt;</literal>
+      <literal>&lt;&lt;=</literal>
+      <literal>=</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>bpchar_minmax_ops</literal></entry>
      <entry><type>character</type></entry>
      <entry>
       <literal>&lt;</literal>
       <literal>&lt;=</literal>
       <literal>=</literal>
       <literal>&gt;=</literal>
       <literal>&gt;</literal>
      </entry>
     </row>
@@ -366,30 +380,86 @@
      <entry><type>uuid</type></entry>
      <entry>
       <literal>&lt;</literal>
       <literal>&lt;=</literal>
       <literal>=</literal>
       <literal>&gt;=</literal>
       <literal>&gt;</literal>
      </entry>
     </row>
     <row>
+     <entry><literal>range_inclusion_ops</></entry>
+     <entry><type>any range type</type></entry>
+     <entry>
+      <literal>&amp;&amp;</>
+      <literal>&amp;&gt;</>
+      <literal>&amp;&lt;</>
+      <literal>&gt;&gt;</>
+      <literal>&lt;&lt;</>
+      <literal>&lt;@</>
+      <literal>=</>
+      <literal>@&gt;</>
+      <literal>&lt;</literal>
+      <literal>&lt;=</literal>
+      <literal>=</literal>
+      <literal>&gt;=</literal>
+      <literal>&gt;</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>pg_lsn_minmax_ops</literal></entry>
      <entry><type>pg_lsn</type></entry>
      <entry>
       <literal>&lt;</literal>
       <literal>&lt;=</literal>
       <literal>=</literal>
       <literal>&gt;=</literal>
       <literal>&gt;</literal>
      </entry>
     </row>
+    <row>
+     <entry><literal>box_inclusion_ops</></entry>
+     <entry><type>box</type></entry>
+     <entry>
+      <literal>&amp;&amp;</>
+      <literal>&amp;&gt;</>
+      <literal>&amp;&lt;</>
+      <literal>&gt;&gt;</>
+      <literal>&lt;&lt;</>
+      <literal>&lt;@</>
+      <literal>~=</>
+      <literal>@&gt;</>
+      <literal>&amp;&gt;|</>
+      <literal>|&amp;&lt;</>
+      <literal>&gt;&gt;|</>
+      <literal>|&lt;&lt;</literal>
+     </entry>
+    </row>
+    <row>
+     <entry><literal>point_box_inclusion_ops</></entry>
+     <entry><type>point</type></entry>
+     <entry>
+      <literal>&amp;&amp;</>
+      <literal>&amp;&gt;</>
+      <literal>&amp;&lt;</>
+      <literal>&gt;&gt;</>
+      <literal>&lt;&lt;</>
+      <literal>&lt;@</>
+      <literal>~=</>
+      <literal>&amp;&gt;|</>
+      <literal>|&amp;&lt;</>
+      <literal>&gt;&gt;|</>
+      <literal>|&lt;&lt;</literal>
+      <literal>&gt;^</>
+      <literal>|&lt;^</literal>
+     </entry>
+    </row>
    </tbody>
   </tgroup>
  </table>
 </sect1>
 
 <sect1 id="brin-extensibility">
  <title>Extensibility</title>
 
  <para>
   The <acronym>BRIN</acronym> interface has a high level of abstraction,
diff --git a/src/backend/access/brin/Makefile b/src/backend/access/brin/Makefile
index ac44fcd..fb36882 100644
--- a/src/backend/access/brin/Makefile
+++ b/src/backend/access/brin/Makefile
@@ -6,13 +6,13 @@
 # IDENTIFICATION
 #    src/backend/access/brin/Makefile
 #
 #-------------------------------------------------------------------------
 
 subdir = src/backend/access/brin
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
 OBJS = brin.o brin_pageops.o brin_revmap.o brin_tuple.o brin_xlog.o \
-	   brin_minmax.o
+		brin_minmax.o brin_inclusion.o
 
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c
new file mode 100644
index 0000000..1a9bafd
--- /dev/null
+++ b/src/backend/access/brin/brin_inclusion.c
@@ -0,0 +1,647 @@
+/*
+ * brin_inclusion.c
+ *		Implementation of inclusion opclasses for BRIN
+ *
+ * This module provides C level BRIN support functions for the *_inclusion_ops
+ * operator classes.  A few SQL level support functions are also required to
+ * the opclasses.
+ *
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  src/backend/access/brin/brin_inclusion.c
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/brin_internal.h"
+#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"
+
+
+/*
+ * Additional SQL level support functions
+ *
+ * Procedure numbers must not collide with BRIN_PROCNUM defines in
+ * brin_internal.h.
+ */
+#define		INCLUSION_MAX_PROCNUMS	5	/* maximum support procs we need */
+#define		PROCNUM_MERGE			11	/* required */
+#define		PROCNUM_MERGEABLE		12	/* optional */
+#define		PROCNUM_CAST			13	/* optional */
+#define		PROCNUM_CONTAINS		14	/* optional */
+#define		PROCNUM_EMPTY			15	/* optional */
+
+
+/*
+ * Subtract this from procnum to obtain index in InclusionOpaque arrays
+ * (Must be equal to minimum of private procnums)
+ */
+#define		PROCNUM_BASE			11
+
+typedef struct InclusionOpaque
+{
+	FmgrInfo	extra_procinfos[INCLUSION_MAX_PROCNUMS];
+	bool		extra_proc_exists[INCLUSION_MAX_PROCNUMS];
+	bool		extra_proc_inited[INCLUSION_MAX_PROCNUMS];
+	Oid			cached_subtype;
+	FmgrInfo	strategy_procinfos[RTMaxStrategyNumber];
+} InclusionOpaque;
+
+static FmgrInfo *inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno,
+					uint16 procnum);
+static FmgrInfo *inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno,
+					Oid subtype, uint16 strategynum);
+
+
+/*
+ * BRIN inclusion OpcInfo function
+ */
+Datum
+brin_inclusion_opcinfo(PG_FUNCTION_ARGS)
+{
+	Oid		typoid = PG_GETARG_OID(0);
+	BrinOpcInfo *result;
+	TypeCacheEntry *bool_typcache = lookup_type_cache(BOOLOID, 0);
+
+	/*
+	 * opaque->procinfos is initialized lazily, as indicated by 'inited'
+	 * which is initialized to all false by palloc0.
+	 */
+	result = palloc0(MAXALIGN(SizeofBrinOpcInfo(3)) + sizeof(InclusionOpaque));
+	result->oi_nstored = 3;
+	result->oi_opaque = (InclusionOpaque *)
+		MAXALIGN((char *) result + SizeofBrinOpcInfo(3));
+	result->oi_typcache[0] = lookup_type_cache(typoid, 0); /* the union */
+	result->oi_typcache[1] = bool_typcache; /* includes elements that are not mergeable */
+	result->oi_typcache[2] = bool_typcache; /* includes empty element */
+
+	PG_RETURN_POINTER(result);
+}
+
+/*
+ * BRIN inclusion add value function
+ *
+ * Examine the given index tuple (which contains partial status of a certain
+ * page range) by comparing it to the given value that comes from another heap
+ * tuple.  If the new value is outside the union specified by the
+ * existing tuple values, update the index tuple and return true.  Otherwise,
+ * return false and do not modify in this case.
+ */
+Datum
+brin_inclusion_add_value(PG_FUNCTION_ARGS)
+{
+	BrinDesc   *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
+	BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
+	Datum		newval = PG_GETARG_DATUM(2);
+	bool		isnull = PG_GETARG_BOOL(3);
+	Oid			colloid = PG_GET_COLLATION();
+	FmgrInfo   *frmg;
+	Datum		result;
+	bool		new = false;
+	AttrNumber	attno;
+	Form_pg_attribute attr;
+
+	/*
+	 * If the new value is null, we record that we saw it if it's the first
+	 * one; otherwise, there's nothing to do.
+	 */
+	if (isnull)
+	{
+		if (column->bv_hasnulls)
+			PG_RETURN_BOOL(false);
+
+		column->bv_hasnulls = true;
+		PG_RETURN_BOOL(true);
+	}
+
+	attno = column->bv_attno;
+	attr = bdesc->bd_tupdesc->attrs[attno - 1];
+
+	/*
+	 * If the recorded value is null, cast or copy the new value (which we
+	 * know to be not null), and we're almost done.
+	 */
+	if (column->bv_allnulls)
+	{
+		frmg = inclusion_get_procinfo(bdesc, attno, PROCNUM_CAST);
+		if (frmg != NULL)
+			column->bv_values[0] = FunctionCall1Coll(frmg, colloid, newval);
+		else
+			column->bv_values[0] = datumCopy(newval, attr->attbyval, attr->attlen);
+		column->bv_values[1] = BoolGetDatum(false);
+		column->bv_values[2] = BoolGetDatum(false);
+		column->bv_allnulls = false;
+		new = true;
+	}
+
+	/* Stop if it already contains elements that are not mergeable. */
+	if (DatumGetBool(column->bv_values[1]))
+		PG_RETURN_BOOL(false);
+
+	/* Check if the new value is empty. */
+	frmg = inclusion_get_procinfo(bdesc, attno, PROCNUM_EMPTY);
+	if (frmg != NULL && DatumGetBool(FunctionCall1Coll(frmg, colloid, newval)))
+	{
+		if (!DatumGetBool(column->bv_values[2]))
+		{
+			column->bv_values[2] = BoolGetDatum(true);
+			PG_RETURN_BOOL(true);
+		}
+
+		PG_RETURN_BOOL(false);
+	}
+
+	if (new)
+		PG_RETURN_BOOL(true);
+
+	/* Check if the new value is already contained. */
+	frmg = inclusion_get_procinfo(bdesc, attno, PROCNUM_CONTAINS);
+	if (frmg != NULL &&
+		DatumGetBool(FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   newval)))
+		PG_RETURN_BOOL(false);
+
+	/* Cast the new value if storage type is different. */
+	frmg = inclusion_get_procinfo(bdesc, attno, PROCNUM_CAST);
+	if (frmg != NULL)
+		newval = FunctionCall1Coll(frmg, colloid, newval);
+
+	/* Check if the new value is mergeable to the union. */
+	frmg = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE);
+	if (frmg != NULL &&
+		!DatumGetBool(FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   newval)))
+	{
+		column->bv_values[1] = BoolGetDatum(true);
+		PG_RETURN_BOOL(true);
+	}
+
+	/* Finally, merge the new value to the union. */
+	frmg = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE);
+	Assert(frmg != NULL);
+	result = FunctionCall2Coll(frmg, colloid, column->bv_values[0], newval);
+	if (!attr->attbyval)
+		pfree(DatumGetPointer(column->bv_values[0]));
+	column->bv_values[0] = result;
+
+	PG_RETURN_BOOL(true);
+}
+
+/*
+ * BRIN inclusion consistent function
+ *
+ * All of the strategies are optional.
+ */
+Datum
+brin_inclusion_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(),
+				subtype;
+	AttrNumber	attno;
+	Datum		query;
+	FmgrInfo   *frmg;
+	Datum		result;
+
+	Assert(key->sk_attno == column->bv_attno);
+
+	/* Handle IS NULL/IS NOT NULL tests. */
+	if (key->sk_flags & SK_ISNULL)
+	{
+		if (key->sk_flags & SK_SEARCHNULL)
+		{
+			if (column->bv_allnulls || column->bv_hasnulls)
+				PG_RETURN_BOOL(true);
+			PG_RETURN_BOOL(false);
+		}
+
+		/*
+		 * For IS NOT NULL, we can only skip ranges that are known to have
+		 * only nulls.
+		 */
+		Assert(key->sk_flags & SK_SEARCHNOTNULL);
+		PG_RETURN_BOOL(!column->bv_allnulls);
+	}
+
+	/* If it is all nulls, it cannot possibly be consistent. */
+	if (column->bv_allnulls)
+		PG_RETURN_BOOL(false);
+
+	/* It has to be checked, if it contains elements that are not mergeable. */
+	if (DatumGetBool(column->bv_values[1]))
+		PG_RETURN_BOOL(true);
+
+	attno = key->sk_attno;
+	subtype = key->sk_subtype;
+	query = key->sk_argument;
+	switch (key->sk_strategy)
+	{
+		/*
+		 * Placement strategies
+		 *
+		 * They are implemented by using logical negation of the other
+		 * placement operators.  So the other strategies are required for
+		 * them to be used.  An error will be thrown by inclusion_get_strategy_procinfo()
+		 * if the required strategy does not exists.
+		 *
+		 * These all return false if either argument is empty, so there is
+		 * no need to check for empty elements.
+		 */
+
+		case RTLeftStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTOverRightStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_BOOL(!DatumGetBool(result));
+
+		case RTOverLeftStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTRightStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_BOOL(!DatumGetBool(result));
+
+		case RTOverRightStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTLeftStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_BOOL(!DatumGetBool(result));
+
+		case RTRightStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTOverLeftStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_BOOL(!DatumGetBool(result));
+
+		case RTBelowStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTOverAboveStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_BOOL(!DatumGetBool(result));
+
+		case RTOverBelowStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTAboveStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_BOOL(!DatumGetBool(result));
+
+		case RTOverAboveStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTBelowStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_BOOL(!DatumGetBool(result));
+
+		case RTAboveStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTOverBelowStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_BOOL(!DatumGetBool(result));
+
+		/*
+		 * Overlaps and contains strategies
+		 *
+		 * These strategies are simple enough that we will call the operator
+		 * of the strategy.  Empty element doesn't change their the results.
+		 */
+
+		case RTOverlapStrategyNumber:
+		case RTContainsStrategyNumber:
+		case RTOldContainsStrategyNumber:
+		case RTContainsElemStrategyNumber:
+		case RTContainsNotEqualStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   key->sk_strategy);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_DATUM(result);
+
+		/*
+		 * Contained by strategies
+		 *
+		 * We cannot just call the original operator for the contained by
+		 * strategies because some elements can be contained even thought
+		 * the union is not.
+		 *
+		 * Also, we will check for empty elements as they are not merged to
+		 * the union but contained by everything.
+		 */
+
+		case RTContainedByStrategyNumber:
+		case RTOldContainedByStrategyNumber:
+		case RTContainedByNotEqualStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTOverlapStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			if (DatumGetBool(result))
+				PG_RETURN_BOOL(true);
+
+			PG_RETURN_DATUM(column->bv_values[2]);
+
+		/*
+		 * Adjacent strategy
+		 *
+		 * To be adjacent with an element in the query most likely to overlap
+		 * with the union.  We will call the actual adjacent procedure in
+		 * case it is not.
+		 *
+		 * An empty element cannot be adjacent to any other, so there is
+		 * no need to check for it.
+		 */
+
+		case RTAdjacentStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTOverlapStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			if (DatumGetBool(result))
+				PG_RETURN_BOOL(true);
+
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTAdjacentStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_DATUM(result);
+
+		/*
+		 * Basic comparison strategies
+		 *
+		 * It is straightforward to support the equality strategies with
+		 * the contains operator.  Generally, inequality strategies do not
+		 * make much sense for the types which will be used with the inclusion
+		 * operator class, but is is possible to implement them with logical
+		 * negation of the left of and right of operator.
+		 *
+		 * Note that, these strategies except the same strategy are not
+		 * suitable for the geometric types which use basic comparison
+		 * operators for their areas.
+		 *
+		 * Empty elements are considered to be less than the others.  We
+		 * cannot use the empty support function to check the query is
+		 * an empty element, because the query can be another data type than
+		 * the empty support function argument.  So we will return true,
+		 * if there is a possibility that empty elements will change
+		 * the result.
+		 */
+
+		case RTLessStrategyNumber:
+		case RTLessEqualStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTRightStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			if (!DatumGetBool(result))
+				PG_RETURN_BOOL(true);
+
+			PG_RETURN_DATUM(column->bv_values[2]);
+
+		case RTSameStrategyNumber:
+		case RTEqualStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTContainsStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			if (DatumGetBool(result))
+				PG_RETURN_BOOL(true);
+
+			PG_RETURN_DATUM(column->bv_values[2]);
+
+
+		case RTGreaterEqualStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTLeftStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			if (!DatumGetBool(result))
+				PG_RETURN_BOOL(true);
+
+			PG_RETURN_DATUM(column->bv_values[2]);
+
+		case RTGreaterStrategyNumber:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTLeftStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_BOOL(!DatumGetBool(result));
+
+		default:
+			/* shouldn't happen */
+			elog(ERROR, "invalid strategy number %d", key->sk_strategy);
+			PG_RETURN_BOOL(false);
+	}
+}
+
+/*
+ * BRIN inclusion union function
+ *
+ * Given two BrinValues, update the first of them as a union of the summary
+ * values contained in both.  The second one is untouched.
+ */
+Datum
+brin_inclusion_union(PG_FUNCTION_ARGS)
+{
+	BrinDesc   *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
+	BrinValues *col_a = (BrinValues *) PG_GETARG_POINTER(1);
+	BrinValues *col_b = (BrinValues *) PG_GETARG_POINTER(2);
+	Oid			colloid = PG_GET_COLLATION();
+	AttrNumber	attno;
+	Form_pg_attribute attr;
+	FmgrInfo   *frmg;
+	Datum		result;
+
+	Assert(col_a->bv_attno == col_b->bv_attno);
+
+	/* Adjust "hasnulls". */
+	if (!col_a->bv_hasnulls && col_b->bv_hasnulls)
+		col_a->bv_hasnulls = true;
+
+	/* If there are no values in B, there's nothing left to do. */
+	if (col_b->bv_allnulls)
+		PG_RETURN_VOID();
+
+	attno = col_a->bv_attno;
+	attr = bdesc->bd_tupdesc->attrs[attno - 1];
+
+	/*
+	 * Adjust "allnulls".  If A doesn't have values, just copy the values
+	 * from B into A, and we're done.  We cannot run the operators in this
+	 * case, because values in A might contain garbage.  Note we already
+	 * established that B contains values.
+	 */
+	if (col_a->bv_allnulls)
+	{
+		col_a->bv_allnulls = false;
+		col_a->bv_values[0] = datumCopy(col_b->bv_values[0],
+										attr->attbyval, attr->attlen);
+		col_a->bv_values[2] = col_b->bv_values[2];
+		col_a->bv_values[1] = col_b->bv_values[1];
+		PG_RETURN_VOID();
+	}
+
+	/* Check if B includes empty elements. */
+	if (!DatumGetBool(col_a->bv_values[2]) &&
+		DatumGetBool(col_b->bv_values[2]))
+		col_a->bv_values[2] = BoolGetDatum(true);
+
+	/* Check if A includes elements that are not mergeable. */
+	if (DatumGetBool(col_a->bv_values[1]))
+		PG_RETURN_VOID();
+
+	/* Check if B includes elements that are not mergeable. */
+	if (DatumGetBool(col_b->bv_values[1]))
+	{
+		col_a->bv_values[1] = BoolGetDatum(true);
+		PG_RETURN_VOID();
+	}
+
+	/* Check if A and B are mergeable. */
+	frmg = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE);
+	if (frmg != NULL &&
+		!DatumGetBool(FunctionCall2Coll(frmg, colloid, col_a->bv_values[0],
+									   col_b->bv_values[0])))
+	{
+		col_a->bv_values[1] = BoolGetDatum(true);
+		PG_RETURN_VOID();
+	}
+
+	/* Finally, merge B to A. */
+	frmg = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE);
+	Assert(frmg != NULL);
+	result = FunctionCall2Coll(frmg, colloid, col_a->bv_values[0],
+							   col_b->bv_values[0]);
+	if (!attr->attbyval)
+		pfree(DatumGetPointer(col_a->bv_values[0]));
+	col_a->bv_values[0] = result;
+
+	PG_RETURN_VOID();
+}
+
+/*
+ * Cache and return inclusion opclass support procedure
+ *
+ * Return the procedure corresponding to the given function support number
+ * or null if it is not exists.
+ */
+static FmgrInfo *
+inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
+{
+	InclusionOpaque *opaque;
+	uint16		basenum = procnum - PROCNUM_BASE;
+
+	opaque = (InclusionOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
+
+	/*
+	 * We cache these in the opaque struct, to avoid repetitive syscache
+	 * lookups.
+	 */
+	if (!opaque->extra_proc_inited[basenum])
+	{
+		if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
+												procnum)))
+		{
+			fmgr_info_copy(&opaque->extra_procinfos[basenum],
+						   index_getprocinfo(bdesc->bd_index, attno, procnum),
+						   bdesc->bd_context);
+
+			opaque->extra_proc_exists[basenum] = true;
+		}
+
+		opaque->extra_proc_inited[basenum] = true;
+	}
+
+	if (opaque->extra_proc_exists[basenum])
+		return &opaque->extra_procinfos[basenum];
+	else
+		return NULL;
+}
+
+/*
+ * Cache and return the procedure of the given strategy
+ *
+ * Return the procedure corresponding to the given sub-type and strategy
+ * number.  The data type of the index will be used as the left hand side
+ * of the operator and the given sub-type will be used as the right hand side.
+ * Throws an error, if the pg_amop row is not exists, but it should not happen
+ * on a properly configured opclass.
+ *
+ * It always throws an error when the data type of the opclass is different
+ * from the data type of the column or the expression.  It happens when
+ * the column data type has implicit cast to the opclass data type.  We don't
+ * bother casting types, because this situation can easily be avoided by
+ * setting storage data type to the opclass.  Same problem does not apply
+ * to the data type of the right hand side, because the type from ScanKey
+ * is always the one which fits the opclass.
+ */
+static FmgrInfo *
+inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype,
+								uint16 strategynum)
+{
+	InclusionOpaque *opaque;
+
+	Assert(strategynum >= 1 &&
+		   strategynum <= RTMaxStrategyNumber);
+
+	opaque = (InclusionOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
+
+	/*
+	 * We cache the procedures for the last sub-type in the opaque struct,
+	 * to avoid repetitive syscache lookups.  If the sub-type is changed,
+	 * invalidate all the cached entries.
+	 */
+	if (opaque->cached_subtype != subtype)
+	{
+		uint16		i;
+
+		for (i = 1; i <= RTMaxStrategyNumber; i++)
+			opaque->strategy_procinfos[i - 1].fn_oid = InvalidOid;
+		opaque->cached_subtype = subtype;
+	}
+
+	if (opaque->strategy_procinfos[strategynum - 1].fn_oid == InvalidOid)
+	{
+		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->strategy_procinfos[strategynum - 1];
+}
diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c
index d64c4f0..236734c 100644
--- a/src/backend/access/brin/brin_minmax.c
+++ b/src/backend/access/brin/brin_minmax.c
@@ -295,20 +295,23 @@ brin_minmax_union(PG_FUNCTION_ARGS)
 			pfree(DatumGetPointer(col_a->bv_values[1]));
 		col_a->bv_values[1] = datumCopy(col_b->bv_values[1],
 										attr->attbyval, attr->attlen);
 	}
 
 	PG_RETURN_VOID();
 }
 
 /*
  * Cache and return the procedure for the given strategy.
+ *
+ * This function has the same structure with inclusion_get_strategy_procinfo()
+ * on brin_inclusion.c.
  */
 static FmgrInfo *
 minmax_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype,
 							 uint16 strategynum)
 {
 	MinmaxOpaque *opaque;
 
 	Assert(strategynum >= 1 &&
 		   strategynum <= BTMaxStrategyNumber);
 
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
index 1486d04..8efceee 100644
--- a/src/include/access/brin_internal.h
+++ b/src/include/access/brin_internal.h
@@ -85,11 +85,17 @@ typedef struct BrinDesc
 extern BrinDesc *brin_build_desc(Relation rel);
 extern void brin_free_desc(BrinDesc *bdesc);
 extern Datum brin_summarize_new_values(PG_FUNCTION_ARGS);
 
 /* brin_minmax.c */
 extern Datum brin_minmax_opcinfo(PG_FUNCTION_ARGS);
 extern Datum brin_minmax_add_value(PG_FUNCTION_ARGS);
 extern Datum brin_minmax_consistent(PG_FUNCTION_ARGS);
 extern Datum brin_minmax_union(PG_FUNCTION_ARGS);
 
+/* brin_inclusion.c */
+extern Datum brin_inclusion_opcinfo(PG_FUNCTION_ARGS);
+extern Datum brin_inclusion_add_value(PG_FUNCTION_ARGS);
+extern Datum brin_inclusion_consistent(PG_FUNCTION_ARGS);
+extern Datum brin_inclusion_union(PG_FUNCTION_ARGS);
+
 #endif   /* BRIN_INTERNAL_H */
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index 79609f7..8a28b8e 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -125,14 +125,15 @@ DESCR("hash index access method");
 #define HASH_AM_OID 405
 DATA(insert OID = 783 (  gist		0 9 f t f f t t f t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup gistcanreturn 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 ));
 DESCR("SP-GiST index access method");
 #define SPGIST_AM_OID 4000
-DATA(insert OID = 3580 (  brin	5 14 f f f f t t f t t f f 0 brininsert brinbeginscan - bringetbitmap brinrescan brinendscan brinmarkpos brinrestrpos brinbuild brinbuildempty brinbulkdelete brinvacuumcleanup - brincostestimate brinoptions ));
+DATA(insert OID = 3580 (  brin	   0 15 f f f f t t f t t f f 0 brininsert brinbeginscan - bringetbitmap brinrescan brinendscan brinmarkpos brinrestrpos brinbuild brinbuildempty brinbulkdelete brinvacuumcleanup - brincostestimate brinoptions ));
+DESCR("block range index (BRIN) access method");
 #define BRIN_AM_OID 3580
 
 #endif   /* PG_AM_H */
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 5aab896..c7c928b 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -968,20 +968,27 @@ DATA(insert (   4074    829  829 1 s      1222    3580 0 ));
 DATA(insert (   4074    829  829 2 s      1223    3580 0 ));
 DATA(insert (   4074    829  829 3 s      1220    3580 0 ));
 DATA(insert (   4074    829  829 4 s      1225    3580 0 ));
 DATA(insert (   4074    829  829 5 s      1224    3580 0 ));
 /* minmax inet */
 DATA(insert (   4075    869  869 1 s      1203    3580 0 ));
 DATA(insert (   4075    869  869 2 s      1204    3580 0 ));
 DATA(insert (   4075    869  869 3 s      1201    3580 0 ));
 DATA(insert (   4075    869  869 4 s      1206    3580 0 ));
 DATA(insert (   4075    869  869 5 s      1205    3580 0 ));
+/* inclusion inet */
+DATA(insert (   4102    869  869 3 s      3552    3580 0 ));
+DATA(insert (   4102    869  869 7 s       934    3580 0 ));
+DATA(insert (   4102    869  869 8 s       932    3580 0 ));
+DATA(insert (   4102    869  869 18 s     1201    3580 0 ));
+DATA(insert (   4102    869  869 24 s      933    3580 0 ));
+DATA(insert (   4102    869  869 26 s      931    3580 0 ));
 /* minmax character */
 DATA(insert (   4076   1042 1042 1 s      1058    3580 0 ));
 DATA(insert (   4076   1042 1042 2 s      1059    3580 0 ));
 DATA(insert (   4076   1042 1042 3 s      1054    3580 0 ));
 DATA(insert (   4076   1042 1042 4 s      1061    3580 0 ));
 DATA(insert (   4076   1042 1042 5 s      1060    3580 0 ));
 /* minmax time without time zone */
 DATA(insert (   4077   1083 1083 1 s      1110    3580 0 ));
 DATA(insert (   4077   1083 1083 2 s      1111    3580 0 ));
 DATA(insert (   4077   1083 1083 3 s      1108    3580 0 ));
@@ -1063,18 +1070,64 @@ DATA(insert (   4055   1700 1700 1 s      1754    3580 0 ));
 DATA(insert (   4055   1700 1700 2 s      1755    3580 0 ));
 DATA(insert (   4055   1700 1700 3 s      1752    3580 0 ));
 DATA(insert (   4055   1700 1700 4 s      1757    3580 0 ));
 DATA(insert (   4055   1700 1700 5 s      1756    3580 0 ));
 /* minmax uuid */
 DATA(insert (   4081   2950 2950 1 s      2974    3580 0 ));
 DATA(insert (   4081   2950 2950 2 s      2976    3580 0 ));
 DATA(insert (   4081   2950 2950 3 s      2972    3580 0 ));
 DATA(insert (   4081   2950 2950 4 s      2977    3580 0 ));
 DATA(insert (   4081   2950 2950 5 s      2975    3580 0 ));
+/* inclusion range types */
+DATA(insert (   4103   3831 3831  1 s     3893    3580 0 ));
+DATA(insert (   4103   3831 3831  2 s     3895    3580 0 ));
+DATA(insert (   4103   3831 3831  3 s     3888    3580 0 ));
+DATA(insert (   4103   3831 3831  4 s     3896    3580 0 ));
+DATA(insert (   4103   3831 3831  5 s     3894    3580 0 ));
+DATA(insert (   4103   3831 3831  7 s     3890    3580 0 ));
+DATA(insert (   4103   3831 3831  8 s     3892    3580 0 ));
+DATA(insert (   4103   3831 2283 16 s     3889    3580 0 ));
+DATA(insert (   4103   3831 3831 17 s     3897    3580 0 ));
+DATA(insert (   4103   3831 3831 18 s     3882    3580 0 ));
+DATA(insert (   4103   3831 3831 20 s     3884    3580 0 ));
+DATA(insert (   4103   3831 3831 21 s     3885    3580 0 ));
+DATA(insert (   4103   3831 3831 22 s     3887    3580 0 ));
+DATA(insert (   4103   3831 3831 23 s     3886    3580 0 ));
 /* minmax pg_lsn */
 DATA(insert (   4082   3220 3220 1 s      3224    3580 0 ));
 DATA(insert (   4082   3220 3220 2 s      3226    3580 0 ));
 DATA(insert (   4082   3220 3220 3 s      3222    3580 0 ));
 DATA(insert (   4082   3220 3220 4 s      3227    3580 0 ));
 DATA(insert (   4082   3220 3220 5 s      3225    3580 0 ));
+/* inclusion box */
+DATA(insert (	4104    603	 603  1 s	   493	  3580 0 ));
+DATA(insert (	4104    603  603  2 s	   494	  3580 0 ));
+DATA(insert (	4104    603  603  3 s	   500	  3580 0 ));
+DATA(insert (	4104    603  603  4 s	   495	  3580 0 ));
+DATA(insert (	4104    603  603  5 s	   496	  3580 0 ));
+DATA(insert (	4104    603  603  6 s	   499	  3580 0 ));
+DATA(insert (	4104    603  603  7 s	   498	  3580 0 ));
+DATA(insert (	4104    603  603  8 s	   497	  3580 0 ));
+DATA(insert (	4104    603  603  9 s	  2571	  3580 0 ));
+DATA(insert (	4104    603  603 10 s 	  2570	  3580 0 ));
+DATA(insert (	4104    603  603 11 s 	  2573	  3580 0 ));
+DATA(insert (	4104    603  603 12 s 	  2572	  3580 0 ));
+DATA(insert (	4104    603  603 13 s 	  2863	  3580 0 ));
+DATA(insert (	4104    603  603 14 s 	  2862	  3580 0 ));
+DATA(insert (	4104    603  600  1 s	  4092	  3580 0 ));
+DATA(insert (	4104    603  600  2 s	  4093	  3580 0 ));
+DATA(insert (	4104    603  600  4 s	  4095	  3580 0 ));
+DATA(insert (	4104    603  600  5 s	  4094	  3580 0 ));
+DATA(insert (	4104    603  600  7 s	   433	  3580 0 ));
+DATA(insert (	4104    603  600  9 s	  4097	  3580 0 ));
+DATA(insert (	4104    603  600 10 s	  4096	  3580 0 ));
+DATA(insert (	4104    603  600 11 s	  4098	  3580 0 ));
+DATA(insert (	4104    603  600 12 s	  4099	  3580 0 ));
+/* inclusion point */
+DATA(insert (	4104    600  600  1 s	   507	  3580 0 ));
+DATA(insert (	4104    600  600  5 s	   508	  3580 0 ));
+DATA(insert (	4104    600  600  6 s	   510	  3580 0 ));
+DATA(insert (	4104    600  600 10 s 	   509	  3580 0 ));
+DATA(insert (	4104    600  600 11 s 	   506	  3580 0 ));
+DATA(insert (	4104    600  603  3 s	   511	  3580 0 ));
 
 #endif   /* PG_AMOP_H */
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index e3de3b5..ca2509b 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -542,20 +542,28 @@ DATA(insert (   4073   703   703  4  3386 ));
 /* 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 ));
 /* 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 ));
+/* inclusion inet */
+DATA(insert (   4102   869   869  1  4105 ));
+DATA(insert (   4102   869   869  2  4106 ));
+DATA(insert (   4102   869   869  3  4107 ));
+DATA(insert (   4102   869   869  4  4108 ));
+DATA(insert (   4102   869   869 11  4063 ));
+DATA(insert (   4102   869   869 12  4071 ));
+DATA(insert (   4102   869   869 14   930 ));
 /* 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 ));
 /* 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 ));
@@ -622,17 +630,40 @@ DATA(insert (   4080  1562  1562  4  3386 ));
 /* 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 ));
 /* 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 ));
+/* inclusion range types */
+DATA(insert (   4103  3831  3831  1  4105 ));
+DATA(insert (   4103  3831  3831  2  4106 ));
+DATA(insert (   4103  3831  3831  3  4107 ));
+DATA(insert (   4103  3831  3831  4  4108 ));
+DATA(insert (   4103  3831  3831  11 4057 ));
+DATA(insert (   4103  3831  3831  14 3859 ));
+DATA(insert (   4103  3831  3831  15 3850 ));
 /* 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 ));
+/* inclusion box */
+DATA(insert (   4104   603   603  1  4105 ));
+DATA(insert (   4104   603   603  2  4106 ));
+DATA(insert (   4104   603   603  3  4107 ));
+DATA(insert (   4104   603   603  4  4108 ));
+DATA(insert (   4104   603   603  11 4067 ));
+DATA(insert (   4104   603   603  14  187 ));
+/* inclusion point */
+DATA(insert (   4104   600   600  1  4105 ));
+DATA(insert (   4104   600   600  2  4106 ));
+DATA(insert (   4104   600   600  3  4107 ));
+DATA(insert (   4104   600   600  4  4108 ));
+DATA(insert (   4104   600   600  11 4067 ));
+DATA(insert (   4104   600   600  13 4091 ));
+DATA(insert (   4104   600   600  14  193 ));
 
 #endif   /* PG_AMPROC_H */
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index f946937..145f0bd 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -246,26 +246,31 @@ 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	inet_inclusion_ops		PGNSP PGUID 4102   869 t 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 2950 ));
+DATA(insert (	3580	range_inclusion_ops		PGNSP PGUID 4103  3831 t 3831 ));
 DATA(insert (	3580	pg_lsn_minmax_ops		PGNSP PGUID 4082  3220 t 3220 ));
-/* no brin opclass for enum, tsvector, tsquery, jsonb, range */
+/* no brin opclass for enum, tsvector, tsquery, jsonb */
+DATA(insert (	3580	box_inclusion_ops		PGNSP PGUID 4104   603 t 603 ));
+DATA(insert (	3580	point_box_inclusion_ops	PGNSP PGUID 4104   600 t 603 ));
+/* no brin opclass for the geometric types except box and point */
 
 #endif   /* PG_OPCLASS_H */
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index 97ffa32..acbc100 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -165,19 +165,22 @@ DATA(insert OID = 4059 (	3580	datetime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4062 (	3580	char_minmax_ops			PGNSP PGUID ));
 DATA(insert OID = 4064 (	3580	bytea_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4065 (	3580	name_minmax_ops			PGNSP PGUID ));
 DATA(insert OID = 4068 (	3580	oid_minmax_ops			PGNSP PGUID ));
 DATA(insert OID = 4069 (	3580	tid_minmax_ops			PGNSP PGUID ));
 DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4077 (	3580	time_minmax_ops			PGNSP PGUID ));
 DATA(insert OID = 4078 (	3580	interval_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4079 (	3580	bit_minmax_ops			PGNSP PGUID ));
 DATA(insert OID = 4080 (	3580	varbit_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4081 (	3580	uuid_minmax_ops			PGNSP PGUID ));
+DATA(insert OID = 4103 (	3580	range_inclusion_ops		PGNSP PGUID ));
 DATA(insert OID = 4082 (	3580	pg_lsn_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4104 (	3580	box_inclusion_ops		PGNSP PGUID ));
 
 #endif   /* PG_OPFAMILY_H */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index e9d589e..d95645a 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4213,20 +4213,30 @@ DATA(insert OID = 2749 (  arraycontained	   PGNSP PGUID 12 1 0 0 0 f f f f t f i
 /* BRIN minmax */
 DATA(insert OID = 3383 ( brin_minmax_opcinfo	PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ _null_ brin_minmax_opcinfo _null_ _null_ _null_ ));
 DESCR("BRIN minmax support");
 DATA(insert OID = 3384 ( brin_minmax_add_value	PGNSP PGUID 12 1 0 0 0 f f f f t f i 4 0 16 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_minmax_add_value _null_ _null_ _null_ ));
 DESCR("BRIN minmax support");
 DATA(insert OID = 3385 ( brin_minmax_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_minmax_consistent _null_ _null_ _null_ ));
 DESCR("BRIN minmax support");
 DATA(insert OID = 3386 ( brin_minmax_union		PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_minmax_union _null_ _null_ _null_ ));
 DESCR("BRIN minmax support");
 
+/* BRIN inclusion */
+DATA(insert OID = 4105 ( brin_inclusion_opcinfo PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ _null_ brin_inclusion_opcinfo _null_ _null_ _null_ ));
+DESCR("BRIN inclusion support");
+DATA(insert OID = 4106 ( brin_inclusion_add_value PGNSP PGUID 12 1 0 0 0 f f f f t f i 4 0 16 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_inclusion_add_value _null_ _null_ _null_ ));
+DESCR("BRIN inclusion support");
+DATA(insert OID = 4107 ( brin_inclusion_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_inclusion_consistent _null_ _null_ _null_ ));
+DESCR("BRIN inclusion support");
+DATA(insert OID = 4108 ( brin_inclusion_union 	PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_inclusion_union _null_ _null_ _null_ ));
+DESCR("BRIN inclusion support");
+
 /* userlock replacements */
 DATA(insert OID = 2880 (  pg_advisory_lock				PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ _null_ pg_advisory_lock_int8 _null_ _null_ _null_ ));
 DESCR("obtain exclusive advisory lock");
 DATA(insert OID = 3089 (  pg_advisory_xact_lock				PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ _null_ pg_advisory_xact_lock_int8 _null_ _null_ _null_ ));
 DESCR("obtain exclusive advisory lock");
 DATA(insert OID = 2881 (  pg_advisory_lock_shared		PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ _null_ pg_advisory_lock_shared_int8 _null_ _null_ _null_ ));
 DESCR("obtain shared advisory lock");
 DATA(insert OID = 3090 (  pg_advisory_xact_lock_shared		PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ _null_ pg_advisory_xact_lock_shared_int8 _null_ _null_ _null_ ));
 DESCR("obtain shared advisory lock");
 DATA(insert OID = 2882 (  pg_try_advisory_lock			PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ _null_ pg_try_advisory_lock_int8 _null_ _null_ _null_ ));
diff --git a/src/test/regress/expected/brin.out b/src/test/regress/expected/brin.out
index 4fe6f07..1ffa598 100644
--- a/src/test/regress/expected/brin.out
+++ b/src/test/regress/expected/brin.out
@@ -16,21 +16,24 @@ CREATE TABLE brintest (byteacol bytea,
 	datecol date,
 	timecol time without time zone,
 	timestampcol timestamp without time zone,
 	timestamptzcol timestamp with time zone,
 	intervalcol interval,
 	timetzcol time with time zone,
 	bitcol bit(10),
 	varbitcol bit varying(16),
 	numericcol numeric,
 	uuidcol uuid,
-	lsncol pg_lsn
+	int4rangecol int4range,
+	lsncol pg_lsn,
+	boxcol box,
+	pointcol point
 ) WITH (fillfactor=10, autovacuum_enabled=off);
 INSERT INTO brintest SELECT
 	repeat(stringu1, 8)::bytea,
 	substr(stringu1, 1, 1)::"char",
 	stringu1::name, 142857 * tenthous,
 	thousand,
 	twothousand,
 	repeat(stringu1, 8),
 	unique1::oid,
 	format('(%s,%s)', tenthous, twenty)::tid,
@@ -43,53 +46,61 @@ INSERT INTO brintest SELECT
 	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+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
+	int4range(thousand, twothousand),
+	format('%s/%s%s', odd, even, tenthous)::pg_lsn,
+	box(point(odd, even), point(thousand, twothousand)),
+	point(thousand, twothousand)
 FROM tenk1 LIMIT 25;
 -- throw in some NULL's and different values
-INSERT INTO brintest (inetcol, cidrcol) SELECT
+INSERT INTO brintest (inetcol, cidrcol, int4rangecol) SELECT
 	inet 'fe80::6e40:8ff:fea9:8c46' + tenthous,
-	cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous
+	cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous,
+	'empty'::int4range
 FROM tenk1 LIMIT 25;
 CREATE INDEX brinidx ON brintest USING brin (
 	byteacol,
 	charcol,
 	namecol,
 	int8col,
 	int2col,
 	int4col,
 	textcol,
 	oidcol,
 	tidcol,
 	float4col,
 	float8col,
 	macaddrcol,
+	inetcol inet_inclusion_ops,
 	inetcol inet_minmax_ops,
 	bpcharcol,
 	datecol,
 	timecol,
 	timestampcol,
 	timestamptzcol,
 	intervalcol,
 	timetzcol,
 	bitcol,
 	varbitcol,
 	numericcol,
 	uuidcol,
-	lsncol
+	int4rangecol,
+	lsncol,
+	boxcol,
+	pointcol
 ) with (pages_per_range = 1);
 CREATE TABLE brinopers (colname name, typ text, op text[], value text[],
 	check (cardinality(op) = cardinality(value)));
 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}'),
@@ -121,21 +132,28 @@ INSERT INTO brinopers VALUES
 	('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}');
+	('int4rangecol', 'int4range', '{<<, &<, &&, &>, >>, @>, <@, =, <, <=, >, >=}', '{"[10000,)","[10000,)","(,]","[3,4)","[36,44)","(1500,1501]","[3,4)","[222,1222)","[36,44)","[43,1043)","[367,4466)","[519,)"}'),
+	('int4rangecol', 'int4range', '{@>, <@, =, <=, >, >=}', '{empty, empty, empty, empty, empty, empty}'),
+	('int4rangecol', 'int4', '{@>}', '{1500}'),
+	('lsncol', 'pg_lsn', '{>, >=, =, <=, <, IS, IS NOT}', '{0/1200, 0/1200, 44/455222, 198/1999799, 198/1999799, NULL, NULL}'),
+	('boxcol', 'point', '{<<, &<, &>, >>, <<|, &<|, |&>, |>>, @>}', '{"(1000,2000)","(3000,4000)","(1,2)","(3,4)","(3000,4000)","(3000,4000)","(1,2)","(1,2)","(500,43)"}'),
+	('boxcol', 'box', '{<<, &<, &&, &>, >>, <<|, &<|, |&>, |>>, @>, <@, ~=}', '{"((1000,2000),(3000,4000))","((1,2),(3000,4000))","((1,2),(3000,4000))","((1,2),(3000,4000))","((1,2),(3,4))","((1000,2000),(3000,4000))","((1,2000),(3,4000))","((1000,2),(3000,4))","((1,2),(3,4))","((1,2),(300,400))","((1,2),(3000,4000))","((222,1222),(44,45))"}'),
+	('pointcol', 'point', '{<<, >>, <^, >^, ~=}', '{"(3000,4000)","(3,4)","(5000,15000)","(1,2)","(222,1222)"}'),
+	('pointcol', 'box', '{<@}', '{"((0,0),(5000,5000))"}');
 DO $x$
 DECLARE
 	r record;
 	r2 record;
 	cond text;
 	count int;
 	mismatch bool;
 BEGIN
 	FOR r IN SELECT colname, oper, typ, value[ordinality] FROM brinopers, unnest(op) WITH ORDINALITY AS oper LOOP
 		mismatch := false;
@@ -215,20 +233,23 @@ INSERT INTO brintest SELECT
 	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',
 	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
+	int4range(thousand, twothousand),
+	format('%s/%s%s', odd, even, tenthous)::pg_lsn,
+	box(point(odd, even), point(thousand, twothousand)),
+	point(thousand, twothousand)
 FROM tenk1 LIMIT 5 OFFSET 5;
 SELECT brin_summarize_new_values('brinidx'::regclass);
  brin_summarize_new_values 
 ---------------------------
                          5
 (1 row)
 
 UPDATE brintest SET int8col = int8col * int4col;
 UPDATE brintest SET textcol = '' WHERE textcol IS NOT NULL;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 6b248f2..108dfa0 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1650,24 +1650,52 @@ ORDER BY 1, 2, 3;
        2742 |            1 | @@
        2742 |            2 | @>
        2742 |            2 | @@@
        2742 |            3 | <@
        2742 |            4 | =
        2742 |            7 | @>
        2742 |            9 | ?
        2742 |           10 | ?|
        2742 |           11 | ?&
        3580 |            1 | <
+       3580 |            1 | <<
+       3580 |            2 | &<
        3580 |            2 | <=
+       3580 |            3 | &&
+       3580 |            3 | <@
        3580 |            3 | =
+       3580 |            4 | &>
        3580 |            4 | >=
        3580 |            5 | >
+       3580 |            5 | >>
+       3580 |            6 | ~=
+       3580 |            7 | >>=
+       3580 |            7 | @>
+       3580 |            8 | <<=
+       3580 |            8 | <@
+       3580 |            9 | &<|
+       3580 |           10 | <<|
+       3580 |           10 | <^
+       3580 |           11 | >^
+       3580 |           11 | |>>
+       3580 |           12 | |&>
+       3580 |           13 | ~
+       3580 |           14 | @
+       3580 |           16 | @>
+       3580 |           17 | -|-
+       3580 |           18 | =
+       3580 |           20 | <
+       3580 |           21 | <=
+       3580 |           22 | >
+       3580 |           23 | >=
+       3580 |           24 | >>
+       3580 |           26 | <<
        4000 |            1 | <<
        4000 |            1 | ~<~
        4000 |            2 | &<
        4000 |            2 | ~<=~
        4000 |            3 | &&
        4000 |            3 | =
        4000 |            4 | &>
        4000 |            4 | ~>=~
        4000 |            5 | >>
        4000 |            5 | ~>~
@@ -1676,21 +1704,21 @@ ORDER BY 1, 2, 3;
        4000 |            7 | @>
        4000 |            8 | <@
        4000 |           10 | <^
        4000 |           11 | <
        4000 |           11 | >^
        4000 |           12 | <=
        4000 |           14 | >=
        4000 |           15 | >
        4000 |           16 | @>
        4000 |           18 | =
-(85 rows)
+(113 rows)
 
 -- Check that all opclass search operators have selectivity estimators.
 -- This is not absolutely required, but it seems a reasonable thing
 -- to insist on for all standard datatypes.
 SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
 FROM pg_amop AS p1, pg_operator AS p2
 WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND
     (p2.oprrest = 0 OR p2.oprjoin = 0);
  amopfamily | amopopr | oid | oprname 
 ------------+---------+-----+---------
diff --git a/src/test/regress/sql/brin.sql b/src/test/regress/sql/brin.sql
index 6a695bb..d528f3f 100644
--- a/src/test/regress/sql/brin.sql
+++ b/src/test/regress/sql/brin.sql
@@ -16,21 +16,24 @@ CREATE TABLE brintest (byteacol bytea,
 	datecol date,
 	timecol time without time zone,
 	timestampcol timestamp without time zone,
 	timestamptzcol timestamp with time zone,
 	intervalcol interval,
 	timetzcol time with time zone,
 	bitcol bit(10),
 	varbitcol bit varying(16),
 	numericcol numeric,
 	uuidcol uuid,
-	lsncol pg_lsn
+	int4rangecol int4range,
+	lsncol pg_lsn,
+	boxcol box,
+	pointcol point
 ) WITH (fillfactor=10, autovacuum_enabled=off);
 
 INSERT INTO brintest SELECT
 	repeat(stringu1, 8)::bytea,
 	substr(stringu1, 1, 1)::"char",
 	stringu1::name, 142857 * tenthous,
 	thousand,
 	twothousand,
 	repeat(stringu1, 8),
 	unique1::oid,
@@ -44,55 +47,63 @@ INSERT INTO brintest SELECT
 	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+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
+	int4range(thousand, twothousand),
+	format('%s/%s%s', odd, even, tenthous)::pg_lsn,
+	box(point(odd, even), point(thousand, twothousand)),
+	point(thousand, twothousand)
 FROM tenk1 LIMIT 25;
 
 -- throw in some NULL's and different values
-INSERT INTO brintest (inetcol, cidrcol) SELECT
+INSERT INTO brintest (inetcol, cidrcol, int4rangecol) SELECT
 	inet 'fe80::6e40:8ff:fea9:8c46' + tenthous,
-	cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous
+	cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous,
+	'empty'::int4range
 FROM tenk1 LIMIT 25;
 
 CREATE INDEX brinidx ON brintest USING brin (
 	byteacol,
 	charcol,
 	namecol,
 	int8col,
 	int2col,
 	int4col,
 	textcol,
 	oidcol,
 	tidcol,
 	float4col,
 	float8col,
 	macaddrcol,
+	inetcol inet_inclusion_ops,
 	inetcol inet_minmax_ops,
 	bpcharcol,
 	datecol,
 	timecol,
 	timestampcol,
 	timestamptzcol,
 	intervalcol,
 	timetzcol,
 	bitcol,
 	varbitcol,
 	numericcol,
 	uuidcol,
-	lsncol
+	int4rangecol,
+	lsncol,
+	boxcol,
+	pointcol
 ) with (pages_per_range = 1);
 
 CREATE TABLE brinopers (colname name, typ text, op text[], value text[],
 	check (cardinality(op) = cardinality(value)));
 
 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}'),
@@ -126,21 +137,28 @@ INSERT INTO brinopers VALUES
 	('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}');
+	('int4rangecol', 'int4range', '{<<, &<, &&, &>, >>, @>, <@, =, <, <=, >, >=}', '{"[10000,)","[10000,)","(,]","[3,4)","[36,44)","(1500,1501]","[3,4)","[222,1222)","[36,44)","[43,1043)","[367,4466)","[519,)"}'),
+	('int4rangecol', 'int4range', '{@>, <@, =, <=, >, >=}', '{empty, empty, empty, empty, empty, empty}'),
+	('int4rangecol', 'int4', '{@>}', '{1500}'),
+	('lsncol', 'pg_lsn', '{>, >=, =, <=, <, IS, IS NOT}', '{0/1200, 0/1200, 44/455222, 198/1999799, 198/1999799, NULL, NULL}'),
+	('boxcol', 'point', '{<<, &<, &>, >>, <<|, &<|, |&>, |>>, @>}', '{"(1000,2000)","(3000,4000)","(1,2)","(3,4)","(3000,4000)","(3000,4000)","(1,2)","(1,2)","(500,43)"}'),
+	('boxcol', 'box', '{<<, &<, &&, &>, >>, <<|, &<|, |&>, |>>, @>, <@, ~=}', '{"((1000,2000),(3000,4000))","((1,2),(3000,4000))","((1,2),(3000,4000))","((1,2),(3000,4000))","((1,2),(3,4))","((1000,2000),(3000,4000))","((1,2000),(3,4000))","((1000,2),(3000,4))","((1,2),(3,4))","((1,2),(300,400))","((1,2),(3000,4000))","((222,1222),(44,45))"}'),
+	('pointcol', 'point', '{<<, >>, <^, >^, ~=}', '{"(3000,4000)","(3,4)","(5000,15000)","(1,2)","(222,1222)"}'),
+	('pointcol', 'box', '{<@}', '{"((0,0),(5000,5000))"}');
 
 DO $x$
 DECLARE
 	r record;
 	r2 record;
 	cond text;
 	count int;
 	mismatch bool;
 BEGIN
 	FOR r IN SELECT colname, oper, typ, value[ordinality] FROM brinopers, unnest(op) WITH ORDINALITY AS oper LOOP
@@ -222,17 +240,20 @@ INSERT INTO brintest SELECT
 	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',
 	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
+	int4range(thousand, twothousand),
+	format('%s/%s%s', odd, even, tenthous)::pg_lsn,
+	box(point(odd, even), point(thousand, twothousand)),
+	point(thousand, twothousand)
 FROM tenk1 LIMIT 5 OFFSET 5;
 
 SELECT brin_summarize_new_values('brinidx'::regclass);
 
 UPDATE brintest SET int8col = int8col * int4col;
 UPDATE brintest SET textcol = '' WHERE textcol IS NOT NULL;
-- 
2.3.2

