]> granicus.if.org Git - postgresql/commitdiff
Add geometry/range functions to support BRIN inclusion
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 5 May 2015 18:22:24 +0000 (15:22 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 5 May 2015 18:22:24 +0000 (15:22 -0300)
This commit adds the following functions:
    box(point) -> box
    bound_box(box, box) -> box
    inet_same_family(inet, inet) -> bool
    inet_merge(inet, inet) -> cidr
    range_merge(anyrange, anyrange) -> anyrange

The first of these is also used to implement a new assignment cast from
point to box.

These functions are the first part of a base to implement an "inclusion"
operator class for BRIN, for multidimensional data types.

Author: Emre Hasegeli
Reviewed by: Andreas Karlsson

18 files changed:
doc/src/sgml/func.sgml
src/backend/utils/adt/geo_ops.c
src/backend/utils/adt/network.c
src/backend/utils/adt/rangetypes.c
src/include/catalog/catversion.h
src/include/catalog/pg_cast.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/include/utils/geo_decls.h
src/include/utils/rangetypes.h
src/test/regress/expected/geometry.out
src/test/regress/expected/geometry_1.out
src/test/regress/expected/geometry_2.out
src/test/regress/expected/inet.out
src/test/regress/expected/rangetypes.out
src/test/regress/sql/geometry.sql
src/test/regress/sql/inet.sql
src/test/regress/sql/rangetypes.sql

index e6f2129f38674a81301c4d99b73203a8ad341914..fb397316048cca72b6293b466760f08b58e4f207 100644 (file)
@@ -8295,6 +8295,12 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
         <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>
@@ -8307,6 +8313,12 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
         <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>
@@ -8734,6 +8746,30 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
         <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>
@@ -12090,6 +12126,17 @@ NULL baz</literallayout>(3 rows)</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>
index 6cb6be5c5fd0f87a88240d86d7cb0ea9f4812508..39a78552410b44c60da235ca28526576c9022eca 100644 (file)
@@ -4227,6 +4227,45 @@ box_div(PG_FUNCTION_ARGS)
        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);
+}
+
 
 /***********************************************************************
  **
index 3a705da6197b1ff30f2863b9ea6f51fac3494b10..1f8469a2cbcd222ed08f21ff29f1e7e78b778267 100644 (file)
@@ -887,6 +887,58 @@ network_hostmask(PG_FUNCTION_ARGS)
        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
index c037b05f93303df335cfc29b64d333110eb1b3b7..aaf4cb68109a3604797abfb47d215e98c9fc0a70 100644 (file)
@@ -1006,13 +1006,14 @@ range_minus(PG_FUNCTION_ARGS)
        PG_RETURN_NULL();
 }
 
-/* set union */
-Datum
-range_union(PG_FUNCTION_ARGS)
+/*
+ * Set union.  If strict is true, it is an error that the two input ranges
+ * are not adjacent or overlapping.
+ */
+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,
@@ -1026,19 +1027,18 @@ range_union(PG_FUNCTION_ARGS)
        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")));
@@ -1053,7 +1053,35 @@ range_union(PG_FUNCTION_ARGS)
        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));
+}
+
+/*
+ * range merge: like set union, except also allow and account for non-adjacent
+ * input ranges.
+ */
+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 */
index e8334025e141aeb44f98ecb119039800312f671d..e8320daedbb10e944e9ba2cc82c10bd74d564f56 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201504291
+#define CATALOG_VERSION_NO     201505051
 
 #endif
index c49fe263bbfe6c644994d9cf46d27302a7767961..259071ed2a97efd5f0037c8bbf3e72bdde67441e 100644 (file)
@@ -273,6 +273,7 @@ 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 ));
index 0a0b2bbdd29ceb77e5dda2ae506e22e3bc807959..bd67d727979dc17c0732331ff2e223bceaf6e1c4 100644 (file)
@@ -1140,6 +1140,8 @@ DATA(insert OID = 978 (  box_distance        PGNSP PGUID 12 1 0 0 0 f f f f t f i 2
 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_ ));
@@ -1744,6 +1746,8 @@ 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_ ));
@@ -2232,6 +2236,10 @@ DATA(insert OID = 2630 (  inetpl                 PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 869
 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_ ));
@@ -4937,6 +4945,8 @@ DATA(insert OID = 3866 (  range_overright PGNSP PGUID 12 1 0 0 0 f f f f t f i 2
 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_ ));
index 33a453f6020d2fc132794788f2f0c5b1e5a09f63..e8104f01a137e73c8971741a7329b722098ec9b1 100644 (file)
@@ -942,6 +942,8 @@ 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);
index 2a91620db7463aca0751bc54f3334b43103f77b9..4377baa645ed26529c1170c9664bfb3b9eb85e40 100644 (file)
@@ -302,6 +302,8 @@ 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);
index 43c80f493c8a817f131a9ca17c552f3feb7964a4..00a3efedc6d3b105f156f4818ba861d47f89f203 100644 (file)
@@ -211,6 +211,7 @@ 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);
index 21ad555c79843230d07306f9ed435c74bf95390b..1271395d4ead3272c297c5480250909039c0b66e 100644 (file)
@@ -278,6 +278,40 @@ SELECT '' AS twenty, b.f1 / p.f1 AS rotation
         | (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
 --
index 65037dc8b03f30b335d8f9f993b234869e667ef5..fad246c2b933148628ea07474e394c105300f61a 100644 (file)
@@ -278,6 +278,40 @@ SELECT '' AS twenty, b.f1 / p.f1 AS rotation
         | (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
 --
index 1878a37b33ce20d61f834183626c0b48f5225aab..c938e66418a7a6a745eca34a4519652d2371a703 100644 (file)
@@ -278,6 +278,40 @@ SELECT '' AS twenty, b.f1 / p.f1 AS rotation
         | (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
 --
index d25e5e42a79cad98f5a7d277cafa416710fbd67d..9447e03ab562205791818d34d65fa8104b84c132 100644 (file)
@@ -614,3 +614,31 @@ SELECT '127::1'::inet - '127::2'::inet;
        -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)
+
index 8654e031dae40d49864e6919104be34faf8a05be..23cdbc3902b00b5c822293d981db8415e1c3038a 100644 (file)
@@ -480,8 +480,26 @@ select numrange(1.0, 2.0) + numrange(1.5, 3.0);
  [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? 
 ----------
index af7f8a51cc7e22309a363df53932871231d17394..1429ee772a37676686a894425f173e8d4526f32b 100644 (file)
@@ -79,6 +79,12 @@ 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
 --
index 2034d3e86f643765b178180ce29ddac777b9fbf1..007741e9359b44c4aa7e1e0f4d328912f899ba6f 100644 (file)
@@ -116,3 +116,10 @@ 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);
index af1335264dc99939b8a807684ee2d301810c9dfc..6d2696f7bf2b1bfcb08536a61167f0ffff39a216 100644 (file)
@@ -108,7 +108,11 @@ 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);