brin-inclusion-v03.patch

text/plain

Filename: brin-inclusion-v03.patch
Type: text/plain
Part: 0
Message: Re: BRIN range operator class

Patch

Format: unified
Series: patch v3
File+
doc/src/sgml/brin.sgml 71 1
doc/src/sgml/func.sgml 35 0
src/backend/access/brin/brin.c 0 58
src/backend/access/brin/brin_inclusion.c 631 0
src/backend/access/brin/brin_tuple.c 9 3
src/backend/access/brin/Makefile 1 1
src/backend/utils/adt/geo_ops.c 163 25
src/backend/utils/adt/network.c 52 0
src/backend/utils/adt/rangetypes.c 33 12
src/bin/initdb/initdb.c 1 0
src/include/access/brin_internal.h 6 0
src/include/access/gist.h 0 20
src/include/access/skey.h 34 0
src/include/catalog/pg_am.h 2 1
src/include/catalog/pg_amop.h 55 0
src/include/catalog/pg_amproc.h 31 0
src/include/catalog/pg_cast.h 1 0
src/include/catalog/pg_opclass.h 6 1
src/include/catalog/pg_operator.h 20 0
src/include/catalog/pg_opfamily.h 3 0
src/include/catalog/pg_proc.h 28 0
src/include/utils/builtins.h 2 0
src/include/utils/geo_decls.h 10 0
src/include/utils/rangetypes.h 1 0
src/test/regress/expected/brin.out 87 55
src/test/regress/expected/inet.out 28 0
src/test/regress/expected/opr_sanity.out 31 2
src/test/regress/expected/rangetypes.out 19 1
src/test/regress/sql/brin.sql 87 55
src/test/regress/sql/inet.sql 7 0
src/test/regress/sql/opr_sanity.sql 3 1
src/test/regress/sql/rangetypes.sql 5 1
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index 1ac282c..c8b8f62 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 the union of the values in the indexed column
+  withing 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/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index d57243a..4f0fb4c 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -8726,20 +8726,44 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
          <indexterm>
           <primary>text</primary>
          </indexterm>
          <literal><function>text(<type>inet</type>)</function></literal>
         </entry>
         <entry><type>text</type></entry>
         <entry>extract IP address and netmask length as text</entry>
         <entry><literal>text(inet '192.168.1.5')</literal></entry>
         <entry><literal>192.168.1.5/32</literal></entry>
        </row>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>inet_same_family</primary>
+         </indexterm>
+         <literal><function>inet_same_family(<type>inet</type>, <type>inet</type>)</function></literal>
+        </entry>
+        <entry><type>boolean</type></entry>
+        <entry>are the addresses from the same family?</entry>
+        <entry><literal>inet_same_family('192.168.1.5/24', '::1')</literal></entry>
+        <entry><literal>false</literal></entry>
+       </row>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>inet_merge</primary>
+         </indexterm>
+         <literal><function>inet_merge(<type>inet</type>, <type>inet</type>)</function></literal>
+        </entry>
+        <entry><type>cidr</type></entry>
+        <entry>the smallest network which includes both of the given networks</entry>
+        <entry><literal>inet_merge('192.168.1.5/24', '192.168.2.5/24')</literal></entry>
+        <entry><literal>192.168.0.0/22</literal></entry>
+       </row>
       </tbody>
      </tgroup>
     </table>
 
   <para>
    Any <type>cidr</> value can be cast to <type>inet</> implicitly
    or explicitly; therefore, the functions shown above as operating on
    <type>inet</> also work on <type>cidr</> values.  (Where there are
    separate functions for <type>inet</> and <type>cidr</>, it is because
    the behavior should be different for the two cases.)
@@ -12027,20 +12051,31 @@ NULL baz</literallayout>(3 rows)</entry>
         <entry>
          <literal>
           <function>upper_inf</function>(<type>anyrange</type>)
          </literal>
         </entry>
         <entry><type>boolean</type></entry>
         <entry>is the upper bound infinite?</entry>
         <entry><literal>upper_inf('(,)'::daterange)</literal></entry>
         <entry><literal>true</literal></entry>
        </row>
+       <row>
+        <entry>
+         <literal>
+          <function>range_merge</function>(<type>anyrange</type>, <type>anyrange</type>)
+         </literal>
+        </entry>
+        <entry><type>anyrange</type></entry>
+        <entry>the smallest range which includes both of the given ranges</entry>
+        <entry><literal>range_merge('[1,2)'::int4range, '[3,4)'::int4range)</literal></entry>
+        <entry><literal>[1,4)</literal></entry>
+       </row>
       </tbody>
      </tgroup>
     </table>
 
   <para>
    The <function>lower</> and  <function>upper</> functions return null
    if the range is empty or the requested bound is infinite.
    The <function>lower_inc</function>, <function>upper_inc</function>,
    <function>lower_inf</function>, and <function>upper_inf</function>
    functions all return false for an empty range.
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.c b/src/backend/access/brin/brin.c
index 2b5fb8d..a6dd4bf 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -98,25 +98,20 @@ brininsert(PG_FUNCTION_ARGS)
 	revmap = brinRevmapInitialize(idxRel, &pagesPerRange);
 
 	for (;;)
 	{
 		bool		need_insert = false;
 		OffsetNumber off;
 		BrinTuple  *brtup;
 		BrinMemTuple *dtup;
 		BlockNumber heapBlk;
 		int			keyno;
-#ifdef USE_ASSERT_CHECKING
-		BrinTuple  *tmptup;
-		BrinMemTuple *tmpdtup;
-		Size 		tmpsiz;
-#endif
 
 		CHECK_FOR_INTERRUPTS();
 
 		heapBlk = ItemPointerGetBlockNumber(heaptid);
 		/* normalize the block number to be the first block in the range */
 		heapBlk = (heapBlk / pagesPerRange) * pagesPerRange;
 		brtup = brinGetTupleForHeapBlock(revmap, heapBlk, &buf, &off, NULL,
 										 BUFFER_LOCK_SHARE);
 
 		/* if range is unsummarized, there's nothing to do */
@@ -130,59 +125,20 @@ brininsert(PG_FUNCTION_ARGS)
 			tupcxt = AllocSetContextCreate(CurrentMemoryContext,
 										   "brininsert cxt",
 										   ALLOCSET_DEFAULT_MINSIZE,
 										   ALLOCSET_DEFAULT_INITSIZE,
 										   ALLOCSET_DEFAULT_MAXSIZE);
 			oldcxt = MemoryContextSwitchTo(tupcxt);
 		}
 
 		dtup = brin_deform_tuple(bdesc, brtup);
 
-#ifdef USE_ASSERT_CHECKING
-		{
-			/*
-			 * When assertions are enabled, we use this as an opportunity to
-			 * test the "union" method, which would otherwise be used very
-			 * rarely: first create a placeholder tuple, and addValue the
-			 * value we just got into it.  Then union the existing index tuple
-			 * with the updated placeholder tuple.  The tuple resulting from
-			 * that union should be identical to the one resulting from the
-			 * regular operation (straight addValue) below.
-			 *
-			 * Here we create the tuple to compare with; the actual comparison
-			 * is below.
-			 */
-			tmptup = brin_form_placeholder_tuple(bdesc, heapBlk, &tmpsiz);
-			tmpdtup = brin_deform_tuple(bdesc, tmptup);
-			for (keyno = 0; keyno < bdesc->bd_tupdesc->natts; keyno++)
-			{
-				BrinValues *bval;
-				FmgrInfo   *addValue;
-
-				bval = &tmpdtup->bt_columns[keyno];
-				addValue = index_getprocinfo(idxRel, keyno + 1,
-											 BRIN_PROCNUM_ADDVALUE);
-				FunctionCall4Coll(addValue,
-								  idxRel->rd_indcollation[keyno],
-								  PointerGetDatum(bdesc),
-								  PointerGetDatum(bval),
-								  values[keyno],
-								  nulls[keyno]);
-			}
-
-			union_tuples(bdesc, tmpdtup, brtup);
-
-			tmpdtup->bt_placeholder = dtup->bt_placeholder;
-			tmptup = brin_form_tuple(bdesc, heapBlk, tmpdtup, &tmpsiz);
-		}
-#endif
-
 		/*
 		 * Compare the key values of the new tuple to the stored index values;
 		 * our deformed tuple will get updated if the new tuple doesn't fit
 		 * the original range (note this means we can't break out of the loop
 		 * early). Make a note of whether this happens, so that we know to
 		 * insert the modified tuple later.
 		 */
 		for (keyno = 0; keyno < bdesc->bd_tupdesc->natts; keyno++)
 		{
 			Datum		result;
@@ -195,34 +151,20 @@ brininsert(PG_FUNCTION_ARGS)
 			result = FunctionCall4Coll(addValue,
 									   idxRel->rd_indcollation[keyno],
 									   PointerGetDatum(bdesc),
 									   PointerGetDatum(bval),
 									   values[keyno],
 									   nulls[keyno]);
 			/* if that returned true, we need to insert the updated tuple */
 			need_insert |= DatumGetBool(result);
 		}
 
-#ifdef USE_ASSERT_CHECKING
-		{
-			/*
-			 * Now we can compare the tuple produced by the union function
-			 * with the one from plain addValue.
-			 */
-			BrinTuple  *cmptup;
-			Size		cmpsz;
-
-			cmptup = brin_form_tuple(bdesc, heapBlk, dtup, &cmpsz);
-			Assert(brin_tuples_equal(tmptup, tmpsiz, cmptup, cmpsz));
-		}
-#endif
-
 		if (!need_insert)
 		{
 			/*
 			 * The tuple is consistent with the new values, so there's nothing
 			 * to do.
 			 */
 			LockBuffer(buf, BUFFER_LOCK_UNLOCK);
 		}
 		else
 		{
diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c
new file mode 100644
index 0000000..d68db41
--- /dev/null
+++ b/src/backend/access/brin/brin_inclusion.c
@@ -0,0 +1,631 @@
+/*
+ * 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
+#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	procinfos[INCLUSION_MAX_PROCNUMS];
+	bool		exists[INCLUSION_MAX_PROCNUMS];
+	bool		inited[INCLUSION_MAX_PROCNUMS];
+	Oid			last_subtype;
+	Oid			last_strategynum;
+	FmgrInfo	last_strategy_procinfo;
+} 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;
+
+	/*
+	 * 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_typids[0] = typoid;	/* the union */
+	result->oi_typids[1] = BOOLOID;	/* includes elements that are not mergeable */
+	result->oi_typids[2] = BOOLOID;	/* includes empty element or not */
+
+	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 that 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 that 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 that 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 the 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 index_getstrategyprocinfo()
+		 * 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));
+
+		/*
+		 * 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:
+		case RTContainedByEqualStrategyNumber:
+			if (DatumGetBool(column->bv_values[2]))
+				PG_RETURN_BOOL(true);
+
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTOverlapStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_DATUM(result);
+
+		/*
+		 * 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 does 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 this strategies except the same strategy are not suitable
+		 * for the geometric types which uses 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:
+			if (DatumGetBool(column->bv_values[2]))
+				PG_RETURN_BOOL(true);
+
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTRightStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_BOOL(!DatumGetBool(result));
+
+		case RTSameStrategyNumber:
+		case RTEqualStrategyNumber:
+			if (DatumGetBool(column->bv_values[2]))
+				PG_RETURN_BOOL(true);
+
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTContainsStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_DATUM(result);
+
+		case RTGreaterEqualStrategyNumber:
+			if (DatumGetBool(column->bv_values[2]))
+				PG_RETURN_BOOL(true);
+
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   RTLeftStrategyNumber);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_BOOL(!DatumGetBool(result));
+
+		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));
+
+		/*
+		 * Other strategies
+		 *
+		 * By default, we will call the operator of the strategy.
+		 *
+		 * We assume that empty element will not change the result.  It is
+		 * true for the contains strategies which will be handled by
+		 * the default case as empty elements cannot contain anything but
+		 * is contained in everything.
+		 */
+
+		default:
+			frmg = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
+												   key->sk_strategy);
+			result = FunctionCall2Coll(frmg, colloid, column->bv_values[0],
+									   query);
+			PG_RETURN_DATUM(result);
+	}
+}
+
+/*
+ * 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 that B includes empty elements or not. */
+	if (!DatumGetBool(col_a->bv_values[2]) &&
+		DatumGetBool(col_b->bv_values[2]))
+		col_a->bv_values[2] = BoolGetDatum(true);
+
+	/* Check that A includes elements that are not mergeable. */
+	if (DatumGetBool(col_a->bv_values[1]))
+		PG_RETURN_VOID();
+
+	/* Check that 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 that 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();
+}
+
+/*
+ * Get 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->inited[basenum])
+	{
+		if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
+												procnum)))
+		{
+			fmgr_info_copy(&opaque->procinfos[basenum],
+						   index_getprocinfo(bdesc->bd_index, attno, procnum),
+						   bdesc->bd_context);
+
+			opaque->exists[basenum] = true;
+		}
+
+		opaque->inited[basenum] = true;
+	}
+
+	if (opaque->exists[basenum])
+		return &opaque->procinfos[basenum];
+	else
+		return NULL;
+}
+
+/*
+ * Get 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 as 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.  Some 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.
+ */
+FmgrInfo *
+inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype,
+								uint16 strategynum)
+{
+	InclusionOpaque *opaque;
+
+	opaque = (InclusionOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
+
+	/*
+	 * We cache the last procedure in the opaque struct, to avoid repetitive
+	 * syscache lookups.  It is enough to cache only the last one, because
+	 * none of the strategies need to lookup for the second one.
+	 */
+	if (opaque->last_subtype != subtype ||
+		opaque->last_strategynum != strategynum)
+	{
+		HeapTuple	tuple;
+		Datum		oprDatum;
+		Oid			opfamily;
+		Form_pg_attribute attr;
+		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 strategy %d for attribute %d of index \"%s\"",
+				 strategynum, attno, RelationGetRelationName(bdesc->bd_index));
+
+		oprDatum = SysCacheGetAttr(AMOPSTRATEGY, tuple,
+								   Anum_pg_amop_amopopr, &isNull);
+		ReleaseSysCache(tuple);
+
+		Assert(!isNull && RegProcedureIsValid(DatumGetObjectId(oprDatum)));
+
+		fmgr_info_cxt(get_opcode(DatumGetObjectId(oprDatum)),
+					  &opaque->last_strategy_procinfo, bdesc->bd_context);
+	}
+
+	return &opaque->last_strategy_procinfo;
+}
diff --git a/src/backend/access/brin/brin_tuple.c b/src/backend/access/brin/brin_tuple.c
index 93f00f6..be09c0f 100644
--- a/src/backend/access/brin/brin_tuple.c
+++ b/src/backend/access/brin/brin_tuple.c
@@ -30,20 +30,21 @@
  *	  src/backend/access/brin/brin_tuple.c
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "access/brin_tuple.h"
 #include "access/tupdesc.h"
 #include "access/tupmacs.h"
 #include "utils/datum.h"
 #include "utils/memutils.h"
+#include "utils/typcache.h"
 
 
 static inline void brin_deconstruct_tuple(BrinDesc *brdesc,
 					   char *tp, bits8 *nullbits, bool nulls,
 					   Datum *values, bool *allnulls, bool *hasnulls);
 
 
 /*
  * Return a tuple descriptor used for on-disk storage of BRIN tuples.
  */
@@ -423,36 +424,41 @@ brin_deform_tuple(BrinDesc *brdesc, BrinTuple *tuple)
 						   values, allnulls, hasnulls);
 
 	/*
 	 * Iterate to assign each of the values to the corresponding item in the
 	 * values array of each column.  The copies occur in the tuple's context.
 	 */
 	oldcxt = MemoryContextSwitchTo(dtup->bt_context);
 	for (valueno = 0, keyno = 0; keyno < brdesc->bd_tupdesc->natts; keyno++)
 	{
 		int			i;
+		TypeCacheEntry *typcache;
 
 		if (allnulls[keyno])
 		{
 			valueno += brdesc->bd_info[keyno]->oi_nstored;
 			continue;
 		}
 
 		/*
 		 * We would like to skip datumCopy'ing the values datum in some cases,
 		 * caller permitting ...
 		 */
 		for (i = 0; i < brdesc->bd_info[keyno]->oi_nstored; i++)
+		{
+			typcache = lookup_type_cache(brdesc->bd_info[keyno]->oi_typids[i],
+										 0);
+
 			dtup->bt_columns[keyno].bv_values[i] =
-				datumCopy(values[valueno++],
-						  brdesc->bd_tupdesc->attrs[keyno]->attbyval,
-						  brdesc->bd_tupdesc->attrs[keyno]->attlen);
+				datumCopy(values[valueno++], typcache->typbyval,
+						  typcache->typlen);
+		}
 
 		dtup->bt_columns[keyno].bv_hasnulls = hasnulls[keyno];
 		dtup->bt_columns[keyno].bv_allnulls = false;
 	}
 
 	MemoryContextSwitchTo(oldcxt);
 
 	pfree(values);
 	pfree(allnulls);
 	pfree(hasnulls);
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 6b6510e..6ff61ee 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -526,21 +526,21 @@ box_copy(BOX *box)
 	BOX		   *result = (BOX *) palloc(sizeof(BOX));
 
 	memcpy((char *) result, (char *) box, sizeof(BOX));
 
 	return result;
 }
 
 
 /*----------------------------------------------------------
  *	Relational operators for BOXes.
- *		<, >, <=, >=, and == are based on box area.
+ *		<, >, <=, >=, and = are based on box area.
  *---------------------------------------------------------*/
 
 /*		box_same		-		are two boxes identical?
  */
 Datum
 box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
@@ -767,20 +767,125 @@ Datum
 box_ge(PG_FUNCTION_ARGS)
 {
 	BOX		   *box1 = PG_GETARG_BOX_P(0);
 	BOX		   *box2 = PG_GETARG_BOX_P(1);
 
 	PG_RETURN_BOOL(FPge(box_ar(box1), box_ar(box2)));
 }
 
 
 /*----------------------------------------------------------
+ *	Relational operators for BOX vs Point
+ *---------------------------------------------------------*/
+
+/*		box_left_pt		-		is box strictly left of point?
+ */
+Datum
+box_left_pt(PG_FUNCTION_ARGS)
+{
+	BOX		   *box = PG_GETARG_BOX_P(0);
+	Point	   *pt = PG_GETARG_POINT_P(1);
+
+	PG_RETURN_BOOL(box->high.x < pt->x);
+}
+
+/*		box_overleft_pt	-		is the right edge of box at or left of point?
+ */
+Datum
+box_overleft_pt(PG_FUNCTION_ARGS)
+{
+	BOX		   *box = PG_GETARG_BOX_P(0);
+	Point	   *pt = PG_GETARG_POINT_P(1);
+
+	PG_RETURN_BOOL(box->low.x <= pt->x);
+}
+
+/*		box_right_pt	-		is box strictly right of point?
+ */
+Datum
+box_right_pt(PG_FUNCTION_ARGS)
+{
+	BOX		   *box = PG_GETARG_BOX_P(0);
+	Point	   *pt = PG_GETARG_POINT_P(1);
+
+	PG_RETURN_BOOL(box->low.x > pt->x);
+}
+
+/*		box_overright_pt -		is the left edge of box at or right of point?
+ */
+Datum
+box_overright_pt(PG_FUNCTION_ARGS)
+{
+	BOX		   *box = PG_GETARG_BOX_P(0);
+	Point	   *pt = PG_GETARG_POINT_P(1);
+
+	PG_RETURN_BOOL(box->high.x >= pt->x);
+}
+
+/*		box_below_pt	-		is box strictly below point?
+ */
+Datum
+box_below_pt(PG_FUNCTION_ARGS)
+{
+	BOX		   *box = PG_GETARG_BOX_P(0);
+	Point	   *pt = PG_GETARG_POINT_P(1);
+
+	PG_RETURN_BOOL(box->high.y < pt->y);
+}
+
+/*		box_overbelow_pt -		is the upper edge of box at or below point?
+ */
+Datum
+box_overbelow_pt(PG_FUNCTION_ARGS)
+{
+	BOX		   *box = PG_GETARG_BOX_P(0);
+	Point	   *pt = PG_GETARG_POINT_P(1);
+
+	PG_RETURN_BOOL(box->low.y <= pt->y);
+}
+
+/*		box_above_pt	-		is box strictly above point?
+ */
+Datum
+box_above_pt(PG_FUNCTION_ARGS)
+{
+	BOX		   *box = PG_GETARG_BOX_P(0);
+	Point	   *pt = PG_GETARG_POINT_P(1);
+
+	PG_RETURN_BOOL(box->low.y > pt->y);
+}
+
+/*		box_overabove_pt -		is the lower edge of box at or above point?
+ */
+Datum
+box_overabove_pt(PG_FUNCTION_ARGS)
+{
+	BOX		   *box = PG_GETARG_BOX_P(0);
+	Point	   *pt = PG_GETARG_POINT_P(1);
+
+	PG_RETURN_BOOL(box->high.y >= pt->y);
+}
+
+/*		box_contain_pt	-		does box contain point?
+ */
+Datum
+box_contain_pt(PG_FUNCTION_ARGS)
+{
+	BOX		   *box = PG_GETARG_BOX_P(0);
+	Point	   *pt = PG_GETARG_POINT_P(1);
+
+	PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x &&
+				   pt->y <= box->high.y && pt->y >= box->low.y);
+}
+
+
+/*----------------------------------------------------------
  *	"Arithmetic" operators on boxes.
  *---------------------------------------------------------*/
 
 /*		box_area		-		returns the area of the box.
  */
 Datum
 box_area(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 
@@ -904,20 +1009,41 @@ box_intersect(PG_FUNCTION_ARGS)
 	result = (BOX *) palloc(sizeof(BOX));
 
 	result->high.x = Min(box1->high.x, box2->high.x);
 	result->low.x = Max(box1->low.x, box2->low.x);
 	result->high.y = Min(box1->high.y, box2->high.y);
 	result->low.y = Max(box1->low.y, box2->low.y);
 
 	PG_RETURN_BOX_P(result);
 }
 
+/*		boxes_bound_box -
+ *				returns the smallest bounding box that
+ *				  includes both of the given boxes.
+ */
+Datum
+boxes_bound_box(PG_FUNCTION_ARGS)
+{
+	BOX		   *box1 = PG_GETARG_BOX_P(0),
+			   *box2 = PG_GETARG_BOX_P(1),
+			   *container;
+
+	container = (BOX *) palloc(sizeof(BOX));
+
+	container->high.x = Max(box1->high.x, box2->high.x);
+	container->low.x = Min(box1->low.x, box2->low.x);
+	container->high.y = Max(box1->high.y, box2->high.y);
+	container->low.y = Min(box1->low.y, box2->low.y);
+
+	PG_RETURN_BOX_P(container);
+}
+
 
 /*		box_diagonal	-
  *				returns a line segment which happens to be the
  *				  positive-slope diagonal of "box".
  */
 Datum
 box_diagonal(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	LSEG	   *result = (LSEG *) palloc(sizeof(LSEG));
@@ -3205,30 +3331,20 @@ on_ps_internal(Point *pt, LSEG *lseg)
 Datum
 on_pb(PG_FUNCTION_ARGS)
 {
 	Point	   *pt = PG_GETARG_POINT_P(0);
 	BOX		   *box = PG_GETARG_BOX_P(1);
 
 	PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x &&
 				   pt->y <= box->high.y && pt->y >= box->low.y);
 }
 
-Datum
-box_contain_pt(PG_FUNCTION_ARGS)
-{
-	BOX		   *box = PG_GETARG_BOX_P(0);
-	Point	   *pt = PG_GETARG_POINT_P(1);
-
-	PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x &&
-				   pt->y <= box->high.y && pt->y >= box->low.y);
-}
-
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
  *		If closed, we use the old O(n) ray method for point-in-polygon.
  *				The ray is horizontal, from pt out to the right.
  *				Each segment that crosses the ray counts as an
  *				intersection; note that an endpoint or edge may touch
  *				but not cross.
  *				(we can do p-in-p in lg(n), but it takes preprocessing)
@@ -4666,24 +4782,42 @@ circle_send(PG_FUNCTION_ARGS)
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
 	pq_sendfloat8(&buf, circle->center.x);
 	pq_sendfloat8(&buf, circle->center.y);
 	pq_sendfloat8(&buf, circle->radius);
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
+/*		cr_circle		- make circle from point of center and distance
+ */
+Datum
+cr_circle(PG_FUNCTION_ARGS)
+{
+	Point	   *center = PG_GETARG_POINT_P(0);
+	float8		radius = PG_GETARG_FLOAT8(1);
+	CIRCLE	   *result;
+
+	result = (CIRCLE *) palloc(sizeof(CIRCLE));
+
+	result->center.x = center->x;
+	result->center.y = center->y;
+	result->radius = radius;
+
+	PG_RETURN_CIRCLE_P(result);
+}
+
 
 /*----------------------------------------------------------
  *	Relational operators for CIRCLEs.
- *		<, >, <=, >=, and == are based on circle area.
+ *		<, >, <=, >=, and = are based on circle area.
  *---------------------------------------------------------*/
 
 /*		circles identical?
  */
 Datum
 circle_same(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle1 = PG_GETARG_CIRCLE_P(0);
 	CIRCLE	   *circle2 = PG_GETARG_CIRCLE_P(1);
 
@@ -5093,78 +5227,82 @@ circle_center(PG_FUNCTION_ARGS)
 /*		circle_ar		-		returns the area of the circle.
  */
 static double
 circle_ar(CIRCLE *circle)
 {
 	return M_PI * (circle->radius * circle->radius);
 }
 
 
 /*----------------------------------------------------------
- *	Conversion operators.
+ *	Type conversions
  *---------------------------------------------------------*/
 
+/*		point_box		- convert point to empty box
+ */
 Datum
-cr_circle(PG_FUNCTION_ARGS)
+point_box(PG_FUNCTION_ARGS)
 {
-	Point	   *center = PG_GETARG_POINT_P(0);
-	float8		radius = PG_GETARG_FLOAT8(1);
-	CIRCLE	   *result;
+	Point	   *pt = PG_GETARG_POINT_P(0);
+	BOX		   *box;
 
-	result = (CIRCLE *) palloc(sizeof(CIRCLE));
+	box = (BOX *) palloc(sizeof(BOX));
 
-	result->center.x = center->x;
-	result->center.y = center->y;
-	result->radius = radius;
+	box->high.x = pt->x;
+	box->low.x = pt->x;
+	box->high.y = pt->y;
+	box->low.y = pt->y;
 
-	PG_RETURN_CIRCLE_P(result);
+	PG_RETURN_BOX_P(box);
 }
 
+/*		circle_box		- convert circle to box
+ */
 Datum
 circle_box(PG_FUNCTION_ARGS)
 {
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(0);
 	BOX		   *box;
 	double		delta;
 
 	box = (BOX *) palloc(sizeof(BOX));
 
 	delta = circle->radius / sqrt(2.0);
 
 	box->high.x = circle->center.x + delta;
 	box->low.x = circle->center.x - delta;
 	box->high.y = circle->center.y + delta;
 	box->low.y = circle->center.y - delta;
 
 	PG_RETURN_BOX_P(box);
 }
 
-/* box_circle()
- * Convert a box to a circle.
+/*		box_circle		- convert box to circle
  */
 Datum
 box_circle(PG_FUNCTION_ARGS)
 {
 	BOX		   *box = PG_GETARG_BOX_P(0);
 	CIRCLE	   *circle;
 
 	circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 
 	circle->center.x = (box->high.x + box->low.x) / 2;
 	circle->center.y = (box->high.y + box->low.y) / 2;
 
 	circle->radius = point_dt(&circle->center, &box->high);
 
 	PG_RETURN_CIRCLE_P(circle);
 }
 
-
+/*		circle_poly		- convert circle to polygon
+ */
 Datum
 circle_poly(PG_FUNCTION_ARGS)
 {
 	int32		npts = PG_GETARG_INT32(0);
 	CIRCLE	   *circle = PG_GETARG_CIRCLE_P(1);
 	POLYGON    *poly;
 	int			base_size,
 				size;
 	int			i;
 	double		angle;
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index 3a705da..fa9efcd 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -881,20 +881,72 @@ network_hostmask(PG_FUNCTION_ARGS)
 	}
 
 	ip_family(dst) = ip_family(ip);
 	ip_bits(dst) = ip_maxbits(ip);
 	SET_INET_VARSIZE(dst);
 
 	PG_RETURN_INET_P(dst);
 }
 
 /*
+ * Returns true if the addresses are from the same family, or false.  Used to
+ * determine the addresses have a common union or not.
+ */
+Datum
+inet_same_family(PG_FUNCTION_ARGS)
+{
+	inet	   *a1 = PG_GETARG_INET_PP(0);
+	inet	   *a2 = PG_GETARG_INET_PP(1);
+
+	PG_RETURN_BOOL(ip_family(a1) == ip_family(a2));
+}
+
+/*
+ * Returns the smallest CIDR which contains both of the inputs.
+ */
+Datum
+inet_merge(PG_FUNCTION_ARGS)
+{
+	inet	   *a1 = PG_GETARG_INET_PP(0),
+			   *a2 = PG_GETARG_INET_PP(1),
+			   *result;
+	int			commonbits;
+
+	if (ip_family(a1) != ip_family(a2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("cannot merge addresses from different families")));
+
+	commonbits = bitncommon(ip_addr(a1), ip_addr(a2),
+							Min(ip_bits(a1), ip_bits(a2)));
+
+	/* Make sure any unused bits are zeroed. */
+	result = (inet *) palloc0(sizeof(inet));
+
+	ip_family(result) = ip_family(a1);
+	ip_bits(result) = commonbits;
+
+	/* Clone appropriate bytes of the address. */
+	if (commonbits > 0)
+		memcpy(ip_addr(result), ip_addr(a1), (commonbits + 7) / 8);
+
+	/* Clean any unwanted bits in the last partial byte. */
+	if (commonbits % 8 != 0)
+		ip_addr(result)[commonbits / 8] &= ~(0xFF >> (commonbits % 8));
+
+	/* Set varlena header correctly. */
+	SET_INET_VARSIZE(result);
+
+	PG_RETURN_INET_P(result);
+}
+
+/*
  * Convert a value of a network datatype to an approximate scalar value.
  * This is used for estimating selectivities of inequality operators
  * involving network types.
  */
 double
 convert_network_to_scalar(Datum value, Oid typid)
 {
 	switch (typid)
 	{
 		case INETOID:
diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c
index c037b05..5f052ee 100644
--- a/src/backend/utils/adt/rangetypes.c
+++ b/src/backend/utils/adt/rangetypes.c
@@ -1000,67 +1000,88 @@ range_minus(PG_FUNCTION_ARGS)
 		upper2.inclusive = !upper2.inclusive;
 		upper2.lower = true;	/* it will become the lower bound */
 		PG_RETURN_RANGE(make_range(typcache, &upper2, &upper1, false));
 	}
 
 	elog(ERROR, "unexpected case in range_minus");
 	PG_RETURN_NULL();
 }
 
 /* set union */
-Datum
-range_union(PG_FUNCTION_ARGS)
+static RangeType *
+range_union_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2,
+					 bool strict)
 {
-	RangeType  *r1 = PG_GETARG_RANGE(0);
-	RangeType  *r2 = PG_GETARG_RANGE(1);
-	TypeCacheEntry *typcache;
 	RangeBound	lower1,
 				lower2;
 	RangeBound	upper1,
 				upper2;
 	bool		empty1,
 				empty2;
 	RangeBound *result_lower;
 	RangeBound *result_upper;
 
 	/* Different types should be prevented by ANYRANGE matching rules */
 	if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
 		elog(ERROR, "range types do not match");
 
-	typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
-
 	range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
 	range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
 
 	/* if either is empty, the other is the correct answer */
 	if (empty1)
-		PG_RETURN_RANGE(r2);
+		return r2;
 	if (empty2)
-		PG_RETURN_RANGE(r1);
+		return r1;
 
-	if (!DatumGetBool(range_overlaps(fcinfo)) &&
-		!DatumGetBool(range_adjacent(fcinfo)))
+	if (strict &&
+		!DatumGetBool(range_overlaps_internal(typcache, r1, r2)) &&
+		!DatumGetBool(range_adjacent_internal(typcache, r1, r2)))
 		ereport(ERROR,
 				(errcode(ERRCODE_DATA_EXCEPTION),
 				 errmsg("result of range union would not be contiguous")));
 
 	if (range_cmp_bounds(typcache, &lower1, &lower2) < 0)
 		result_lower = &lower1;
 	else
 		result_lower = &lower2;
 
 	if (range_cmp_bounds(typcache, &upper1, &upper2) > 0)
 		result_upper = &upper1;
 	else
 		result_upper = &upper2;
 
-	PG_RETURN_RANGE(make_range(typcache, result_lower, result_upper, false));
+	return make_range(typcache, result_lower, result_upper, false);
+}
+
+Datum
+range_union(PG_FUNCTION_ARGS)
+{
+	RangeType  *r1 = PG_GETARG_RANGE(0);
+	RangeType  *r2 = PG_GETARG_RANGE(1);
+	TypeCacheEntry *typcache;
+
+	typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+	PG_RETURN_RANGE(range_union_internal(typcache, r1, r2, true));
+}
+
+Datum
+range_merge(PG_FUNCTION_ARGS)
+{
+	RangeType  *r1 = PG_GETARG_RANGE(0);
+	RangeType  *r2 = PG_GETARG_RANGE(1);
+	TypeCacheEntry *typcache;
+
+	typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+	PG_RETURN_RANGE(range_union_internal(typcache, r1, r2, false));
 }
 
 /* set intersection */
 Datum
 range_intersect(PG_FUNCTION_ARGS)
 {
 	RangeType  *r1 = PG_GETARG_RANGE(0);
 	RangeType  *r2 = PG_GETARG_RANGE(1);
 	TypeCacheEntry *typcache;
 	RangeBound	lower1,
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 18614e7..a21c3fa 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1884,20 +1884,21 @@ setup_description(void)
 	/* Create default descriptions for operator implementation functions */
 	PG_CMD_PUTS("WITH funcdescs AS ( "
 				"SELECT p.oid as p_oid, oprname, "
 			  "coalesce(obj_description(o.oid, 'pg_operator'),'') as opdesc "
 				"FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) "
 				"INSERT INTO pg_description "
 				"  SELECT p_oid, 'pg_proc'::regclass, 0, "
 				"    'implementation of ' || oprname || ' operator' "
 				"  FROM funcdescs "
 				"  WHERE opdesc NOT LIKE 'deprecated%' AND "
+				"  opdesc NOT LIKE 'same as %' AND "
 				"  NOT EXISTS (SELECT 1 FROM pg_description "
 		  "    WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass);\n");
 
 	PG_CMD_CLOSE;
 
 	check_ok();
 }
 
 #ifdef HAVE_LOCALE_T
 /*
diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h
index 84eed61..9dca259 100644
--- a/src/include/access/brin_internal.h
+++ b/src/include/access/brin_internal.h
@@ -84,11 +84,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/access/gist.h b/src/include/access/gist.h
index 01f0a70..dd773c1 100644
--- a/src/include/access/gist.h
+++ b/src/include/access/gist.h
@@ -29,40 +29,20 @@
 #define GIST_UNION_PROC					2
 #define GIST_COMPRESS_PROC				3
 #define GIST_DECOMPRESS_PROC			4
 #define GIST_PENALTY_PROC				5
 #define GIST_PICKSPLIT_PROC				6
 #define GIST_EQUAL_PROC					7
 #define GIST_DISTANCE_PROC				8
 #define GISTNProcs						8
 
 /*
- * strategy numbers for GiST opclasses that want to implement the old
- * RTREE behavior.
- */
-#define RTLeftStrategyNumber			1
-#define RTOverLeftStrategyNumber		2
-#define RTOverlapStrategyNumber			3
-#define RTOverRightStrategyNumber		4
-#define RTRightStrategyNumber			5
-#define RTSameStrategyNumber			6
-#define RTContainsStrategyNumber		7		/* for @> */
-#define RTContainedByStrategyNumber		8		/* for <@ */
-#define RTOverBelowStrategyNumber		9
-#define RTBelowStrategyNumber			10
-#define RTAboveStrategyNumber			11
-#define RTOverAboveStrategyNumber		12
-#define RTOldContainsStrategyNumber		13		/* for old spelling of @> */
-#define RTOldContainedByStrategyNumber	14		/* for old spelling of <@ */
-#define RTKNNSearchStrategyNumber		15
-
-/*
  * Page opaque data in a GiST index page.
  */
 #define F_LEAF				(1 << 0)	/* leaf page */
 #define F_DELETED			(1 << 1)	/* the page has been deleted */
 #define F_TUPLES_DELETED	(1 << 2)	/* some tuples on the page are dead */
 #define F_FOLLOW_RIGHT		(1 << 3)	/* page to the right has no downlink */
 
 typedef XLogRecPtr GistNSN;
 
 /*
diff --git a/src/include/access/skey.h b/src/include/access/skey.h
index eeee1f4..c5ac298 100644
--- a/src/include/access/skey.h
+++ b/src/include/access/skey.h
@@ -34,20 +34,54 @@ typedef uint16 StrategyNumber;
 #define BTLessStrategyNumber			1
 #define BTLessEqualStrategyNumber		2
 #define BTEqualStrategyNumber			3
 #define BTGreaterEqualStrategyNumber	4
 #define BTGreaterStrategyNumber			5
 
 #define BTMaxStrategyNumber				5
 
 
 /*
+ * Strategy numbers for opclasses that want to implement the old RTREE behavior.
+ * Operator strategy numbers used in the GiST, SP-GiST, GIN, BRIN  opclasses.
+ * New numbers are chosen to match up operator names with existing usages.
+ */
+#define RTLeftStrategyNumber			1		/* for << */
+#define RTOverLeftStrategyNumber		2		/* for &< */
+#define RTOverlapStrategyNumber			3		/* for && */
+#define RTOverRightStrategyNumber		4		/* for &> */
+#define RTRightStrategyNumber			5		/* for >> */
+#define RTSameStrategyNumber			6		/* for ~= */
+#define RTContainsStrategyNumber		7		/* for @> */
+#define RTContainedByStrategyNumber		8		/* for <@ */
+#define RTOverBelowStrategyNumber		9		/* for &<| */
+#define RTBelowStrategyNumber			10		/* for <<| */
+#define RTAboveStrategyNumber			11		/* for |>> */
+#define RTOverAboveStrategyNumber		12		/* for |&> */
+#define RTOldContainsStrategyNumber		13		/* for old spelling of @> */
+#define RTOldContainedByStrategyNumber	14		/* for old spelling of <@ */
+#define RTKNNSearchStrategyNumber		15
+#define RTContainsElemStrategyNumber	16		/* for range types @> elem */
+#define RTAdjacentStrategyNumber		17		/* for -|- */
+#define RTEqualStrategyNumber			18		/* for = */
+#define RTNotEqualStrategyNumber		19		/* for != */
+#define RTLessStrategyNumber			20		/* for < */
+#define RTLessEqualStrategyNumber		21		/* for <= */
+#define RTGreaterStrategyNumber			22		/* for > */
+#define RTGreaterEqualStrategyNumber	23		/* for >= */
+#define RTContainsNotEqualStrategyNumber	24	/* for inet >> */
+#define RTContainsEqualStrategyNumber	25		/* for inet >>= */
+#define RTContainedByNotEqualStrategyNumber	26	/* for inet << */
+#define RTContainedByEqualStrategyNumber	27	/* for inet <<= */
+
+
+/*
  * A ScanKey represents the application of a comparison operator between
  * a table or index column and a constant.  When it's part of an array of
  * ScanKeys, the comparison conditions are implicitly ANDed.  The index
  * column is the left argument of the operator, if it's a binary operator.
  * (The data structure can support unary indexable operators too; in that
  * case sk_argument would go unused.  This is not currently implemented.)
  *
  * For an index scan, sk_strategy and sk_subtype must be set correctly for
  * the operator.  When using a ScanKey in a heap scan, these fields are not
  * used and may be set to InvalidStrategy/InvalidOid.
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index 0531222..4d8007e 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 8 f t f f t t f t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup - gistcostestimate gistoptions ));
 DESCR("GiST index access method");
 #define GIST_AM_OID 783
 DATA(insert OID = 2742 (  gin		0 6 f f f f t t f f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbuildempty ginbulkdelete ginvacuumcleanup - gincostestimate ginoptions ));
 DESCR("GIN index access method");
 #define GIN_AM_OID 2742
 DATA(insert OID = 4000 (  spgist	0 5 f f f f f t f t f f f 0 spginsert spgbeginscan spggettuple spggetbitmap spgrescan spgendscan spgmarkpos spgrestrpos spgbuild spgbuildempty spgbulkdelete spgvacuumcleanup spgcanreturn spgcostestimate spgoptions ));
 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..d3a6360 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 (   4060    869  869  3 s     3552    3580 0 ));
+DATA(insert (   4060    869  869 18 s     1201    3580 0 ));
+DATA(insert (   4060    869  869 24 s      933    3580 0 ));
+DATA(insert (   4060    869  869 25 s      934    3580 0 ));
+DATA(insert (   4060    869  869 26 s      931    3580 0 ));
+DATA(insert (   4060    869  869 27 s      932    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,66 @@ 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 (   4063   3831 3831  1 s     3893    3580 0 ));
+DATA(insert (   4063   3831 3831  2 s     3895    3580 0 ));
+DATA(insert (   4063   3831 3831  3 s     3888    3580 0 ));
+DATA(insert (   4063   3831 3831  4 s     3896    3580 0 ));
+DATA(insert (   4063   3831 3831  5 s     3894    3580 0 ));
+DATA(insert (   4063   3831 3831  7 s     3890    3580 0 ));
+DATA(insert (   4063   3831 3831  8 s     3892    3580 0 ));
+DATA(insert (   4063   3831 2283 16 s     3889    3580 0 ));
+DATA(insert (   4063   3831 3831 17 s     3897    3580 0 ));
+DATA(insert (   4063   3831 3831 18 s     3882    3580 0 ));
+DATA(insert (   4063   3831 3831 20 s     3884    3580 0 ));
+DATA(insert (   4063   3831 3831 21 s     3885    3580 0 ));
+DATA(insert (   4063   3831 3831 22 s     3887    3580 0 ));
+DATA(insert (   4063   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 (	4066    603	 603  1 s	   493	  3580 0 ));
+DATA(insert (	4066    603  603  2 s	   494	  3580 0 ));
+DATA(insert (	4066    603  603  3 s	   500	  3580 0 ));
+DATA(insert (	4066    603  603  4 s	   495	  3580 0 ));
+DATA(insert (	4066    603  603  5 s	   496	  3580 0 ));
+DATA(insert (	4066    603  603  6 s	   499	  3580 0 ));
+DATA(insert (	4066    603  603  7 s	   498	  3580 0 ));
+DATA(insert (	4066    603  603  8 s	   497	  3580 0 ));
+DATA(insert (	4066    603  603  9 s	  2571	  3580 0 ));
+DATA(insert (	4066    603  603 10 s 	  2570	  3580 0 ));
+DATA(insert (	4066    603  603 11 s 	  2573	  3580 0 ));
+DATA(insert (	4066    603  603 12 s 	  2572	  3580 0 ));
+DATA(insert (	4066    603  603 13 s 	  2863	  3580 0 ));
+DATA(insert (	4066    603  603 14 s 	  2862	  3580 0 ));
+DATA(insert (	4066    603  600  1 s	  4092	  3580 0 ));
+DATA(insert (	4066    603  600  2 s	  4093	  3580 0 ));
+DATA(insert (	4066    603  600  3 s	  4100	  3580 0 ));
+DATA(insert (	4066    603  600  4 s	  4095	  3580 0 ));
+DATA(insert (	4066    603  600  5 s	  4094	  3580 0 ));
+DATA(insert (	4066    603  600  7 s	   433	  3580 0 ));
+DATA(insert (	4066    603  600  9 s	  4097	  3580 0 ));
+DATA(insert (	4066    603  600 10 s	  4096	  3580 0 ));
+DATA(insert (	4066    603  600 11 s	  4098	  3580 0 ));
+DATA(insert (	4066    603  600 12 s	  4099	  3580 0 ));
+/* inclusion point */
+DATA(insert (	4066    600  600  1 s	   507	  3580 0 ));
+DATA(insert (	4066    600  600  5 s	   508	  3580 0 ));
+DATA(insert (	4066    600  600  6 s	   510	  3580 0 ));
+DATA(insert (	4066    600  600 10 s 	   509	  3580 0 ));
+DATA(insert (	4066    600  600 11 s 	   506	  3580 0 ));
+DATA(insert (	4066    600  603  3 s	  4101	  3580 0 ));
+DATA(insert (	4066    600  603  8 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 49d3d13..5e557e5 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -629,20 +629,28 @@ 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 ));
+/* inclusion inet */
+DATA(insert (   4060   869   869  1  3387 ));
+DATA(insert (   4060   869   869  2  3388 ));
+DATA(insert (   4060   869   869  3  3389 ));
+DATA(insert (   4060   869   869  4  3390 ));
+DATA(insert (   4060   869   869 11  4061 ));
+DATA(insert (   4060   869   869 12  4071 ));
+DATA(insert (   4060   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 ));
 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 */
@@ -777,21 +785,44 @@ 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 ));
+/* inclusion range types */
+DATA(insert (   4063  3831  3831  1  3387 ));
+DATA(insert (   4063  3831  3831  2  3388 ));
+DATA(insert (   4063  3831  3831  3  3389 ));
+DATA(insert (   4063  3831  3831  4  3390 ));
+DATA(insert (   4063  3831  3831  11 4057 ));
+DATA(insert (   4063  3831  3831  14 3859 ));
+DATA(insert (   4063  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 ));
 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 ));
+/* inclusion box */
+DATA(insert (   4066   603   603  1  3387 ));
+DATA(insert (   4066   603   603  2  3388 ));
+DATA(insert (   4066   603   603  3  3389 ));
+DATA(insert (   4066   603   603  4  3390 ));
+DATA(insert (   4066   603   603  11 4067 ));
+DATA(insert (   4066   603   603  14  187 ));
+/* inclusion point */
+DATA(insert (   4066   600   600  1  3387 ));
+DATA(insert (   4066   600   600  2  3388 ));
+DATA(insert (   4066   600   600  3  3389 ));
+DATA(insert (   4066   600   600  4  3390 ));
+DATA(insert (   4066   600   600  11 4067 ));
+DATA(insert (   4066   600   600  13 4091 ));
+DATA(insert (   4066   600   600  14  193 ));
 
 #endif   /* PG_AMPROC_H */
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index b314369..6d54c15 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -266,20 +266,21 @@ DATA(insert ( 1186 1083 1419 a f ));
 DATA(insert ( 1266 1083 2046 a f ));
 /* Cross-category casts between int4 and abstime, reltime */
 DATA(insert (	23	702    0 e b ));
 DATA(insert (  702	 23    0 e b ));
 DATA(insert (	23	703    0 e b ));
 DATA(insert (  703	 23    0 e b ));
 
 /*
  * Geometric category
  */
+DATA(insert (  600	603 4091 a f ));
 DATA(insert (  601	600 1532 e f ));
 DATA(insert (  602	600 1533 e f ));
 DATA(insert (  602	604 1449 a f ));
 DATA(insert (  603	600 1534 e f ));
 DATA(insert (  603	601 1541 e f ));
 DATA(insert (  603	604 1448 a f ));
 DATA(insert (  603	718 1479 e f ));
 DATA(insert (  604	600 1540 e f ));
 DATA(insert (  604	602 1447 a f ));
 DATA(insert (  604	603 1446 e f ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index b3acef6..b3b2a91 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 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	inet_inclusion_ops		PGNSP PGUID 4060   869 t 869 ));
 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 ));
 /* no brin opclass for record, anyarray */
 DATA(insert (	3580	uuid_minmax_ops			PGNSP PGUID 4081  2950 t 0 ));
+DATA(insert (	3580	range_inclusion_ops		PGNSP PGUID 4063  3831 t 3831 ));
 DATA(insert (	3580	pg_lsn_minmax_ops		PGNSP PGUID 4082  3220 t 0 ));
-/* 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 4066   603 t 0 ));
+DATA(insert (	3580	point_box_inclusion_ops	PGNSP PGUID 4066   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_operator.h b/src/include/catalog/pg_operator.h
index af991d3..f7fdbb2 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -251,22 +251,42 @@ DESCR("is above");
 DATA(insert OID = 507 (  "<<"	   PGNSP PGUID b f f 600 600	16	 0	 0 point_left positionsel positionjoinsel ));
 DESCR("is left of");
 DATA(insert OID = 508 (  ">>"	   PGNSP PGUID b f f 600 600	16	 0	 0 point_right positionsel positionjoinsel ));
 DESCR("is right of");
 DATA(insert OID = 509 (  "<^"	   PGNSP PGUID b f f 600 600	16	 0	 0 point_below positionsel positionjoinsel ));
 DESCR("is below");
 DATA(insert OID = 510 (  "~="	   PGNSP PGUID b f f 600 600	16 510 713 point_eq eqsel eqjoinsel ));
 DESCR("same as");
 DATA(insert OID = 511 (  "<@"	   PGNSP PGUID b f f 600 603	16 433	 0 on_pb contsel contjoinsel ));
 DESCR("point inside box");
+DATA(insert OID = 4092 ( "<<"	   PGNSP PGUID b f f 603 600	16	 0	 0 box_left_pt positionsel positionjoinsel ));
+DESCR("is left of");
+DATA(insert OID = 4093 ( "&<"	   PGNSP PGUID b f f 603 600	16	 0	 0 box_overleft_pt positionsel positionjoinsel ));
+DESCR("overlaps or is left of");
+DATA(insert OID = 4094 ( ">>"	   PGNSP PGUID b f f 603 600	16	 0	 0 box_right_pt positionsel positionjoinsel ));
+DESCR("is right of");
+DATA(insert OID = 4095 ( "&>"	   PGNSP PGUID b f f 603 600	16	 0	 0 box_overright_pt positionsel positionjoinsel ));
+DESCR("overlaps or is right of");
+DATA(insert OID = 4096 ( "<<|"	   PGNSP PGUID b f f 603 600	16	 0	 0 box_below_pt positionsel positionjoinsel ));
+DESCR("is below");
+DATA(insert OID = 4097 ( "&<|"	   PGNSP PGUID b f f 603 600	16	 0	 0 box_overbelow_pt positionsel positionjoinsel ));
+DESCR("overlaps or is below");
+DATA(insert OID = 4098 ( "|>>"	   PGNSP PGUID b f f 603 600	16	 0	 0 box_above_pt positionsel positionjoinsel ));
+DESCR("is above");
+DATA(insert OID = 4099 ( "|&>"	   PGNSP PGUID b f f 603 600	16	 0	 0 box_overabove_pt positionsel positionjoinsel ));
+DESCR("overlaps or is above");
 DATA(insert OID = 433 (  "@>"	   PGNSP PGUID b f f 603 600	16 511	 0 box_contain_pt contsel contjoinsel ));
 DESCR("contains");
+DATA(insert OID = 4100 ( "&&"	   PGNSP PGUID b f f 603 600	16 4101	 0 box_contain_pt contsel contjoinsel ));
+DESCR("same as @>");
+DATA(insert OID = 4101 ( "&&"	   PGNSP PGUID b f f 600 603	16 4100	 0 on_pb contsel contjoinsel ));
+DESCR("same as <@");
 DATA(insert OID = 512 (  "<@"	   PGNSP PGUID b f f 600 602	16 755	 0 on_ppath - - ));
 DESCR("point within closed path, or point on open path");
 DATA(insert OID = 513 (  "@@"	   PGNSP PGUID l f f	 0 603 600	 0	 0 box_center - - ));
 DESCR("center of");
 DATA(insert OID = 514 (  "*"	   PGNSP PGUID b f f	23	23	23 514	 0 int4mul - - ));
 DESCR("multiply");
 DATA(insert OID = 517 (  "<->"	   PGNSP PGUID b f f 600 600 701 517	 0 point_distance - - ));
 DESCR("distance between");
 DATA(insert OID = 518 (  "<>"	   PGNSP PGUID b f f	23	23	16 518	96 int4ne neqsel neqjoinsel ));
 DESCR("not equal");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index 97ffa32..7d0eb8b 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 = 4060 (	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 = 4063 (	3580	range_inclusion_ops		PGNSP PGUID ));
 DATA(insert OID = 4082 (	3580	pg_lsn_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4066 (	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 9edfdb8..c6f33c3 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -334,20 +334,28 @@ DATA(insert OID = 182 (  int24mi		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23
 DATA(insert OID = 183 (  int42mi		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "23 21" _null_ _null_ _null_ _null_ int42mi _null_ _null_ _null_ ));
 DATA(insert OID = 184 (  oideq			   PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "26 26" _null_ _null_ _null_ _null_ oideq _null_ _null_ _null_ ));
 DATA(insert OID = 185 (  oidne			   PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "26 26" _null_ _null_ _null_ _null_ oidne _null_ _null_ _null_ ));
 DATA(insert OID = 186 (  box_same		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ box_same _null_ _null_ _null_ ));
 DATA(insert OID = 187 (  box_contain	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ box_contain _null_ _null_ _null_ ));
 DATA(insert OID = 188 (  box_left		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ box_left _null_ _null_ _null_ ));
 DATA(insert OID = 189 (  box_overleft	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ box_overleft _null_ _null_ _null_ ));
 DATA(insert OID = 190 (  box_overright	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ box_overright _null_ _null_ _null_ ));
 DATA(insert OID = 191 (  box_right		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ box_right _null_ _null_ _null_ ));
 DATA(insert OID = 192 (  box_contained	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ box_contained _null_ _null_ _null_ ));
+DATA(insert OID = 4083 (  box_left_pt	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ box_left_pt _null_ _null_ _null_ ));
+DATA(insert OID = 4084 (  box_overleft_pt  PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ box_overleft_pt _null_ _null_ _null_ ));
+DATA(insert OID = 4085 (  box_right_pt	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ box_right_pt _null_ _null_ _null_ ));
+DATA(insert OID = 4086 (  box_overright_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ box_overright_pt _null_ _null_ _null_ ));
+DATA(insert OID = 4087 (  box_below_pt	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ box_below_pt _null_ _null_ _null_ ));
+DATA(insert OID = 4088 (  box_overbelow_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ box_overbelow_pt _null_ _null_ _null_ ));
+DATA(insert OID = 4089 (  box_above_pt	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ box_above_pt _null_ _null_ _null_ ));
+DATA(insert OID = 4090 (  box_overabove_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ box_overabove_pt _null_ _null_ _null_ ));
 DATA(insert OID = 193 (  box_contain_pt    PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ box_contain_pt _null_ _null_ _null_ ));
 
 DATA(insert OID = 195 (  pg_node_tree_in	PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 194 "2275" _null_ _null_ _null_ _null_ pg_node_tree_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 196 (  pg_node_tree_out	PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "194" _null_ _null_ _null_ _null_ pg_node_tree_out _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 197 (  pg_node_tree_recv	PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 194 "2281" _null_ _null_ _null_ _null_ pg_node_tree_recv _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 198 (  pg_node_tree_send	PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 17 "194" _null_ _null_ _null_ _null_	pg_node_tree_send _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -1123,20 +1131,22 @@ DATA(insert OID = 973 (  path_inter		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0
 DATA(insert OID = 975 (  area			   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 701 "603" _null_ _null_ _null_ _null_	box_area _null_ _null_ _null_ ));
 DESCR("box area");
 DATA(insert OID = 976 (  width			   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 701 "603" _null_ _null_ _null_ _null_	box_width _null_ _null_ _null_ ));
 DESCR("box width");
 DATA(insert OID = 977 (  height			   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 701 "603" _null_ _null_ _null_ _null_	box_height _null_ _null_ _null_ ));
 DESCR("box height");
 DATA(insert OID = 978 (  box_distance	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 701 "603 603" _null_ _null_ _null_ _null_	box_distance _null_ _null_ _null_ ));
 DATA(insert OID = 979 (  area			   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 701 "602" _null_ _null_ _null_ _null_	path_area _null_ _null_ _null_ ));
 DESCR("area of a closed path");
 DATA(insert OID = 980 (  box_intersect	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 603 "603 603" _null_ _null_ _null_ _null_	box_intersect _null_ _null_ _null_ ));
+DATA(insert OID = 4067 ( boxes_bound_box   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 603 "603 603" _null_ _null_ _null_ _null_	boxes_bound_box _null_ _null_ _null_ ));
+DESCR("bounding box of two boxes");
 DATA(insert OID = 981 (  diagonal		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 601 "603" _null_ _null_ _null_ _null_	box_diagonal _null_ _null_ _null_ ));
 DESCR("box diagonal");
 DATA(insert OID = 982 (  path_n_lt		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "602 602" _null_ _null_ _null_ _null_ path_n_lt _null_ _null_ _null_ ));
 DATA(insert OID = 983 (  path_n_gt		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "602 602" _null_ _null_ _null_ _null_ path_n_gt _null_ _null_ _null_ ));
 DATA(insert OID = 984 (  path_n_eq		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "602 602" _null_ _null_ _null_ _null_ path_n_eq _null_ _null_ _null_ ));
 DATA(insert OID = 985 (  path_n_le		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "602 602" _null_ _null_ _null_ _null_ path_n_le _null_ _null_ _null_ ));
 DATA(insert OID = 986 (  path_n_ge		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "602 602" _null_ _null_ _null_ _null_ path_n_ge _null_ _null_ _null_ ));
 DATA(insert OID = 987 (  path_length	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 701 "602" _null_ _null_ _null_ _null_	path_length _null_ _null_ _null_ ));
 DATA(insert OID = 988 (  point_ne		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "600 600" _null_ _null_ _null_ _null_ point_ne _null_ _null_ _null_ ));
 DATA(insert OID = 989 (  point_vert		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "600 600" _null_ _null_ _null_ _null_ point_vert _null_ _null_ _null_ ));
@@ -1723,20 +1733,22 @@ DATA(insert OID = 1471 (  circle_distance	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2
 DATA(insert OID = 1472 (  circle_center		PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 600 "718" _null_ _null_ _null_ _null_ circle_center _null_ _null_ _null_ ));
 DATA(insert OID = 1473 (  circle			PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 718 "600 701" _null_ _null_ _null_ _null_ cr_circle _null_ _null_ _null_ ));
 DESCR("convert point and radius to circle");
 DATA(insert OID = 1474 (  circle			PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 718 "604" _null_ _null_ _null_ _null_ poly_circle _null_ _null_ _null_ ));
 DESCR("convert polygon to circle");
 DATA(insert OID = 1475 (  polygon			PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 604 "23 718" _null_ _null_ _null_ _null_	circle_poly _null_ _null_ _null_ ));
 DESCR("convert vertex count and circle to polygon");
 DATA(insert OID = 1476 (  dist_pc			PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 701 "600 718" _null_ _null_ _null_ _null_ dist_pc _null_ _null_ _null_ ));
 DATA(insert OID = 1477 (  circle_contain_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "718 600" _null_ _null_ _null_ _null_  circle_contain_pt _null_ _null_ _null_ ));
 DATA(insert OID = 1478 (  pt_contained_circle	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "600 718" _null_ _null_ _null_ _null_  pt_contained_circle _null_ _null_ _null_ ));
+DATA(insert OID = 4091 (  box				PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 603 "600" _null_ _null_ _null_ _null_ point_box _null_ _null_ _null_ ));
+DESCR("convert point to empty box");
 DATA(insert OID = 1479 (  circle			PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 718 "603" _null_ _null_ _null_ _null_ box_circle _null_ _null_ _null_ ));
 DESCR("convert box to circle");
 DATA(insert OID = 1480 (  box				PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 603 "718" _null_ _null_ _null_ _null_ circle_box _null_ _null_ _null_ ));
 DESCR("convert circle to box");
 DATA(insert OID = 1481 (  tinterval			 PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 704 "702 702" _null_ _null_ _null_ _null_ mktinterval _null_ _null_ _null_ ));
 DESCR("convert to tinterval");
 
 DATA(insert OID = 1482 (  lseg_ne			PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "601 601" _null_ _null_ _null_ _null_  lseg_ne _null_ _null_ _null_ ));
 DATA(insert OID = 1483 (  lseg_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "601 601" _null_ _null_ _null_ _null_  lseg_lt _null_ _null_ _null_ ));
 DATA(insert OID = 1484 (  lseg_le			PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "601 601" _null_ _null_ _null_ _null_  lseg_le _null_ _null_ _null_ ));
@@ -2211,20 +2223,24 @@ DESCR("inet address of the server");
 DATA(insert OID = 2199 (  inet_server_port		PGNSP PGUID 12 1 0 0 0 f f f f f f s 0 0 23 "" _null_ _null_ _null_ _null_	inet_server_port _null_ _null_ _null_ ));
 DESCR("server's port number for this connection");
 
 DATA(insert OID = 2627 (  inetnot			PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 869 "869" _null_ _null_ _null_ _null_	inetnot _null_ _null_ _null_ ));
 DATA(insert OID = 2628 (  inetand			PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 869 "869 869" _null_ _null_ _null_ _null_	inetand _null_ _null_ _null_ ));
 DATA(insert OID = 2629 (  inetor			PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 869 "869 869" _null_ _null_ _null_ _null_	inetor _null_ _null_ _null_ ));
 DATA(insert OID = 2630 (  inetpl			PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 869 "869 20" _null_ _null_ _null_ _null_	inetpl _null_ _null_ _null_ ));
 DATA(insert OID = 2631 (  int8pl_inet		PGNSP PGUID 14 1 0 0 0 f f f f t f i 2 0 869 "20 869" _null_ _null_ _null_ _null_	"select $2 + $1" _null_ _null_ _null_ ));
 DATA(insert OID = 2632 (  inetmi_int8		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 869 "869 20" _null_ _null_ _null_ _null_	inetmi_int8 _null_ _null_ _null_ ));
 DATA(insert OID = 2633 (  inetmi			PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 20 "869 869" _null_ _null_ _null_ _null_	inetmi _null_ _null_ _null_ ));
+DATA(insert OID = 4071 (  inet_same_family	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_ inet_same_family _null_ _null_ _null_ ));
+DESCR("are the addresses from the same family?");
+DATA(insert OID = 4061 (  inet_merge		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 650 "869 869" _null_ _null_ _null_ _null_ inet_merge _null_ _null_ _null_ ));
+DESCR("the smallest network which includes both of the given networks");
 
 /* GiST support for inet and cidr */
 DATA(insert OID = 3553 (  inet_gist_consistent	PGNSP PGUID 12 1 0 0 0 f f f f t f i 5 0 16 "2281 869 23 26 2281" _null_ _null_ _null_ _null_ inet_gist_consistent _null_ _null_ _null_ ));
 DESCR("GiST support");
 DATA(insert OID = 3554 (  inet_gist_union		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ inet_gist_union _null_ _null_ _null_ ));
 DESCR("GiST support");
 DATA(insert OID = 3555 (  inet_gist_compress	PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ inet_gist_compress _null_ _null_ _null_ ));
 DESCR("GiST support");
 DATA(insert OID = 3556 (  inet_gist_decompress	PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ inet_gist_decompress _null_ _null_ _null_ ));
 DESCR("GiST support");
@@ -4133,20 +4149,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_ 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_ 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_ 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_ brin_minmax_union _null_ _null_ _null_ ));
 DESCR("BRIN minmax support");
 
+/* BRIN inclusion */
+DATA(insert OID = 3387 ( 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_ brin_inclusion_opcinfo _null_ _null_ _null_ ));
+DESCR("BRIN inclusion support");
+DATA(insert OID = 3388 ( 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_ brin_inclusion_add_value _null_ _null_ _null_ ));
+DESCR("BRIN inclusion support");
+DATA(insert OID = 3389 ( 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_ brin_inclusion_consistent _null_ _null_ _null_ ));
+DESCR("BRIN inclusion support");
+DATA(insert OID = 3390 ( 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_ 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_ 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_ 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_ 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_ 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_ pg_try_advisory_lock_int8 _null_ _null_ _null_ ));
@@ -4891,20 +4917,22 @@ DESCR("implementation of -|- operator");
 DATA(insert OID = 3863 (  range_before		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_before _null_ _null_ _null_ ));
 DESCR("implementation of << operator");
 DATA(insert OID = 3864 (  range_after		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_after _null_ _null_ _null_ ));
 DESCR("implementation of >> operator");
 DATA(insert OID = 3865 (  range_overleft	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_overleft _null_ _null_ _null_ ));
 DESCR("implementation of &< operator");
 DATA(insert OID = 3866 (  range_overright	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_overright _null_ _null_ _null_ ));
 DESCR("implementation of &> operator");
 DATA(insert OID = 3867 (  range_union		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ range_union _null_ _null_ _null_ ));
 DESCR("implementation of + operator");
+DATA(insert OID = 4057 (  range_merge		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ range_merge _null_ _null_ _null_ ));
+DESCR("the smallest range which includes both of the given ranges");
 DATA(insert OID = 3868 (  range_intersect	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ range_intersect _null_ _null_ _null_ ));
 DESCR("implementation of * operator");
 DATA(insert OID = 3869 (  range_minus		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ range_minus _null_ _null_ _null_ ));
 DESCR("implementation of - operator");
 DATA(insert OID = 3870 (  range_cmp PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "3831 3831" _null_ _null_ _null_ _null_ range_cmp _null_ _null_ _null_ ));
 DESCR("less-equal-greater");
 DATA(insert OID = 3871 (  range_lt	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_lt _null_ _null_ _null_ ));
 DATA(insert OID = 3872 (  range_le	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_le _null_ _null_ _null_ ));
 DATA(insert OID = 3873 (  range_ge	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_ge _null_ _null_ _null_ ));
 DATA(insert OID = 3874 (  range_gt	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_gt _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index bc4517d..4a20e9a 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -935,20 +935,22 @@ extern Datum inet_client_addr(PG_FUNCTION_ARGS);
 extern Datum inet_client_port(PG_FUNCTION_ARGS);
 extern Datum inet_server_addr(PG_FUNCTION_ARGS);
 extern Datum inet_server_port(PG_FUNCTION_ARGS);
 extern Datum inetnot(PG_FUNCTION_ARGS);
 extern Datum inetand(PG_FUNCTION_ARGS);
 extern Datum inetor(PG_FUNCTION_ARGS);
 extern Datum inetpl(PG_FUNCTION_ARGS);
 extern Datum inetmi_int8(PG_FUNCTION_ARGS);
 extern Datum inetmi(PG_FUNCTION_ARGS);
 extern void clean_ipv6_addr(int addr_family, char *addr);
+extern Datum inet_same_family(PG_FUNCTION_ARGS);
+extern Datum inet_merge(PG_FUNCTION_ARGS);
 
 /* mac.c */
 extern Datum macaddr_in(PG_FUNCTION_ARGS);
 extern Datum macaddr_out(PG_FUNCTION_ARGS);
 extern Datum macaddr_recv(PG_FUNCTION_ARGS);
 extern Datum macaddr_send(PG_FUNCTION_ARGS);
 extern Datum macaddr_cmp(PG_FUNCTION_ARGS);
 extern Datum macaddr_lt(PG_FUNCTION_ARGS);
 extern Datum macaddr_le(PG_FUNCTION_ARGS);
 extern Datum macaddr_eq(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 0b6d3c3..256079c 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -275,34 +275,43 @@ extern Datum box_overlap(PG_FUNCTION_ARGS);
 extern Datum box_left(PG_FUNCTION_ARGS);
 extern Datum box_overleft(PG_FUNCTION_ARGS);
 extern Datum box_right(PG_FUNCTION_ARGS);
 extern Datum box_overright(PG_FUNCTION_ARGS);
 extern Datum box_below(PG_FUNCTION_ARGS);
 extern Datum box_overbelow(PG_FUNCTION_ARGS);
 extern Datum box_above(PG_FUNCTION_ARGS);
 extern Datum box_overabove(PG_FUNCTION_ARGS);
 extern Datum box_contained(PG_FUNCTION_ARGS);
 extern Datum box_contain(PG_FUNCTION_ARGS);
+extern Datum box_left_pt(PG_FUNCTION_ARGS);
+extern Datum box_overleft_pt(PG_FUNCTION_ARGS);
+extern Datum box_right_pt(PG_FUNCTION_ARGS);
+extern Datum box_overright_pt(PG_FUNCTION_ARGS);
+extern Datum box_below_pt(PG_FUNCTION_ARGS);
+extern Datum box_overbelow_pt(PG_FUNCTION_ARGS);
+extern Datum box_above_pt(PG_FUNCTION_ARGS);
+extern Datum box_overabove_pt(PG_FUNCTION_ARGS);
 extern Datum box_contain_pt(PG_FUNCTION_ARGS);
 extern Datum box_below_eq(PG_FUNCTION_ARGS);
 extern Datum box_above_eq(PG_FUNCTION_ARGS);
 extern Datum box_lt(PG_FUNCTION_ARGS);
 extern Datum box_gt(PG_FUNCTION_ARGS);
 extern Datum box_eq(PG_FUNCTION_ARGS);
 extern Datum box_le(PG_FUNCTION_ARGS);
 extern Datum box_ge(PG_FUNCTION_ARGS);
 extern Datum box_area(PG_FUNCTION_ARGS);
 extern Datum box_width(PG_FUNCTION_ARGS);
 extern Datum box_height(PG_FUNCTION_ARGS);
 extern Datum box_distance(PG_FUNCTION_ARGS);
 extern Datum box_center(PG_FUNCTION_ARGS);
 extern Datum box_intersect(PG_FUNCTION_ARGS);
+extern Datum boxes_bound_box(PG_FUNCTION_ARGS);
 extern Datum box_diagonal(PG_FUNCTION_ARGS);
 extern Datum points_box(PG_FUNCTION_ARGS);
 extern Datum box_add(PG_FUNCTION_ARGS);
 extern Datum box_sub(PG_FUNCTION_ARGS);
 extern Datum box_mul(PG_FUNCTION_ARGS);
 extern Datum box_div(PG_FUNCTION_ARGS);
 
 /* public path routines */
 extern Datum path_area(PG_FUNCTION_ARGS);
 extern Datum path_in(PG_FUNCTION_ARGS);
@@ -389,20 +398,21 @@ extern Datum circle_sub_pt(PG_FUNCTION_ARGS);
 extern Datum circle_mul_pt(PG_FUNCTION_ARGS);
 extern Datum circle_div_pt(PG_FUNCTION_ARGS);
 extern Datum circle_diameter(PG_FUNCTION_ARGS);
 extern Datum circle_radius(PG_FUNCTION_ARGS);
 extern Datum circle_distance(PG_FUNCTION_ARGS);
 extern Datum dist_pc(PG_FUNCTION_ARGS);
 extern Datum dist_cpoly(PG_FUNCTION_ARGS);
 extern Datum dist_ppoly(PG_FUNCTION_ARGS);
 extern Datum circle_center(PG_FUNCTION_ARGS);
 extern Datum cr_circle(PG_FUNCTION_ARGS);
+extern Datum point_box(PG_FUNCTION_ARGS);
 extern Datum box_circle(PG_FUNCTION_ARGS);
 extern Datum circle_box(PG_FUNCTION_ARGS);
 extern Datum poly_circle(PG_FUNCTION_ARGS);
 extern Datum circle_poly(PG_FUNCTION_ARGS);
 extern Datum circle_area(PG_FUNCTION_ARGS);
 
 /* support routines for the GiST access method (access/gist/gistproc.c) */
 extern Datum gist_box_compress(PG_FUNCTION_ARGS);
 extern Datum gist_box_decompress(PG_FUNCTION_ARGS);
 extern Datum gist_box_union(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/rangetypes.h b/src/include/utils/rangetypes.h
index 173bf74..2c0e050 100644
--- a/src/include/utils/rangetypes.h
+++ b/src/include/utils/rangetypes.h
@@ -203,15 +203,16 @@ extern int range_cmp_bound_values(TypeCacheEntry *typcache, RangeBound *b1,
 					   RangeBound *b2);
 extern bool bounds_adjacent(TypeCacheEntry *typcache, RangeBound bound1,
 				RangeBound bound2);
 extern RangeType *make_empty_range(TypeCacheEntry *typcache);
 
 /* GiST support (in rangetypes_gist.c) */
 extern Datum range_gist_consistent(PG_FUNCTION_ARGS);
 extern Datum range_gist_compress(PG_FUNCTION_ARGS);
 extern Datum range_gist_decompress(PG_FUNCTION_ARGS);
 extern Datum range_gist_union(PG_FUNCTION_ARGS);
+extern Datum range_merge(PG_FUNCTION_ARGS);
 extern Datum range_gist_penalty(PG_FUNCTION_ARGS);
 extern Datum range_gist_picksplit(PG_FUNCTION_ARGS);
 extern Datum range_gist_same(PG_FUNCTION_ARGS);
 
 #endif   /* RANGETYPES_H */
diff --git a/src/test/regress/expected/brin.out b/src/test/regress/expected/brin.out
index f47f366..47f081f 100644
--- a/src/test/regress/expected/brin.out
+++ b/src/test/regress/expected/brin.out
@@ -15,143 +15,172 @@ 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);
 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,
 	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',
 	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;
+	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, int4rangecol) SELECT
+	inet '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_minmax_ops,
+	inetcol inet_inclusion_ops,
 	bpcharcol,
 	datecol,
 	timecol,
 	timestampcol,
 	timestamptzcol,
 	intervalcol,
 	timetzcol,
 	bitcol,
 	varbitcol,
 	numericcol,
 	uuidcol,
-	lsncol
+	int4rangecol,
+	lsncol,
+	boxcol,
+	pointcol
 ) with (pages_per_range = 1);
 BEGIN;
-CREATE TABLE brinopers (colname name, op text[], value text[],
+CREATE TABLE brinopers (colname name, typ regtype, 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}');
+INSERT INTO brinopers VALUES
+	('byteacol', NULL, '{>, >=, =, <=, <}', '{AAAAAA, AAAAAA, BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA, ZZZZZZ, ZZZZZZ}'),
+	('charcol', NULL, '{>, >=, =, <=, <}', '{A, A, M, Z, Z}'),
+	('namecol', NULL, '{>, >=, =, <=, <}', '{AAAAAA, AAAAAA, MAAAAA, ZZAAAA, ZZAAAA}'),
+	('int8col', NULL, '{>, >=, =, <=, <}', '{0, 0, 1257141600, 1428427143, 1428427143}'),
+	('int2col', NULL, '{>, >=, =, <=, <}', '{0, 0, 800, 999, 999}'),
+	('int4col', NULL, '{>, >=, =, <=, <}', '{0, 0, 800, 1999, 1999}'),
+	('textcol', NULL, '{>, >=, =, <=, <}', '{AAAAAA, AAAAAA, BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA, ZZAAAA, ZZAAAA}'),
+	('oidcol', NULL, '{>, >=, =, <=, <}', '{0, 0, 8800, 9999, 9999}'),
+	('tidcol', NULL, '{>, >=, =, <=, <}', '{"(0,0)", "(0,0)", "(8800,0)", "(9999,19)", "(9999,19)"}'),
+	('float4col', NULL, '{>, >=, =, <=, <}', '{0.0103093, 0.0103093, 1, 1, 1}'),
+	('float8col', NULL, '{>, >=, =, <=, <}', '{0, 0, 0, 1.98, 1.98}'),
+	('inetcol', NULL, '{&&, =, <, <=, >, >=, >>=, >>, <<=, <<}', '{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', NULL, '{&&, >>=, <<=, =}', '{fe80::6e40:8ff:fea9:a673/32, fe80::6e40:8ff:fea9:8c46, fe80::6e40:8ff:fea9:a673/32, fe80::6e40:8ff:fea9:8c46}'),
+	('inetcol', 'cidr', '{<<=}', '{0/0}'),
+	('bpcharcol', NULL, '{>, >=, =, <=, <}', '{A, A, W, Z, Z}'),
+	('datecol', NULL, '{>, >=, =, <=, <}', '{1995-08-15, 1995-08-15, 2009-12-01, 2022-12-30, 2022-12-30}'),
+	('timecol', NULL, '{>, >=, =, <=, <}', '{01:20:30, 01:20:30, 02:28:57, 06:28:31.5, 06:28:31.5}'),
+	('timestampcol', NULL, '{>, >=, =, <=, <}', '{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', NULL, '{>, >=, =, <=, <}', '{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', NULL, '{>, >=, =, <=, <}', '{00:00:00, 00:00:00, 1 mons 13 days 12:24, 2 mons 23 days 07:48:00, 1 year}'),
+	('timetzcol', NULL, '{>, >=, =, <=, <}', '{01:30:20-03, 01:30:20-03, 01:35:50-08, 23:55:05-03, 23:55:05-03}'),
+	('numericcol', NULL, '{>, >=, =, <=, <}', '{0.00, 0.01, 2268164.347826086956521739130434782609, 99470151.9, 99470151.9}'),
+	('macaddrcol', NULL, '{>, >=, =, <=, <}', '{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}'),
+	('bitcol', NULL, '{>, >=, =, <=, <}', '{0000000010, 0000000010, 0011011110, 1111111000, 1111111000}'),
+	('varbitcol', NULL, '{>, >=, =, <=, <}', '{0000000000000100, 0000000000000100, 0001010001100110, 1111111111111000, 1111111111111000}'),
+	('uuidcol', NULL, '{>, >=, =, <=, <}', '{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}'),
+	('int4rangecol', NULL, '{<<, &<, &&, &>, >>, @>, <@, =, <, <=, >, >=}', '{"[10000,)","[10000,)","(,]","[3,4)","[36,44)","(1500,1501]","[3,4)","[222,1222)","[36,44)","[43,1043)","[367,4466)","[519,)"}'),
+	('int4rangecol', NULL, '{@>, <@, =, <=, >, >=}', '{empty, empty, empty, empty, empty, empty}'),
+	('int4rangecol', 'int4', '{@>}', '{1500}'),
+	('lsncol', NULL, '{>, >=, =, <=, <, IS, IS NOT}', '{0/1200, 0/1200, 44/455222, 198/1999799, 198/1999799, NULL, NULL}'),
+	('boxcol', NULL, '{<<, &<, &&, &>, >>, <<|, &<|, |&>, |>>, @>, <@, ~=}', '{"((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))"}'),
+	('boxcol', 'point', '{<<, &<, &&, &>, >>, <<|, &<|, |&>, |>>, @>}', '{"(1000,2000)","(3000,4000)","(500,43)","(1,2)","(3,4)","(3000,4000)","(3000,4000)","(1,2)","(1,2)","(500,43)"}'),
+	('pointcol', NULL, '{<<, >>, <^, >^, ~=}', '{"(3000,4000)","(3,4)","(5000,15000)","(1,2)","(222,1222)"}'),
+	('pointcol', 'box', '{<@, &&}', '{"((0,0),(5000,5000))","((0,0),(3000,4000))"}');
 COMMIT;
 DO $x$
 DECLARE
         r record;
-        tabname text;
-        tabname_ss text;
+        cond text;
 		count int;
-		query text;
-		plan text;
 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);
+        FOR r IN SELECT colname, oper, typ, value[ordinality] FROM brinopers, unnest(op) WITH ORDINALITY AS oper LOOP
+				-- prepare the condition
+				IF r.typ 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('create temp table %s (tid tid) ON COMMIT DROP', tabname);
-                EXECUTE query;
+				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;
-				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;
+				EXECUTE format($y$INSERT INTO brin_result_ss SELECT ctid FROM brintest WHERE %s $y$, cond);
+
+				-- make sure we have a sensible test case
+                SELECT count(*) INTO count FROM brin_result;
+				IF count = 0 THEN RAISE EXCEPTION '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);
+                PERFORM * FROM brin_result EXCEPT ALL SELECT * FROM brin_result_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);
+                PERFORM * FROM brin_result_ss EXCEPT ALL SELECT * FROM brin_result;
 				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,
 	substr(stringu1, 1, 1)::"char",
 	stringu1::name, 142857 * tenthous,
 	thousand,
 	twothousand,
 	repeat(stringu1, 42),
 	unique1::oid,
 	format('(%s,%s)', tenthous, twenty)::tid,
@@ -163,20 +192,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/inet.out b/src/test/regress/expected/inet.out
index d58bf01..ad76766 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -588,10 +588,38 @@ SELECT '127::1'::inet + 10000000000;
 ------------------
  127::2:540b:e401
 (1 row)
 
 SELECT '127::1'::inet - '127::2'::inet;
  ?column? 
 ----------
        -1
 (1 row)
 
+-- insert one more row with addressed from different families
+INSERT INTO INET_TBL (c, i) VALUES ('10', '10::/8');
+-- now, this one should fail
+SELECT inet_merge(c, i) FROM INET_TBL;
+ERROR:  cannot merge addresses from different families
+-- fix it by inet_same_family() condition
+SELECT inet_merge(c, i) FROM INET_TBL WHERE inet_same_family(c, i);
+   inet_merge    
+-----------------
+ 192.168.1.0/24
+ 192.168.1.0/24
+ 192.168.1.0/24
+ 192.168.1.0/24
+ 192.168.1.0/24
+ 192.168.1.0/24
+ 10.0.0.0/8
+ 10.0.0.0/8
+ 10.1.2.3/32
+ 10.1.2.0/24
+ 10.1.0.0/16
+ 10.0.0.0/8
+ 10.0.0.0/7
+ 8.0.0.0/6
+ 10:23::/64
+ 10:23::8000/113
+ ::/24
+(17 rows)
+
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 9870bfa..993c8eb 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1070,54 +1070,56 @@ FROM pg_operator as p1 LEFT JOIN pg_description as d
 WHERE d.classoid IS NULL AND p1.oid <= 9999;
  oid | oprname 
 -----+---------
 (0 rows)
 
 -- Check that operators' underlying functions have suitable comments,
 -- namely 'implementation of XXX operator'.  (Note: it's not necessary to
 -- put such comments into pg_proc.h; initdb will generate them as needed.)
 -- In some cases involving legacy names for operators, there are multiple
 -- operators referencing the same pg_proc entry, so ignore operators whose
--- comments say they are deprecated.
+-- comments say they are deprecated or same as other operator.
 -- We also have a few functions that are both operator support and meant to
 -- be called directly; those should have comments matching their operator.
 WITH funcdescs AS (
   SELECT p.oid as p_oid, proname, o.oid as o_oid,
     obj_description(p.oid, 'pg_proc') as prodesc,
     'implementation of ' || oprname || ' operator' as expecteddesc,
     obj_description(o.oid, 'pg_operator') as oprdesc
   FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid
   WHERE o.oid <= 9999
 )
 SELECT * FROM funcdescs
   WHERE prodesc IS DISTINCT FROM expecteddesc
     AND oprdesc NOT LIKE 'deprecated%'
+    AND oprdesc NOT LIKE 'same as %'
     AND prodesc IS DISTINCT FROM oprdesc;
  p_oid | proname | o_oid | prodesc | expecteddesc | oprdesc 
 -------+---------+-------+---------+--------------+---------
 (0 rows)
 
 -- Show all the operator-implementation functions that have their own
 -- comments.  This should happen only in cases where the function and
 -- operator syntaxes are both documented at the user level.
 -- This should be a pretty short list; it's mostly legacy cases.
 WITH funcdescs AS (
   SELECT p.oid as p_oid, proname, o.oid as o_oid,
     obj_description(p.oid, 'pg_proc') as prodesc,
     'implementation of ' || oprname || ' operator' as expecteddesc,
     obj_description(o.oid, 'pg_operator') as oprdesc
   FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid
   WHERE o.oid <= 9999
 )
 SELECT p_oid, proname, prodesc FROM funcdescs
   WHERE prodesc IS DISTINCT FROM expecteddesc
     AND oprdesc NOT LIKE 'deprecated%'
+    AND oprdesc NOT LIKE 'same as %'
 ORDER BY 1;
  p_oid |         proname         |                     prodesc                     
 -------+-------------------------+-------------------------------------------------
    378 | array_append            | append element onto end of array
    379 | array_prepend           | prepend element onto front of array
   1035 | aclinsert               | add/update ACL item
   1036 | aclremove               | remove ACL item
   1037 | aclcontains             | contains
   3217 | jsonb_extract_path      | get value from jsonb with path elements
   3940 | jsonb_extract_path_text | get value from jsonb as text with path elements
@@ -1652,24 +1654,51 @@ 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 |            4 | &>
        3580 |            4 | >=
        3580 |            5 | >
+       3580 |            5 | >>
+       3580 |            6 | ~=
+       3580 |            7 | @>
+       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 |           25 | >>=
+       3580 |           26 | <<
+       3580 |           27 | <<=
        4000 |            1 | <<
        4000 |            1 | ~<~
        4000 |            2 | &<
        4000 |            2 | ~<=~
        4000 |            3 | &&
        4000 |            3 | =
        4000 |            4 | &>
        4000 |            4 | ~>=~
        4000 |            5 | >>
        4000 |            5 | ~>~
@@ -1678,21 +1707,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)
+(112 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/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index 35d0dd3..556486e 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -473,22 +473,40 @@ select numrange(1.0, 2.0) + numrange(2.0, 3.0);
 -----------
  [1.0,3.0)
 (1 row)
 
 select numrange(1.0, 2.0) + numrange(1.5, 3.0);
  ?column?  
 -----------
  [1.0,3.0)
 (1 row)
 
-select numrange(1.0, 2.0) + numrange(2.5, 3.0);
+select numrange(1.0, 2.0) + numrange(2.5, 3.0);	-- should fail
 ERROR:  result of range union would not be contiguous
+select range_merge(numrange(1.0, 2.0), numrange(2.0, 3.0));
+ range_merge 
+-------------
+ [1.0,3.0)
+(1 row)
+
+select range_merge(numrange(1.0, 2.0), numrange(1.5, 3.0));
+ range_merge 
+-------------
+ [1.0,3.0)
+(1 row)
+
+select range_merge(numrange(1.0, 2.0), numrange(2.5, 3.0)); -- shouldn't fail
+ range_merge 
+-------------
+ [1.0,3.0)
+(1 row)
+
 select numrange(1.0, 2.0) * numrange(2.0, 3.0);
  ?column? 
 ----------
  empty
 (1 row)
 
 select numrange(1.0, 2.0) * numrange(1.5, 3.0);
  ?column?  
 -----------
  [1.5,2.0)
diff --git a/src/test/regress/sql/brin.sql b/src/test/regress/sql/brin.sql
index 3aff925..758f560 100644
--- a/src/test/regress/sql/brin.sql
+++ b/src/test/regress/sql/brin.sql
@@ -15,149 +15,178 @@ 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);
 
 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,
 	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',
 	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;
+	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-only tuples too
-INSERT INTO brintest SELECT NULL FROM tenk1 LIMIT 25;
+-- throw in some NULL's and different values
+INSERT INTO brintest (inetcol, int4rangecol) SELECT
+	inet '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_minmax_ops,
+	inetcol inet_inclusion_ops,
 	bpcharcol,
 	datecol,
 	timecol,
 	timestampcol,
 	timestamptzcol,
 	intervalcol,
 	timetzcol,
 	bitcol,
 	varbitcol,
 	numericcol,
 	uuidcol,
-	lsncol
+	int4rangecol,
+	lsncol,
+	boxcol,
+	pointcol
 ) with (pages_per_range = 1);
 
 BEGIN;
-CREATE TABLE brinopers (colname name, op text[], value text[],
+CREATE TABLE brinopers (colname name, typ regtype, 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}');
+INSERT INTO brinopers VALUES
+	('byteacol', NULL, '{>, >=, =, <=, <}', '{AAAAAA, AAAAAA, BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA, ZZZZZZ, ZZZZZZ}'),
+	('charcol', NULL, '{>, >=, =, <=, <}', '{A, A, M, Z, Z}'),
+	('namecol', NULL, '{>, >=, =, <=, <}', '{AAAAAA, AAAAAA, MAAAAA, ZZAAAA, ZZAAAA}'),
+	('int8col', NULL, '{>, >=, =, <=, <}', '{0, 0, 1257141600, 1428427143, 1428427143}'),
+	('int2col', NULL, '{>, >=, =, <=, <}', '{0, 0, 800, 999, 999}'),
+	('int4col', NULL, '{>, >=, =, <=, <}', '{0, 0, 800, 1999, 1999}'),
+	('textcol', NULL, '{>, >=, =, <=, <}', '{AAAAAA, AAAAAA, BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA, ZZAAAA, ZZAAAA}'),
+	('oidcol', NULL, '{>, >=, =, <=, <}', '{0, 0, 8800, 9999, 9999}'),
+	('tidcol', NULL, '{>, >=, =, <=, <}', '{"(0,0)", "(0,0)", "(8800,0)", "(9999,19)", "(9999,19)"}'),
+	('float4col', NULL, '{>, >=, =, <=, <}', '{0.0103093, 0.0103093, 1, 1, 1}'),
+	('float8col', NULL, '{>, >=, =, <=, <}', '{0, 0, 0, 1.98, 1.98}'),
+	('inetcol', NULL, '{&&, =, <, <=, >, >=, >>=, >>, <<=, <<}', '{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', NULL, '{&&, >>=, <<=, =}', '{fe80::6e40:8ff:fea9:a673/32, fe80::6e40:8ff:fea9:8c46, fe80::6e40:8ff:fea9:a673/32, fe80::6e40:8ff:fea9:8c46}'),
+	('inetcol', 'cidr', '{<<=}', '{0/0}'),
+	('bpcharcol', NULL, '{>, >=, =, <=, <}', '{A, A, W, Z, Z}'),
+	('datecol', NULL, '{>, >=, =, <=, <}', '{1995-08-15, 1995-08-15, 2009-12-01, 2022-12-30, 2022-12-30}'),
+	('timecol', NULL, '{>, >=, =, <=, <}', '{01:20:30, 01:20:30, 02:28:57, 06:28:31.5, 06:28:31.5}'),
+	('timestampcol', NULL, '{>, >=, =, <=, <}', '{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', NULL, '{>, >=, =, <=, <}', '{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', NULL, '{>, >=, =, <=, <}', '{00:00:00, 00:00:00, 1 mons 13 days 12:24, 2 mons 23 days 07:48:00, 1 year}'),
+	('timetzcol', NULL, '{>, >=, =, <=, <}', '{01:30:20-03, 01:30:20-03, 01:35:50-08, 23:55:05-03, 23:55:05-03}'),
+	('numericcol', NULL, '{>, >=, =, <=, <}', '{0.00, 0.01, 2268164.347826086956521739130434782609, 99470151.9, 99470151.9}'),
+	('macaddrcol', NULL, '{>, >=, =, <=, <}', '{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}'),
+	('bitcol', NULL, '{>, >=, =, <=, <}', '{0000000010, 0000000010, 0011011110, 1111111000, 1111111000}'),
+	('varbitcol', NULL, '{>, >=, =, <=, <}', '{0000000000000100, 0000000000000100, 0001010001100110, 1111111111111000, 1111111111111000}'),
+	('uuidcol', NULL, '{>, >=, =, <=, <}', '{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}'),
+	('int4rangecol', NULL, '{<<, &<, &&, &>, >>, @>, <@, =, <, <=, >, >=}', '{"[10000,)","[10000,)","(,]","[3,4)","[36,44)","(1500,1501]","[3,4)","[222,1222)","[36,44)","[43,1043)","[367,4466)","[519,)"}'),
+	('int4rangecol', NULL, '{@>, <@, =, <=, >, >=}', '{empty, empty, empty, empty, empty, empty}'),
+	('int4rangecol', 'int4', '{@>}', '{1500}'),
+	('lsncol', NULL, '{>, >=, =, <=, <, IS, IS NOT}', '{0/1200, 0/1200, 44/455222, 198/1999799, 198/1999799, NULL, NULL}'),
+	('boxcol', NULL, '{<<, &<, &&, &>, >>, <<|, &<|, |&>, |>>, @>, <@, ~=}', '{"((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))"}'),
+	('boxcol', 'point', '{<<, &<, &&, &>, >>, <<|, &<|, |&>, |>>, @>}', '{"(1000,2000)","(3000,4000)","(500,43)","(1,2)","(3,4)","(3000,4000)","(3000,4000)","(1,2)","(1,2)","(500,43)"}'),
+	('pointcol', NULL, '{<<, >>, <^, >^, ~=}', '{"(3000,4000)","(3,4)","(5000,15000)","(1,2)","(222,1222)"}'),
+	('pointcol', 'box', '{<@, &&}', '{"((0,0),(5000,5000))","((0,0),(3000,4000))"}');
 COMMIT;
 
 DO $x$
 DECLARE
         r record;
-        tabname text;
-        tabname_ss text;
+        cond text;
 		count int;
-		query text;
-		plan text;
 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);
+        FOR r IN SELECT colname, oper, typ, value[ordinality] FROM brinopers, unnest(op) WITH ORDINALITY AS oper LOOP
+				-- prepare the condition
+				IF r.typ 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('create temp table %s (tid tid) ON COMMIT DROP', tabname);
-                EXECUTE query;
+				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;
-				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;
+				EXECUTE format($y$INSERT INTO brin_result_ss SELECT ctid FROM brintest WHERE %s $y$, cond);
+
+				-- make sure we have a sensible test case
+                SELECT count(*) INTO count FROM brin_result;
+				IF count = 0 THEN RAISE EXCEPTION '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);
+                PERFORM * FROM brin_result EXCEPT ALL SELECT * FROM brin_result_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);
+                PERFORM * FROM brin_result_ss EXCEPT ALL SELECT * FROM brin_result;
 				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,
 	substr(stringu1, 1, 1)::"char",
 	stringu1::name, 142857 * tenthous,
 	thousand,
 	twothousand,
 	repeat(stringu1, 42),
 	unique1::oid,
@@ -170,17 +199,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;
diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql
index c9792b7..09a446c 100644
--- a/src/test/regress/sql/inet.sql
+++ b/src/test/regress/sql/inet.sql
@@ -103,10 +103,17 @@ SELECT '127.0.0.2'::inet  - ('127.0.0.2'::inet - 500);
 SELECT '127::2'::inet  - ('127::2'::inet + 500);
 SELECT '127::2'::inet  - ('127::2'::inet - 500);
 -- these should give overflow errors:
 SELECT '127.0.0.1'::inet + 10000000000;
 SELECT '127.0.0.1'::inet - 10000000000;
 SELECT '126::1'::inet - '127::2'::inet;
 SELECT '127::1'::inet - '126::2'::inet;
 -- but not these
 SELECT '127::1'::inet + 10000000000;
 SELECT '127::1'::inet - '127::2'::inet;
+
+-- insert one more row with addressed from different families
+INSERT INTO INET_TBL (c, i) VALUES ('10', '10::/8');
+-- now, this one should fail
+SELECT inet_merge(c, i) FROM INET_TBL;
+-- fix it by inet_same_family() condition
+SELECT inet_merge(c, i) FROM INET_TBL WHERE inet_same_family(c, i);
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 7159a83..2c20763 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -628,51 +628,53 @@ WHERE p1.oprjoin = p2.oid AND
 SELECT p1.oid, p1.oprname
 FROM pg_operator as p1 LEFT JOIN pg_description as d
      ON p1.tableoid = d.classoid and p1.oid = d.objoid and d.objsubid = 0
 WHERE d.classoid IS NULL AND p1.oid <= 9999;
 
 -- Check that operators' underlying functions have suitable comments,
 -- namely 'implementation of XXX operator'.  (Note: it's not necessary to
 -- put such comments into pg_proc.h; initdb will generate them as needed.)
 -- In some cases involving legacy names for operators, there are multiple
 -- operators referencing the same pg_proc entry, so ignore operators whose
--- comments say they are deprecated.
+-- comments say they are deprecated or same as other operator.
 -- We also have a few functions that are both operator support and meant to
 -- be called directly; those should have comments matching their operator.
 WITH funcdescs AS (
   SELECT p.oid as p_oid, proname, o.oid as o_oid,
     obj_description(p.oid, 'pg_proc') as prodesc,
     'implementation of ' || oprname || ' operator' as expecteddesc,
     obj_description(o.oid, 'pg_operator') as oprdesc
   FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid
   WHERE o.oid <= 9999
 )
 SELECT * FROM funcdescs
   WHERE prodesc IS DISTINCT FROM expecteddesc
     AND oprdesc NOT LIKE 'deprecated%'
+    AND oprdesc NOT LIKE 'same as %'
     AND prodesc IS DISTINCT FROM oprdesc;
 
 -- Show all the operator-implementation functions that have their own
 -- comments.  This should happen only in cases where the function and
 -- operator syntaxes are both documented at the user level.
 -- This should be a pretty short list; it's mostly legacy cases.
 WITH funcdescs AS (
   SELECT p.oid as p_oid, proname, o.oid as o_oid,
     obj_description(p.oid, 'pg_proc') as prodesc,
     'implementation of ' || oprname || ' operator' as expecteddesc,
     obj_description(o.oid, 'pg_operator') as oprdesc
   FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid
   WHERE o.oid <= 9999
 )
 SELECT p_oid, proname, prodesc FROM funcdescs
   WHERE prodesc IS DISTINCT FROM expecteddesc
     AND oprdesc NOT LIKE 'deprecated%'
+    AND oprdesc NOT LIKE 'same as %'
 ORDER BY 1;
 
 
 -- **************** pg_aggregate ****************
 
 -- Look for illegal values in pg_aggregate fields.
 
 SELECT ctid, aggfnoid::oid
 FROM pg_aggregate as p1
 WHERE aggfnoid = 0 OR aggtransfn = 0 OR
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index aa026ca..6a9abac 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -101,21 +101,25 @@ select numrange(1.0, 2.0) << numrange(3.0, 4.0);
 select numrange(1.0, 3.0,'[]') << numrange(3.0, 4.0,'[]');
 select numrange(1.0, 3.0,'()') << numrange(3.0, 4.0,'()');
 select numrange(1.0, 2.0) >> numrange(3.0, 4.0);
 select numrange(3.0, 70.0) &< numrange(6.6, 100.0);
 
 select numrange(1.1, 2.2) < numrange(1.0, 200.2);
 select numrange(1.1, 2.2) < numrange(1.1, 1.2);
 
 select numrange(1.0, 2.0) + numrange(2.0, 3.0);
 select numrange(1.0, 2.0) + numrange(1.5, 3.0);
-select numrange(1.0, 2.0) + numrange(2.5, 3.0);
+select numrange(1.0, 2.0) + numrange(2.5, 3.0);	-- should fail
+
+select range_merge(numrange(1.0, 2.0), numrange(2.0, 3.0));
+select range_merge(numrange(1.0, 2.0), numrange(1.5, 3.0));
+select range_merge(numrange(1.0, 2.0), numrange(2.5, 3.0)); -- shouldn't fail
 
 select numrange(1.0, 2.0) * numrange(2.0, 3.0);
 select numrange(1.0, 2.0) * numrange(1.5, 3.0);
 select numrange(1.0, 2.0) * numrange(2.5, 3.0);
 
 create table numrange_test2(nr numrange);
 create index numrange_test2_hash_idx on numrange_test2 (nr);
 
 INSERT INTO numrange_test2 VALUES('[, 5)');
 INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2));