From 2f1d65c1f4219db18664f3b0e731be71caba2245 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sun, 15 Mar 2015 13:10:42 +0100
Subject: [PATCH 1/7] sql level support functions

---
 doc/src/sgml/func.sgml                   | 47 +++++++++++++++++++++++++++++
 src/backend/utils/adt/geo_ops.c          | 39 ++++++++++++++++++++++++
 src/backend/utils/adt/network.c          | 52 ++++++++++++++++++++++++++++++++
 src/backend/utils/adt/rangetypes.c       | 45 +++++++++++++++++++--------
 src/include/catalog/pg_cast.h            |  1 +
 src/include/catalog/pg_proc.h            | 10 ++++++
 src/include/utils/builtins.h             |  2 ++
 src/include/utils/geo_decls.h            |  2 ++
 src/include/utils/rangetypes.h           |  1 +
 src/test/regress/expected/geometry.out   | 34 +++++++++++++++++++++
 src/test/regress/expected/geometry_1.out | 34 +++++++++++++++++++++
 src/test/regress/expected/geometry_2.out | 34 +++++++++++++++++++++
 src/test/regress/expected/inet.out       | 28 +++++++++++++++++
 src/test/regress/expected/rangetypes.out | 20 +++++++++++-
 src/test/regress/sql/geometry.sql        |  6 ++++
 src/test/regress/sql/inet.sql            |  7 +++++
 src/test/regress/sql/rangetypes.sql      |  6 +++-
 17 files changed, 354 insertions(+), 14 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index e6f2129..fb39731 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -8289,32 +8289,44 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
          <indexterm>
           <primary>box</primary>
          </indexterm>
          <literal><function>box(<type>circle</type>)</function></literal>
         </entry>
         <entry><type>box</type></entry>
         <entry>circle to box</entry>
         <entry><literal>box(circle '((0,0),2.0)')</literal></entry>
        </row>
        <row>
+        <entry><literal><function>box(<type>point</type>)</function></literal></entry>
+        <entry><type>box</type></entry>
+        <entry>point to empty box</entry>
+        <entry><literal>box(point '(0,0)')</literal></entry>
+       </row>
+       <row>
         <entry><literal><function>box(<type>point</type>, <type>point</type>)</function></literal></entry>
         <entry><type>box</type></entry>
         <entry>points to box</entry>
         <entry><literal>box(point '(0,0)', point '(1,1)')</literal></entry>
        </row>
        <row>
         <entry><literal><function>box(<type>polygon</type>)</function></literal></entry>
         <entry><type>box</type></entry>
         <entry>polygon to box</entry>
         <entry><literal>box(polygon '((0,0),(1,1),(2,0))')</literal></entry>
        </row>
        <row>
+        <entry><literal><function>bound_box(<type>box</type>, <type>box</type>)</function></literal></entry>
+        <entry><type>box</type></entry>
+        <entry>boxes to bounding box</entry>
+        <entry><literal>bound_box(box '((0,0),(1,1))', box '((3,3),(4,4))')</literal></entry>
+       </row>
+       <row>
         <entry>
          <indexterm>
           <primary>circle</primary>
          </indexterm>
          <literal><function>circle(<type>box</type>)</function></literal>
         </entry>
         <entry><type>circle</type></entry>
         <entry>box to circle</entry>
         <entry><literal>circle(box '((0,0),(1,1))')</literal></entry>
        </row>
@@ -8727,20 +8739,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.)
@@ -12083,20 +12119,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/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 6cb6be5..39a7855 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -4220,20 +4220,59 @@ box_div(PG_FUNCTION_ARGS)
 											  PointPGetDatum(p)));
 	low = DatumGetPointP(DirectFunctionCall2(point_div,
 											 PointPGetDatum(&box->low),
 											 PointPGetDatum(p)));
 
 	result = box_construct(high->x, low->x, high->y, low->y);
 
 	PG_RETURN_BOX_P(result);
 }
 
+/*
+ * Convert point to empty box
+ */
+Datum
+point_box(PG_FUNCTION_ARGS)
+{
+	Point	   *pt = PG_GETARG_POINT_P(0);
+	BOX		   *box;
+
+	box = (BOX *) palloc(sizeof(BOX));
+
+	box->high.x = pt->x;
+	box->low.x = pt->x;
+	box->high.y = pt->y;
+	box->low.y = pt->y;
+
+	PG_RETURN_BOX_P(box);
+}
+
+/*
+ * 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);
+}
+
 
 /***********************************************************************
  **
  **		Routines for 2D paths.
  **
  ***********************************************************************/
 
 /* path_add()
  * Concatenate two paths (only if they are both open).
  */
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index 3a705da..1f8469a 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
+ * check that we can create a network which contains both of the networks.
+ */
+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/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index c49fe26..259071e 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_proc.h b/src/include/catalog/pg_proc.h
index 0a0b2bb..bd67d72 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -1133,20 +1133,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_ _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_ _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_ _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_ _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_ _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_ _null_	box_intersect _null_ _null_ _null_ ));
+DATA(insert OID = 4067 ( 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_ _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_ _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_ _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_ _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_ _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_ _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_ _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_ _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_ _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_ _null_ point_vert _null_ _null_ _null_ ));
@@ -1737,20 +1739,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_ _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_ _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_ _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_ _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_ _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_  _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_  _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_ _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_ _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_ _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_ _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_  _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_  _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_  _null_ lseg_le _null_ _null_ _null_ ));
@@ -2225,20 +2229,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_ _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_ _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_ _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_ _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_ _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_ _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_ _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_ _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_ _null_ inet_same_family _null_ _null_ _null_ ));
+DESCR("are the addresses from the same family?");
+DATA(insert OID = 4063 (  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_ _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_ _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_ _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_ _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_ _null_ inet_gist_decompress _null_ _null_ _null_ ));
 DESCR("GiST support");
@@ -4930,20 +4938,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_ _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_ _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_ _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_ _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_ _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_ _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_ _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_ _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_ _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_ _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_ _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_ _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_ _null_ range_gt _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 33a453f..e8104f0 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 2a91620..4377baa 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -295,20 +295,22 @@ 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 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);
+extern Datum point_box(PG_FUNCTION_ARGS);
+extern Datum boxes_bound_box(PG_FUNCTION_ARGS);
 
 /* public path routines */
 extern Datum path_area(PG_FUNCTION_ARGS);
 extern Datum path_in(PG_FUNCTION_ARGS);
 extern Datum path_out(PG_FUNCTION_ARGS);
 extern Datum path_recv(PG_FUNCTION_ARGS);
 extern Datum path_send(PG_FUNCTION_ARGS);
 extern Datum path_n_lt(PG_FUNCTION_ARGS);
 extern Datum path_n_gt(PG_FUNCTION_ARGS);
 extern Datum path_n_eq(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/rangetypes.h b/src/include/utils/rangetypes.h
index 43c80f4..00a3efe 100644
--- a/src/include/utils/rangetypes.h
+++ b/src/include/utils/rangetypes.h
@@ -204,15 +204,16 @@ extern int range_cmp_bound_values(TypeCacheEntry *typcache, RangeBound *b1,
 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_fetch(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/geometry.out b/src/test/regress/expected/geometry.out
index 21ad555..1271395 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -271,20 +271,54 @@ SELECT '' AS twenty, b.f1 / p.f1 AS rotation
         | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
         | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
         | (0.3,0.05),(0.25,0)
         | (-0.3,-0.3),(-0.3,-0.3)
         | (0.12,-0.84),(0.12,-0.84)
         | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
         | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
         | (0.3,0),(0.3,0)
 (20 rows)
 
+SELECT f1::box
+	FROM POINT_TBL;
+          f1           
+-----------------------
+ (0,0),(0,0)
+ (-10,0),(-10,0)
+ (-3,4),(-3,4)
+ (5.1,34.5),(5.1,34.5)
+ (-5,-12),(-5,-12)
+ (10,10),(10,10)
+(6 rows)
+
+SELECT bound_box(a.f1, b.f1)
+	FROM BOX_TBL a, BOX_TBL b;
+      bound_box      
+---------------------
+ (2,2),(0,0)
+ (3,3),(0,0)
+ (2.5,3.5),(0,0)
+ (3,3),(0,0)
+ (3,3),(0,0)
+ (3,3),(1,1)
+ (3,3.5),(1,1)
+ (3,3),(1,1)
+ (2.5,3.5),(0,0)
+ (3,3.5),(1,1)
+ (2.5,3.5),(2.5,2.5)
+ (3,3.5),(2.5,2.5)
+ (3,3),(0,0)
+ (3,3),(1,1)
+ (3,3.5),(2.5,2.5)
+ (3,3),(3,3)
+(16 rows)
+
 --
 -- Paths
 --
 SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
  eight | npoints |           path            
 -------+---------+---------------------------
        |       2 | [(1,2),(3,4)]
        |       2 | ((1,2),(3,4))
        |       4 | [(0,0),(3,0),(4,5),(1,6)]
        |       2 | ((1,2),(3,4))
diff --git a/src/test/regress/expected/geometry_1.out b/src/test/regress/expected/geometry_1.out
index 65037dc..fad246c 100644
--- a/src/test/regress/expected/geometry_1.out
+++ b/src/test/regress/expected/geometry_1.out
@@ -271,20 +271,54 @@ SELECT '' AS twenty, b.f1 / p.f1 AS rotation
         | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
         | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
         | (0.3,0.05),(0.25,0)
         | (-0.3,-0.3),(-0.3,-0.3)
         | (0.12,-0.84),(0.12,-0.84)
         | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
         | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
         | (0.3,0),(0.3,0)
 (20 rows)
 
+SELECT f1::box
+	FROM POINT_TBL;
+          f1           
+-----------------------
+ (0,0),(0,0)
+ (-10,0),(-10,0)
+ (-3,4),(-3,4)
+ (5.1,34.5),(5.1,34.5)
+ (-5,-12),(-5,-12)
+ (10,10),(10,10)
+(6 rows)
+
+SELECT bound_box(a.f1, b.f1)
+	FROM BOX_TBL a, BOX_TBL b;
+      bound_box      
+---------------------
+ (2,2),(0,0)
+ (3,3),(0,0)
+ (2.5,3.5),(0,0)
+ (3,3),(0,0)
+ (3,3),(0,0)
+ (3,3),(1,1)
+ (3,3.5),(1,1)
+ (3,3),(1,1)
+ (2.5,3.5),(0,0)
+ (3,3.5),(1,1)
+ (2.5,3.5),(2.5,2.5)
+ (3,3.5),(2.5,2.5)
+ (3,3),(0,0)
+ (3,3),(1,1)
+ (3,3.5),(2.5,2.5)
+ (3,3),(3,3)
+(16 rows)
+
 --
 -- Paths
 --
 SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
  eight | npoints |           path            
 -------+---------+---------------------------
        |       2 | [(1,2),(3,4)]
        |       2 | ((1,2),(3,4))
        |       4 | [(0,0),(3,0),(4,5),(1,6)]
        |       2 | ((1,2),(3,4))
diff --git a/src/test/regress/expected/geometry_2.out b/src/test/regress/expected/geometry_2.out
index 1878a37..c938e66 100644
--- a/src/test/regress/expected/geometry_2.out
+++ b/src/test/regress/expected/geometry_2.out
@@ -271,20 +271,54 @@ SELECT '' AS twenty, b.f1 / p.f1 AS rotation
         | (0.109762715209,-0.0562379754329),(0.0813970697055,-0.0604311578117)
         | (-0.251479289941,0.103550295858),(-0.322485207101,0.0739644970414)
         | (0.3,0.05),(0.25,0)
         | (-0.3,-0.3),(-0.3,-0.3)
         | (0.12,-0.84),(0.12,-0.84)
         | (0.0976764836466,-0.072517389374),(0.0976764836466,-0.072517389374)
         | (-0.301775147929,0.12426035503),(-0.301775147929,0.12426035503)
         | (0.3,0),(0.3,0)
 (20 rows)
 
+SELECT f1::box
+	FROM POINT_TBL;
+          f1           
+-----------------------
+ (0,0),(0,0)
+ (-10,0),(-10,0)
+ (-3,4),(-3,4)
+ (5.1,34.5),(5.1,34.5)
+ (-5,-12),(-5,-12)
+ (10,10),(10,10)
+(6 rows)
+
+SELECT bound_box(a.f1, b.f1)
+	FROM BOX_TBL a, BOX_TBL b;
+      bound_box      
+---------------------
+ (2,2),(0,0)
+ (3,3),(0,0)
+ (2.5,3.5),(0,0)
+ (3,3),(0,0)
+ (3,3),(0,0)
+ (3,3),(1,1)
+ (3,3.5),(1,1)
+ (3,3),(1,1)
+ (2.5,3.5),(0,0)
+ (3,3.5),(1,1)
+ (2.5,3.5),(2.5,2.5)
+ (3,3.5),(2.5,2.5)
+ (3,3),(0,0)
+ (3,3),(1,1)
+ (3,3.5),(2.5,2.5)
+ (3,3),(3,3)
+(16 rows)
+
 --
 -- Paths
 --
 SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
  eight | npoints |           path            
 -------+---------+---------------------------
        |       2 | [(1,2),(3,4)]
        |       2 | ((1,2),(3,4))
        |       4 | [(0,0),(3,0),(4,5),(1,6)]
        |       2 | ((1,2),(3,4))
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index d25e5e4..9447e03 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -607,10 +607,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/rangetypes.out b/src/test/regress/expected/rangetypes.out
index 8654e03..23cdbc3 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/geometry.sql b/src/test/regress/sql/geometry.sql
index af7f8a5..1429ee7 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -72,20 +72,26 @@ SELECT '' AS twentyfour, b.f1 - p.f1 AS translation
    FROM BOX_TBL b, POINT_TBL p;
 
 -- scaling and rotation
 SELECT '' AS twentyfour, b.f1 * p.f1 AS rotation
    FROM BOX_TBL b, POINT_TBL p;
 
 SELECT '' AS twenty, b.f1 / p.f1 AS rotation
    FROM BOX_TBL b, POINT_TBL p
    WHERE (p.f1 <-> point '(0,0)') >= 1;
 
+SELECT f1::box
+	FROM POINT_TBL;
+
+SELECT bound_box(a.f1, b.f1)
+	FROM BOX_TBL a, BOX_TBL b;
+
 --
 -- Paths
 --
 
 SELECT '' AS eight, npoints(f1) AS npoints, f1 AS path FROM PATH_TBL;
 
 SELECT '' AS four, path(f1) FROM POLYGON_TBL;
 
 -- translation
 SELECT '' AS eight, p1.f1 + point '(10,10)' AS dist_add
diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql
index 2034d3e..007741e 100644
--- a/src/test/regress/sql/inet.sql
+++ b/src/test/regress/sql/inet.sql
@@ -109,10 +109,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/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index af13352..6d2696f 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));
-- 
2.3.2

