Fix handling of EMPTY geometries in btree operator
authorSandro Santilli <strk@kbt.io>
Fri, 23 Jun 2017 14:47:13 +0000 (14:47 +0000)
committerSandro Santilli <strk@kbt.io>
Fri, 23 Jun 2017 14:47:13 +0000 (14:47 +0000)
Includes regress test

See #3777

git-svn-id: http://svn.osgeo.org/postgis/trunk@15447 b70326c6-7e19-0410-871a-916f4a2858ee

postgis/lwgeom_btree.c
regress/operators.sql
regress/operators_expected

index 328ee5c27143291977c01efae1ac11c2a3d99a34..062d1cd83f189e5603b08184252e482c29e14895 100644 (file)
@@ -53,6 +53,7 @@ Datum lwgeom_lt(PG_FUNCTION_ARGS)
        GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
        GBOX box1;
        GBOX box2;
+       bool empty1, empty2;
 
        POSTGIS_DEBUG(2, "lwgeom_lt called");
 
@@ -60,14 +61,19 @@ Datum lwgeom_lt(PG_FUNCTION_ARGS)
 
        POSTGIS_DEBUG(3, "lwgeom_lt passed getSRID test");
 
-       gserialized_get_gbox_p(geom1, &box1);
-       gserialized_get_gbox_p(geom2, &box2);
+       empty1 = ( gserialized_get_gbox_p(geom1, &box1) == LW_FAILURE );
+       empty2 = ( gserialized_get_gbox_p(geom2, &box2) == LW_FAILURE );
 
        PG_FREE_IF_COPY(geom1, 0);
        PG_FREE_IF_COPY(geom2, 1);
 
        POSTGIS_DEBUG(3, "lwgeom_lt getbox2d_p passed");
 
+       if  ( empty1 != empty2 )
+       {
+               PG_RETURN_BOOL(FALSE);
+       }
+
        if  ( ! FPeq(box1.xmin , box2.xmin) )
        {
                if  (box1.xmin < box2.xmin)
@@ -102,17 +108,23 @@ Datum lwgeom_le(PG_FUNCTION_ARGS)
        GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
        GBOX box1;
        GBOX box2;
+       bool empty1, empty2;
 
        POSTGIS_DEBUG(2, "lwgeom_le called");
 
        error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2));
 
-       gserialized_get_gbox_p(geom1, &box1);
-       gserialized_get_gbox_p(geom2, &box2);
+       empty1 = ( gserialized_get_gbox_p(geom1, &box1) == LW_FAILURE );
+       empty2 = ( gserialized_get_gbox_p(geom2, &box2) == LW_FAILURE );
 
        PG_FREE_IF_COPY(geom1, 0);
        PG_FREE_IF_COPY(geom2, 1);
 
+       if  ( empty1 != empty2 )
+       {
+               PG_RETURN_BOOL(FALSE);
+       }
+
        if  ( ! FPeq(box1.xmin , box2.xmin) )
        {
                if  (box1.xmin < box2.xmin)
@@ -168,9 +180,10 @@ Datum lwgeom_eq(PG_FUNCTION_ARGS)
 
        gbox_init(&box1);
        gbox_init(&box2);
-       
+
        empty1 = ( gserialized_get_gbox_p(geom1, &box1) == LW_FAILURE );
        empty2 = ( gserialized_get_gbox_p(geom2, &box2) == LW_FAILURE );
+
        PG_FREE_IF_COPY(geom1, 0);
        PG_FREE_IF_COPY(geom2, 1);
 
@@ -198,17 +211,23 @@ Datum lwgeom_ge(PG_FUNCTION_ARGS)
        GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
        GBOX box1;
        GBOX box2;
+       bool empty1, empty2;
 
        POSTGIS_DEBUG(2, "lwgeom_ge called");
 
        error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2));
 
-       gserialized_get_gbox_p(geom1, &box1);
-       gserialized_get_gbox_p(geom2, &box2);
+       empty1 = ( gserialized_get_gbox_p(geom1, &box1) == LW_FAILURE );
+       empty2 = ( gserialized_get_gbox_p(geom2, &box2) == LW_FAILURE );
 
        PG_FREE_IF_COPY(geom1, 0);
        PG_FREE_IF_COPY(geom2, 1);
 
+       if  ( empty1 != empty2 )
+       {
+               PG_RETURN_BOOL(FALSE);
+       }
+
        if  ( ! FPeq(box1.xmin , box2.xmin) )
        {
                if  (box1.xmin > box2.xmin)
@@ -255,17 +274,23 @@ Datum lwgeom_gt(PG_FUNCTION_ARGS)
        GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
        GBOX box1;
        GBOX box2;
+       bool empty1, empty2;
 
        POSTGIS_DEBUG(2, "lwgeom_gt called");
 
        error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2));
 
-       gserialized_get_gbox_p(geom1, &box1);
-       gserialized_get_gbox_p(geom2, &box2);
+       empty1 = ( gserialized_get_gbox_p(geom1, &box1) == LW_FAILURE );
+       empty2 = ( gserialized_get_gbox_p(geom2, &box2) == LW_FAILURE );
 
        PG_FREE_IF_COPY(geom1, 0);
        PG_FREE_IF_COPY(geom2, 1);
 
+       if  ( empty1 != empty2 )
+       {
+               PG_RETURN_BOOL(FALSE);
+       }
+
        if  ( ! FPeq(box1.xmin , box2.xmin) )
        {
                if  (box1.xmin > box2.xmin)
@@ -308,17 +333,23 @@ Datum lwgeom_cmp(PG_FUNCTION_ARGS)
        GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
        GBOX box1;
        GBOX box2;
+       bool empty1, empty2;
 
        POSTGIS_DEBUG(2, "lwgeom_cmp called");
 
        error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2));
 
-       gserialized_get_gbox_p(geom1, &box1);
-       gserialized_get_gbox_p(geom2, &box2);
+       empty1 = ( gserialized_get_gbox_p(geom1, &box1) == LW_FAILURE );
+       empty2 = ( gserialized_get_gbox_p(geom2, &box2) == LW_FAILURE );
 
        PG_FREE_IF_COPY(geom1, 0);
        PG_FREE_IF_COPY(geom2, 1);
 
+       if  ( empty1 != empty2 )
+       {
+               PG_RETURN_BOOL(FALSE);
+       }
+
        if  ( ! FPeq(box1.xmin , box2.xmin) )
        {
                if  (box1.xmin < box2.xmin)
index 1306700a0ae2954881ea0b702d26a9d9c96dbaea..5a2113dd12e09d0de71528aed527be2fb4a81772 100644 (file)
@@ -140,4 +140,15 @@ WITH v(i,g) AS ( VALUES
 SELECT 'ndovm2', array_agg(i) FROM v WHERE g &&& 'POINTZ(0 0 1)'::geometry
 ORDER BY 1;
 
+-- GROUP BY on empty
+SELECT '#3777', ST_AsText(geom), count(*) FROM (
+SELECT 'POINT(0 0)'::geometry geom UNION ALL
+SELECT 'POINT(0 0)'::geometry UNION ALL
+SELECT 'POINT(0 0)'::geometry UNION ALL
+SELECT 'POINT(0 1)'::geometry UNION ALL
+SELECT 'LINESTRING(0 0,0 1)'::geometry UNION ALL
+SELECT 'GEOMETRYCOLLECTION EMPTY'::geometry UNION ALL
+SELECT 'POINT EMPTY'::geometry
+) foo
+GROUP BY geom ORDER BY 2;
 
index c1539e6e4fcc0564043276d2f24f19b02aec6838..b5b3761aa06c700a3b63df8669671f4616e23f57 100644 (file)
@@ -56,3 +56,7 @@ ndov6|t
 ndov7|t
 ndovm1|{1,2,3,4,5,8}
 ndovm2|{1,2,4,6,7}
+#3777|GEOMETRYCOLLECTION EMPTY|2
+#3777|LINESTRING(0 0,0 1)|1
+#3777|POINT(0 0)|3
+#3777|POINT(0 1)|1