diff options
author | Anel Husakovic <anel@mariadb.org> | 2020-10-29 01:40:31 +0100 |
---|---|---|
committer | Anel Husakovic <anel@mariadb.org> | 2021-03-27 10:42:39 +0100 |
commit | 6769d1a0782f140dcd12c9ced6fda34ac0e41d85 (patch) | |
tree | 496207894596a5fbd77a23ba313f8e15ff16b87e | |
parent | 48141f3c1787de941d969ad1e6675611b2b650c2 (diff) | |
download | mariadb-git-6769d1a0782f140dcd12c9ced6fda34ac0e41d85.tar.gz |
MDEV-13467: Feature request: Support for ST_Distance_Sphere()
- Cherry-pick 51e48b9f8981 - vscode gitignore
- Thanks Robin Dupret for the review.
Reviewed by:daniel@mariadb.org
holyfoot@mariadb.com
-rw-r--r-- | .gitignore | 10 | ||||
-rw-r--r-- | mysql-test/r/gis-precise.result | 111 | ||||
-rw-r--r-- | mysql-test/suite/innodb_gis/t/1.test | 13 | ||||
-rw-r--r-- | mysql-test/suite/innodb_gis/t/bug16236208.test | 1 | ||||
-rw-r--r-- | mysql-test/suite/innodb_gis/t/create_spatial_index.test | 1 | ||||
-rw-r--r-- | mysql-test/suite/innodb_gis/t/gis.test | 13 | ||||
-rw-r--r-- | mysql-test/suite/innodb_gis/t/precise.test | 2 | ||||
-rw-r--r-- | mysql-test/suite/innodb_gis/t/rtree.test | 6 | ||||
-rw-r--r-- | mysql-test/t/gis-precise.test | 78 | ||||
-rw-r--r-- | sql/item_create.cc | 36 | ||||
-rw-r--r-- | sql/item_geofunc.cc | 142 | ||||
-rw-r--r-- | sql/item_geofunc.h | 14 | ||||
-rw-r--r-- | sql/spatial.cc | 188 | ||||
-rw-r--r-- | sql/spatial.h | 22 |
14 files changed, 598 insertions, 39 deletions
diff --git a/.gitignore b/.gitignore index 8477515105b..00754884d3d 100644 --- a/.gitignore +++ b/.gitignore @@ -507,3 +507,13 @@ FakesAssemblies/ # QtCreator && CodeBlocks *.cbp +compile_commands.json +.clang-format +.kscope/ +.vimrc +.editorconfig +.kateconfig +*.kdev4 + +# Visual Studio Code workspace +.vscode/ diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result index d5e1751d800..aaeb6e852a1 100644 --- a/mysql-test/r/gis-precise.result +++ b/mysql-test/r/gis-precise.result @@ -807,3 +807,114 @@ SRID(GEOMETRYFROMTEXT(' MULTIPOINT(8 4,5 0,7 8,6 9,3 4,7 3,5 5) ')))); ASTEXT(ST_BUFFER(POLYGONFROMTEXT(' POLYGON((9 9,5 2,4 5,9 9))'), SRID(GEOMETRYFROMTEXT(' MULTIPOINT(8 4,5 0,7 8,6 9,3 4,7 3,5 5) ')))) POLYGON((9 9,5 2,4 5,9 9)) +# +# MDEV-13467 Feature request: Support for ST_Distance_Sphere() +# +SELECT ST_DISTANCE_SPHERE(); +ERROR 42000: Incorrect parameter count in the call to native function 'ST_DISTANCE_SPHERE' +SELECT ST_DISTANCE_SPHERE(NULL); +ERROR 42000: Incorrect parameter count in the call to native function 'ST_DISTANCE_SPHERE' +SELECT ST_DISTANCE_SPHERE(NULL, NULL); +ST_DISTANCE_SPHERE(NULL, NULL) +NULL +SELECT ST_DISTANCE_SPHERE(NULL, NULL, 3); +ST_DISTANCE_SPHERE(NULL, NULL, 3) +NULL +SELECT ST_DISTANCE_SPHERE(NULL, 1, 3); +ST_DISTANCE_SPHERE(NULL, 1, 3) +NULL +SELECT ST_DISTANCE_SPHERE(1, NULL, 3); +ST_DISTANCE_SPHERE(1, NULL, 3) +NULL +SELECT ST_DISTANCE_SPHERE(1, 1); +ERROR 22023: Invalid GIS data provided to function ST_Distance_Sphere. +SELECT ST_DISTANCE_SPHERE(1, 1, 3); +ERROR 22023: Invalid GIS data provided to function ST_Distance_Sphere. +SELECT ST_DISTANCE_SPHERE(1, 1, NULL); +ST_DISTANCE_SPHERE(1, 1, NULL) +NULL +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(1 0)'), ST_GEOMFROMTEXT('LINESTRING(0 0, 1 1)')); +ERROR HY000: Internal error: st_distance_sphere +# Test Points and radius +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('POINT(1 1)')); +ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('POINT(1 1)')) +157249.0357231545 +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(-1 -1)'), ST_GEOMFROMTEXT('POINT(-2 -2)')), 10); +TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(-1 -1)'), ST_GEOMFROMTEXT('POINT(-2 -2)')), 10) +157225.0865419108 +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('POINT(1 1)'), 1); +ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('POINT(1 1)'), 1) +0.024682056391766436 +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('POINT(1 1)'), 0); +ERROR HY000: Internal error: Radius must be greater than zero. +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('POINT(1 1)'), -1); +ERROR HY000: Internal error: Radius must be greater than zero. +# Test longitude/lattitude +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 1)'), ST_GEOMFROMTEXT('POINT(1 2)')), 10); +TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 1)'), ST_GEOMFROMTEXT('POINT(1 2)')), 10) +157225.0865419108 +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 1)'), ST_GEOMFROMTEXT('POINT(2 1)')), 10); +TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 1)'), ST_GEOMFROMTEXT('POINT(2 1)')), 10) +222355.4901806686 +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(1 0)'), ST_GEOMFROMTEXT('POINT(1 2)')), 10); +TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(1 0)'), ST_GEOMFROMTEXT('POINT(1 2)')), 10) +222389.3645969269 +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(1 0)'), ST_GEOMFROMTEXT('POINT(2 1)')); +ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(1 0)'), ST_GEOMFROMTEXT('POINT(2 1)')) +157249.0357231545 +# Test Points - Multipoints +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(1 1)')); +ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(1 1)')) +157249.0357231545 +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 1)'), ST_GEOMFROMTEXT('POINT(0 0)')); +ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 1)'), ST_GEOMFROMTEXT('POINT(0 0)')) +157249.0357231545 +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(1 1,2 2)')); +ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(1 1,2 2)')) +157249.0357231545 +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(2 2,1 1)')); +ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(2 2,1 1)')) +157249.0357231545 +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(1 1,2 2)'), 1); +ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(1 1,2 2)'), 1) +0.024682056391766436 +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(2 2,1 1)'), 1); +ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(2 2,1 1)'), 1) +0.024682056391766436 +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(2 2, 1 1, 3 4)'), 1); +ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(2 2, 1 1, 3 4)'), 1) +0.024682056391766436 +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(2 2, 1 1,5 6)'), 1); +ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(2 2, 1 1,5 6)'), 1) +0.024682056391766436 +# Test Multipoints - Multipoints +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(3 4,8 9 )'), ST_GEOMFROMTEXT('MULTIPOINT(3 4,8 9 )')); +ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(3 4,8 9 )'), ST_GEOMFROMTEXT('MULTIPOINT(3 4,8 9 )')) +0 +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 2,1 1 )'), ST_GEOMFROMTEXT('MULTIPOINT(3 4,8 9 )')), 10); +TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 2,1 1 )'), ST_GEOMFROMTEXT('MULTIPOINT(3 4,8 9 )')), 10) +314282.5644496733 +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 2,1 1 )'), ST_GEOMFROMTEXT('MULTIPOINT(8 9,3 4 )')), 10); +TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 2,1 1 )'), ST_GEOMFROMTEXT('MULTIPOINT(8 9,3 4 )')), 10) +314282.5644496733 +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 2,1 1 )'), ST_GEOMFROMTEXT('MULTIPOINT(8 9,3 4 )'),1), 17); +TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 2,1 1 )'), ST_GEOMFROMTEXT('MULTIPOINT(8 9,3 4 )'),1), 17) +0.04933028646581131 +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 2,1 1 )'), ST_GEOMFROMTEXT('MULTIPOINT(8 9,3 4 )'),0); +ERROR HY000: Internal error: Radius must be greater than zero. +set @pt1 = ST_GeomFromText('POINT(190 -30)'); +set @pt2 = ST_GeomFromText('POINT(-30 50)'); +SELECT ST_Distance_Sphere(@pt1, @pt2); +ERROR HY000: Out of range error: Longitude should be [-180,180] in function ST_Distance_Sphere. +set @pt1 = ST_GeomFromText('POINT(135 -30)'); +set @pt2 = ST_GeomFromText('POINT(-30 91)'); +SELECT ST_Distance_Sphere(@pt1, @pt2); +ERROR HY000: Out of range error: Latitude should be [-90,90] in function ST_Distance_Sphere. +set @zenica = ST_GeomFromText('POINT(17.907743 44.203438)'); +set @sarajevo = ST_GeomFromText('POINT(18.413076 43.856258)'); +SELECT TRUNCATE(ST_Distance_Sphere(@zenica, @sarajevo), 10); +TRUNCATE(ST_Distance_Sphere(@zenica, @sarajevo), 10) +55878.5933759170 +SELECT TRUNCATE(ST_Distance_Sphere(@sarajevo, @zenica), 10); +TRUNCATE(ST_Distance_Sphere(@sarajevo, @zenica), 10) +55878.5933759170 diff --git a/mysql-test/suite/innodb_gis/t/1.test b/mysql-test/suite/innodb_gis/t/1.test index 256cd1ab0ad..0e5fba6fc34 100644 --- a/mysql-test/suite/innodb_gis/t/1.test +++ b/mysql-test/suite/innodb_gis/t/1.test @@ -393,7 +393,6 @@ insert into t1 values (1); insert into t1 values (1.11); --error 1416 insert into t1 values ("qwerty"); -# --error ER_GIS_INVALID_DATA --error ER_BAD_NULL_ERROR insert into t1 values (ST_pointfromtext('point(1,1)')); @@ -437,7 +436,6 @@ select ST_y(b) IS NULL from t1; -# --error ER_GIS_INVALID_DATA select MBRwithin(b, b) IS NULL, MBRcontains(b, b) IS NULL, MBRoverlaps(b, b) IS NULL, MBRequals(b, b) IS NULL, MBRdisjoint(b, b) IS NULL, ST_touches(b, b) IS NULL, @@ -466,7 +464,6 @@ DROP TABLE t1; # CREATE TABLE `t1` ( `col9` set('a'), `col89` date); INSERT IGNORE INTO `t1` VALUES ('','0000-00-00'); -# --error ER_GIS_INVALID_DATA select ST_geomfromtext(col9,col89) as a from t1; DROP TABLE t1; @@ -623,17 +620,11 @@ SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS MBRwithin FROM t1 a1 JOIN # MBROverlaps needs a few more tests, with point and line dimensions -# --error ER_GIS_INVALID_DATA SET @vert1 = ST_GeomFromText('POLYGON ((0 -2, 0 2, 0 -2))'); -# --error ER_GIS_INVALID_DATA SET @horiz1 = ST_GeomFromText('POLYGON ((-2 0, 2 0, -2 0))'); -# --error ER_GIS_INVALID_DATA SET @horiz2 = ST_GeomFromText('POLYGON ((-1 0, 3 0, -1 0))'); -# --error ER_GIS_INVALID_DATA SET @horiz3 = ST_GeomFromText('POLYGON ((2 0, 3 0, 2 0))'); -# --error ER_GIS_INVALID_DATA SET @point1 = ST_GeomFromText('POLYGON ((0 0))'); -# --error ER_GIS_INVALID_DATA SET @point2 = ST_GeomFromText('POLYGON ((-2 0))'); SELECT GROUP_CONCAT(a1.name ORDER BY a1.name) AS MBRoverlaps FROM t1 a1 WHERE MBROverlaps(a1.square, @vert1) GROUP BY a1.name; @@ -772,10 +763,8 @@ SELECT 1 FROM (SELECT GREATEST(1,GEOMETRYCOLLECTION('00000','00000')) b FROM DUA --echo # BUG#51875: crash when loading data into geometry function ST_polyfromwkb --echo # SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; -# --error ER_GIS_INVALID_DATA SET @a=ST_POLYFROMWKB(@a); SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; -# --error ER_GIS_INVALID_DATA SET @a=ST_POLYFROMWKB(@a); @@ -899,7 +888,6 @@ DROP TABLE g1; CREATE TABLE g1(a TEXT NOT NULL, KEY(a(255))); INSERT INTO g1 VALUES ('a'),('a'); -# --error ER_GIS_INVALID_DATA SELECT 1 FROM g1 WHERE a >= ANY (SELECT 1 FROM g1 WHERE a = ST_geomfromtext('') OR a) ; @@ -1447,5 +1435,4 @@ DROP DATABASE gis_ogs; --echo # Bug#13362660 ASSERTION `FIELD_POS < FIELD_COUNT' FAILED. IN PROTOCOL_TEXT::STORE --echo # -# --error ER_GIS_INVALID_DATA SELECT ST_Union('', ''), md5(1); diff --git a/mysql-test/suite/innodb_gis/t/bug16236208.test b/mysql-test/suite/innodb_gis/t/bug16236208.test index b55ab1d0fd3..3a1fbefc52c 100644 --- a/mysql-test/suite/innodb_gis/t/bug16236208.test +++ b/mysql-test/suite/innodb_gis/t/bug16236208.test @@ -47,7 +47,6 @@ ST_GeomFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')); CREATE INDEX linestring_index ON linestring(linestring_nokey(5)); ALTER TABLE linestring ADD KEY (linestring_key(5)); -# --error ER_GIS_INVALID_DATA SELECT ST_AsText(linestring_nokey) FROM linestring FORCE KEY ( linestring_key ) WHERE ST_CONTAINS( ST_GeomFromText('POLYGON( ( 3923 2815 , 4246 2122 , 4028 2971 , 4017 3019 , 3923 2815 ) )') , linestring_key ) AND diff --git a/mysql-test/suite/innodb_gis/t/create_spatial_index.test b/mysql-test/suite/innodb_gis/t/create_spatial_index.test index 6a15b0f2d74..1c0a7e7aaa7 100644 --- a/mysql-test/suite/innodb_gis/t/create_spatial_index.test +++ b/mysql-test/suite/innodb_gis/t/create_spatial_index.test @@ -1141,7 +1141,6 @@ insert into `t1` values( linestring(point(1,1),point(1,1)) ); -# --error ER_GIS_INVALID_DATA --error ER_BAD_NULL_ERROR insert into `t1` values ( diff --git a/mysql-test/suite/innodb_gis/t/gis.test b/mysql-test/suite/innodb_gis/t/gis.test index 489934e957e..ba1b3b12ec2 100644 --- a/mysql-test/suite/innodb_gis/t/gis.test +++ b/mysql-test/suite/innodb_gis/t/gis.test @@ -388,7 +388,6 @@ insert into t1 values (1.11); --error 1416 insert into t1 values ("qwerty"); --error 1048 -# --error ER_GIS_INVALID_DATA insert into t1 values (ST_pointfromtext('point(1,1)')); drop table t1; @@ -431,7 +430,6 @@ select ST_y(b) IS NULL from t1; -# --error ER_GIS_INVALID_DATA select MBRwithin(b, b) IS NULL, MBRcontains(b, b) IS NULL, MBRoverlaps(b, b) IS NULL, MBRequals(b, b) IS NULL, MBRdisjoint(b, b) IS NULL, ST_touches(b, b) IS NULL, @@ -460,7 +458,6 @@ DROP TABLE t1; # CREATE TABLE `t1` ( `col9` set('a'), `col89` date); INSERT IGNORE INTO `t1` VALUES ('','0000-00-00'); -# --error ER_GIS_INVALID_DATA select ST_geomfromtext(col9,col89) as a from t1; DROP TABLE t1; @@ -617,17 +614,11 @@ SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS MBRwithin FROM t1 a1 JOIN # MBROverlaps needs a few more tests, with point and line dimensions -# --error ER_GIS_INVALID_DATA SET @vert1 = ST_GeomFromText('POLYGON ((0 -2, 0 2, 0 -2))'); -# --error ER_GIS_INVALID_DATA SET @horiz1 = ST_GeomFromText('POLYGON ((-2 0, 2 0, -2 0))'); -# --error ER_GIS_INVALID_DATA SET @horiz2 = ST_GeomFromText('POLYGON ((-1 0, 3 0, -1 0))'); -# --error ER_GIS_INVALID_DATA SET @horiz3 = ST_GeomFromText('POLYGON ((2 0, 3 0, 2 0))'); -# --error ER_GIS_INVALID_DATA SET @point1 = ST_GeomFromText('POLYGON ((0 0))'); -# --error ER_GIS_INVALID_DATA SET @point2 = ST_GeomFromText('POLYGON ((-2 0))'); SELECT GROUP_CONCAT(a1.name ORDER BY a1.name) AS MBRoverlaps FROM t1 a1 WHERE MBROverlaps(a1.square, @vert1) GROUP BY a1.name; @@ -766,10 +757,8 @@ SELECT 1 FROM (SELECT GREATEST(1,GEOMETRYCOLLECTION('00000','00000')) b FROM DUA --echo # BUG#51875: crash when loading data into geometry function ST_polyfromwkb --echo # SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; -# --error ER_GIS_INVALID_DATA SET @a=ST_POLYFROMWKB(@a); SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; -# --error ER_GIS_INVALID_DATA SET @a=ST_POLYFROMWKB(@a); @@ -901,7 +890,6 @@ DROP TABLE g1; CREATE TABLE g1(a TEXT NOT NULL, KEY(a(255))); INSERT INTO g1 VALUES ('a'),('a'); -# --error ER_GIS_INVALID_DATA SELECT 1 FROM g1 WHERE a >= ANY (SELECT 1 FROM g1 WHERE a = ST_geomfromtext('') OR a) ; @@ -1440,5 +1428,4 @@ DROP DATABASE gis_ogs; --echo # Bug#13362660 ASSERTION `FIELD_POS < FIELD_COUNT' FAILED. IN PROTOCOL_TEXT::STORE --echo # -# --error ER_GIS_INVALID_DATA SELECT ST_Union('', ''), md5(1); diff --git a/mysql-test/suite/innodb_gis/t/precise.test b/mysql-test/suite/innodb_gis/t/precise.test index 9174a100003..3936610530f 100644 --- a/mysql-test/suite/innodb_gis/t/precise.test +++ b/mysql-test/suite/innodb_gis/t/precise.test @@ -122,7 +122,6 @@ SELECT ST_Equals(ST_PointFromText('POINT (12 13)'),ST_PointFromText('POINT (12 1 --echo # BUG#11759650/51979: UNION/INTERSECTION OF POLYGONS CRASHES MYSQL --echo # -# --error ER_GIS_INVALID_DATA SELECT ST_ASTEXT(ST_UNION(ST_GEOMFROMTEXT('POLYGON((525000 183300,525400 183300,525400 18370, 525000 183700,525000 183300))'), ST_geomfromtext('POLYGON((525298.67 183511.53,525296.57 @@ -140,7 +139,6 @@ ST_geomfromtext('POLYGON((525298.67 183511.53,525296.57 183491.55))'))) st_u; SET @a=0x0000000001030000000200000005000000000000000000000000000000000000000000000000002440000000000000000000000000000024400000000000002440000000000000000000000000000024400000000000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000F03F00000000000000400000000000000040000000000000F03F0000000000000040000000000000F03F000000000000F03F; -# --error ER_GIS_INVALID_DATA SELECT ST_ASTEXT(ST_TOUCHES(@a, ST_GEOMFROMTEXT('point(0 0)'))) t; diff --git a/mysql-test/suite/innodb_gis/t/rtree.test b/mysql-test/suite/innodb_gis/t/rtree.test index 58d81576b3e..98931e70e62 100644 --- a/mysql-test/suite/innodb_gis/t/rtree.test +++ b/mysql-test/suite/innodb_gis/t/rtree.test @@ -78,17 +78,11 @@ SELECT name, ST_AsText(square) from t1 where MBRWithin(@p, square); # MBROverlaps needs a few more tests, with point and line dimensions -# --error ER_GIS_INVALID_DATA SET @vert1 = ST_GeomFromText('POLYGON ((0 -2, 0 2, 0 -2))'); -# --error ER_GIS_INVALID_DATA SET @horiz1 = ST_GeomFromText('POLYGON ((-2 0, 2 0, -2 0))'); -# --error ER_GIS_INVALID_DATA SET @horiz2 = ST_GeomFromText('POLYGON ((-1 0, 3 0, -1 0))'); -# --error ER_GIS_INVALID_DATA SET @horiz3 = ST_GeomFromText('POLYGON ((2 0, 3 0, 2 0))'); -# --error ER_GIS_INVALID_DATA SET @point1 = ST_GeomFromText('POLYGON ((0 0))'); -# --error ER_GIS_INVALID_DATA SET @point2 = ST_GeomFromText('POLYGON ((-2 0))'); SELECT GROUP_CONCAT(a1.name ORDER BY a1.name) AS MBRoverlaps FROM t1 a1 WHERE MBROverlaps(a1.square, @vert1) GROUP BY a1.name; diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test index ede535596da..b75318e034b 100644 --- a/mysql-test/t/gis-precise.test +++ b/mysql-test/t/gis-precise.test @@ -393,3 +393,81 @@ with cte1 as( select (st_symdifference(point(1,1),point(1,1))) as a1 ), cte2 a --source include/gis_debug.inc + +--echo # +--echo # MDEV-13467 Feature request: Support for ST_Distance_Sphere() +--echo # + +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT ST_DISTANCE_SPHERE(); +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT ST_DISTANCE_SPHERE(NULL); +SELECT ST_DISTANCE_SPHERE(NULL, NULL); +# NULL args and optional radius will return NULL +SELECT ST_DISTANCE_SPHERE(NULL, NULL, 3); +# At least 1 NULL arg and optional radius will return NULL +SELECT ST_DISTANCE_SPHERE(NULL, 1, 3); +# At least 1 NULL arg and optional radius will return NULL +SELECT ST_DISTANCE_SPHERE(1, NULL, 3); +# Return ER_GIS_INVALID_DATA for invalid geometry +--error ER_GIS_INVALID_DATA +SELECT ST_DISTANCE_SPHERE(1, 1); +--error ER_GIS_INVALID_DATA +SELECT ST_DISTANCE_SPHERE(1, 1, 3); +# Return NULL if radius is NULL +SELECT ST_DISTANCE_SPHERE(1, 1, NULL); +# Wrong geometry +--error ER_INTERNAL_ERROR +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(1 0)'), ST_GEOMFROMTEXT('LINESTRING(0 0, 1 1)')); + +--echo # Test Points and radius +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('POINT(1 1)')); +# make bb x86 happy +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(-1 -1)'), ST_GEOMFROMTEXT('POINT(-2 -2)')), 10); +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('POINT(1 1)'), 1); +--error ER_INTERNAL_ERROR +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('POINT(1 1)'), 0); +--error ER_INTERNAL_ERROR +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('POINT(1 1)'), -1); +--echo # Test longitude/lattitude +# make bb x86 happy +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 1)'), ST_GEOMFROMTEXT('POINT(1 2)')), 10); +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 1)'), ST_GEOMFROMTEXT('POINT(2 1)')), 10); +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(1 0)'), ST_GEOMFROMTEXT('POINT(1 2)')), 10); +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(1 0)'), ST_GEOMFROMTEXT('POINT(2 1)')); +--echo # Test Points - Multipoints +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(1 1)')); +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 1)'), ST_GEOMFROMTEXT('POINT(0 0)')); +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(1 1,2 2)')); +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(2 2,1 1)')); +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(1 1,2 2)'), 1); +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(2 2,1 1)'), 1); +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(2 2, 1 1, 3 4)'), 1); +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('POINT(0 0)'), ST_GEOMFROMTEXT('MULTIPOINT(2 2, 1 1,5 6)'), 1); +--echo # Test Multipoints - Multipoints +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(3 4,8 9 )'), ST_GEOMFROMTEXT('MULTIPOINT(3 4,8 9 )')); +# make bb x86 happy +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 2,1 1 )'), ST_GEOMFROMTEXT('MULTIPOINT(3 4,8 9 )')), 10); +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 2,1 1 )'), ST_GEOMFROMTEXT('MULTIPOINT(8 9,3 4 )')), 10); +# make bb x86 happy +SELECT TRUNCATE(ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 2,1 1 )'), ST_GEOMFROMTEXT('MULTIPOINT(8 9,3 4 )'),1), 17); +--error ER_INTERNAL_ERROR +SELECT ST_DISTANCE_SPHERE(ST_GEOMFROMTEXT('MULTIPOINT(1 2,1 1 )'), ST_GEOMFROMTEXT('MULTIPOINT(8 9,3 4 )'),0); + +# Longitude out of range [-180,180] +set @pt1 = ST_GeomFromText('POINT(190 -30)'); +set @pt2 = ST_GeomFromText('POINT(-30 50)'); +--error ER_STD_OUT_OF_RANGE_ERROR +SELECT ST_Distance_Sphere(@pt1, @pt2); + +# Latitude out of range [-90, 90] +set @pt1 = ST_GeomFromText('POINT(135 -30)'); +set @pt2 = ST_GeomFromText('POINT(-30 91)'); +--error ER_STD_OUT_OF_RANGE_ERROR +SELECT ST_Distance_Sphere(@pt1, @pt2); + +# POINT in form (longitude[-180, 180] latitude[-90, 90]) +set @zenica = ST_GeomFromText('POINT(17.907743 44.203438)'); +set @sarajevo = ST_GeomFromText('POINT(18.413076 43.856258)'); +SELECT TRUNCATE(ST_Distance_Sphere(@zenica, @sarajevo), 10); +SELECT TRUNCATE(ST_Distance_Sphere(@sarajevo, @zenica), 10); diff --git a/sql/item_create.cc b/sql/item_create.cc index 1cf5a06a3a4..4bfb2615fbe 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -202,7 +202,6 @@ public: @return An item representing the function call */ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) = 0; - protected: /** Constructor. */ Create_func_arg2() {} @@ -229,7 +228,6 @@ public: @return An item representing the function call */ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0; - protected: /** Constructor. */ Create_func_arg3() {} @@ -975,6 +973,19 @@ class Create_func_distance : public Create_func_arg2 Create_func_distance() {} virtual ~Create_func_distance() {} }; + + +class Create_func_distance_sphere: public Create_native_func +{ + public: + virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list); + static Create_func_distance_sphere s_singleton; + + protected: + Create_func_distance_sphere() {} + virtual ~Create_func_distance_sphere() {} +}; + #endif @@ -4761,6 +4772,26 @@ Create_func_glength::create_1_arg(THD *thd, Item *arg1) { return new (thd->mem_root) Item_func_glength(thd, arg1); } + + +Create_func_distance_sphere Create_func_distance_sphere::s_singleton; + +Item* +Create_func_distance_sphere::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) +{ + int arg_count= 0; + + if (item_list != NULL) + arg_count= item_list->elements; + + if (arg_count < 2) + { + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); + return NULL; + } + return new (thd->mem_root) Item_func_sphere_distance(thd, *item_list); +} #endif @@ -7051,6 +7082,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_within)}, { { C_STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)}, { { C_STRING_WITH_LEN("ST_Y") }, GEOM_BUILDER(Create_func_y)}, + { { C_STRING_WITH_LEN("ST_DISTANCE_SPHERE") }, GEOM_BUILDER(Create_func_distance_sphere)}, { { C_STRING_WITH_LEN("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)}, { { C_STRING_WITH_LEN("SUBTIME") }, BUILDER(Create_func_subtime)}, { { C_STRING_WITH_LEN("TAN") }, BUILDER(Create_func_tan)}, diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 1c3fafc0582..2b0f67f4ddc 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -2537,11 +2537,151 @@ mem_error: } +double Item_func_sphere_distance::val_real() +{ + /* To test null_value of item, first get well-known bytes as a backups */ + String bak1, bak2; + String *arg1= args[0]->val_str(&bak1); + String *arg2= args[1]->val_str(&bak2); + double distance= 0.0; + double sphere_radius= 6370986.0; // Default radius equals Earth radius + + null_value= (args[0]->null_value || args[1]->null_value); + if (null_value) + { + goto handle_errors; + } + + if (arg_count == 3) + { + sphere_radius= args[2]->val_real(); + // Radius cannot be Null + if (args[2]->null_value) + { + null_value= true; + goto handle_errors; + } + if (sphere_radius <= 0) + { + my_error(ER_INTERNAL_ERROR, MYF(0), "Radius must be greater than zero."); + return 1; + } + } + Geometry_buffer buffer1, buffer2; + Geometry *g1, *g2; + if (!(g1= Geometry::construct(&buffer1, arg1->ptr(), arg1->length())) || + !(g2= Geometry::construct(&buffer2, arg2->ptr(), arg2->length()))) + { + my_error(ER_GIS_INVALID_DATA, MYF(0), "ST_Distance_Sphere"); + goto handle_errors; + } +// Method allowed for points and multipoints + if (!(g1->get_class_info()->m_type_id == Geometry::wkb_point || + g1->get_class_info()->m_type_id == Geometry::wkb_multipoint) || + !(g2->get_class_info()->m_type_id == Geometry::wkb_point || + g2->get_class_info()->m_type_id == Geometry::wkb_multipoint)) + { + // Generate error message in case different geometry is used? + my_error(ER_INTERNAL_ERROR, MYF(0), func_name()); + return 0; + } + distance= spherical_distance_points(g1, g2, sphere_radius); + if (distance < 0) + { + my_error(ER_INTERNAL_ERROR, MYF(0), "Returned distance cannot be negative."); + return 1; + } + return distance; + + handle_errors: + return 0; +} + + +double Item_func_sphere_distance::spherical_distance_points(Geometry *g1, + Geometry *g2, + const double r) +{ + double res= 0.0; + // Length for the single point (25 Bytes) + uint32 len= SRID_SIZE + POINT_DATA_SIZE + WKB_HEADER_SIZE; + int error= 0; + + switch (g2->get_class_info()->m_type_id) + { + case Geometry::wkb_point: + // Optimization for point-point case + if (g1->get_class_info()->m_type_id == Geometry::wkb_point) + { + res= static_cast<Gis_point *>(g2)->calculate_haversine(g1, r, &error); + } + else + { + // Optimization for single point in Multipoint + if (g1->get_data_size() == len) + { + res= static_cast<Gis_point *>(g2)->calculate_haversine(g1, r, &error); + } + else + { + // There are multipoints in g1 + // g1 is MultiPoint and calculate MP.sphericaldistance from g2 Point + if (g1->get_data_size() != GET_SIZE_ERROR) + static_cast<Gis_point *>(g2)->spherical_distance_multipoints( + (Gis_multi_point *)g1, r, &res, &error); + } + } + break; + + case Geometry::wkb_multipoint: + // Optimization for point-point case + if (g1->get_class_info()->m_type_id == Geometry::wkb_point) + { + // Optimization for single point in Multipoint g2 + if (g2->get_data_size() == len) + { + res= static_cast<Gis_point *>(g1)->calculate_haversine(g2, r, &error); + } + else + { + if (g2->get_data_size() != GET_SIZE_ERROR) + // g1 is a point (casted to multi_point) and g2 multipoint + static_cast<Gis_point *>(g1)->spherical_distance_multipoints( + (Gis_multi_point *)g2, r, &res, &error); + } + } + else + { + // Multipoints in g1 and g2 - no optimization + static_cast<Gis_multi_point *>(g1)->spherical_distance_multipoints( + (Gis_multi_point *)g2, r, &res, &error); + } + break; + + default: + DBUG_ASSERT(0); + break; + } + + if (res < 0) + goto handle_error; + + handle_error: + if (error > 0) + my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0), + "Longitude should be [-180,180]", "ST_Distance_Sphere"); + else if(error < 0) + my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0), + "Latitude should be [-90,90]", "ST_Distance_Sphere"); + return res; +} + + String *Item_func_pointonsurface::val_str(String *str) { Gcalc_operation_transporter trn(&func, &collector); - DBUG_ENTER("Item_func_pointonsurface::val_real"); + DBUG_ENTER("Item_func_pointonsurface::val_str"); DBUG_ASSERT(fixed == 1); String *res= args[0]->val_str(&tmp_value); Geometry_buffer buffer; diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index a858a9a2d57..efff940ec4b 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -714,6 +714,20 @@ public: }; +class Item_func_sphere_distance: public Item_real_func +{ + double spherical_distance_points(Geometry *g1, Geometry *g2, + const double sphere_r); +public: + Item_func_sphere_distance(THD *thd, List<Item> &list): + Item_real_func(thd, list) {} + double val_real(); + const char *func_name() const { return "st_distance_sphere"; } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_func_sphere_distance>(thd, mem_root, this); } +}; + + class Item_func_pointonsurface: public Item_geometry_func { String tmp_value; diff --git a/sql/spatial.cc b/sql/spatial.cc index 840f8bd809c..711efa91394 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -1032,6 +1032,119 @@ const Geometry::Class_info *Gis_point::get_class_info() const } +/** + Function to calculate haversine. + Taking as arguments Point and Multipoint geometries. + Multipoint geometry has to be single point only. + It is up to caller to ensure valid input. + + @param g pointer to the Geometry + @param r sphere radius + @param error pointer describing the error in case of the boundary conditions + + @return distance in case without error, it is caclulcated distance (non-negative), + in case error exist, negative value. +*/ +double Gis_point::calculate_haversine(const Geometry *g, + const double sphere_radius, + int *error) +{ + DBUG_ASSERT(sphere_radius > 0); + double x1r, x2r, y1r, y2r, dlong, dlat, res; + + // This check is done only for optimization purposes where we know it will + // be one and only one point in Multipoint + if (g->get_class_info()->m_type_id == Geometry::wkb_multipoint) + { + const char point_size= 4 + WKB_HEADER_SIZE + POINT_DATA_SIZE+1; //1 for the type + char point_temp[point_size]; + memset(point_temp+4, Geometry::wkb_point, 1); + memcpy(point_temp+5, static_cast<const Gis_multi_point *>(g)->get_data_ptr()+5, 4); + memcpy(point_temp+4+WKB_HEADER_SIZE, g->get_data_ptr()+4+WKB_HEADER_SIZE, + POINT_DATA_SIZE); + point_temp[point_size-1]= '\0'; + Geometry_buffer gbuff; + Geometry *gg= Geometry::construct(&gbuff, point_temp, point_size-1); + DBUG_ASSERT(gg); + if (static_cast<Gis_point *>(gg)->get_xy_radian(&x2r, &y2r)) + DBUG_ASSERT(0); + } + else + { + if (static_cast<const Gis_point *>(g)->get_xy_radian(&x2r, &y2r)) + DBUG_ASSERT(0); + } + if (this->get_xy_radian(&x1r, &y1r)) + DBUG_ASSERT(0); + // Check boundary conditions: longitude[-180,180] + if (!((x2r >= -M_PI && x2r <= M_PI) && (x1r >= -M_PI && x1r <= M_PI))) + { + *error=1; + return -1; + } + // Check boundary conditions: lattitude[-90,90] + if (!((y2r >= -M_PI/2 && y2r <= M_PI/2) && (y1r >= -M_PI/2 && y1r <= M_PI/2))) + { + *error=-1; + return -1; + } + dlat= sin((y2r - y1r)/2)*sin((y2r - y1r)/2); + dlong= sin((x2r - x1r)/2)*sin((x2r - x1r)/2); + res= 2*sphere_radius*asin((sqrt(dlat + cos(y1r)*cos(y2r)*dlong))); + return res; +} + + +/** + Function that calculate spherical distance of Point from Multipoint geometries. + In case there is single point in Multipoint geometries calculate_haversine() + can handle such case. Otherwise, new geometry (Point) has to be constructed. + + @param g pointer to the Geometry + @param r sphere radius + @param result pointer to the result + @param err pointer to the error obtained from calculate_haversin() + + @return state + @retval TRUE failed + @retval FALSE success +*/ +int Gis_point::spherical_distance_multipoints(Geometry *g, const double r, + double *result, int *err) +{ + uint32 num_of_points2; + // To find the minimum radius it cannot be greater than Earth radius + double res= 6370986.0; + double temp_res= 0.0; + const uint32 len= 4 + WKB_HEADER_SIZE + POINT_DATA_SIZE + 1; + char s[len]; + g->num_geometries(&num_of_points2); + DBUG_ASSERT(num_of_points2 >= 1); + if (num_of_points2 == 1) + { + *result= this->calculate_haversine(g, r, err); + return 0; + } + for (uint32 i=1; i <= num_of_points2; i++) + { + Geometry_buffer buff_temp; + Geometry *temp; + + // First 4 bytes are handled already, make sure to create a Point + memset(s + 4, Geometry::wkb_point, 1); + memcpy(s + 5, g->get_data_ptr() + 5, 4); + memcpy(s + 4 + WKB_HEADER_SIZE, g->get_data_ptr() + 4 + WKB_HEADER_SIZE*i +\ + POINT_DATA_SIZE*(i-1), POINT_DATA_SIZE); + s[len-1]= '\0'; + temp= Geometry::construct(&buff_temp, s, len); + DBUG_ASSERT(temp); + temp_res= this->calculate_haversine(temp, r, err); + if (res > temp_res) + res= temp_res; + } + *result= res; + return 0; +} /***************************** LineString *******************************/ uint32 Gis_line_string::get_data_size() const @@ -2162,6 +2275,81 @@ const Geometry::Class_info *Gis_multi_point::get_class_info() const } +/** + Function that calculate spherical distance of Multipoints geometries. + In case there is single point in Multipoint geometries calculate_haversine() + can handle such case. Otherwise, new geometry (Point) has to be constructed. + + @param g pointer to the Geometry + @param r sphere radius + @param result pointer to the result + @param err pointer to the error obtained from calculate_haversin() + + @return state + @retval TRUE failed + @retval FALSE success +*/ +int Gis_multi_point::spherical_distance_multipoints(Geometry *g, const double r, + double *result, int *err) +{ + const uint32 len= 4 + WKB_HEADER_SIZE + POINT_DATA_SIZE + 1; + // Check how many points are stored in Multipoints + uint32 num_of_points1, num_of_points2; + // To find the minimum radius it cannot be greater than Earth radius + double res= 6370986.0; + + /* From Item_func_sphere_distance::spherical_distance_points, + we are sure that there will be multiple points and we have to construct + Point geometry and return the smallest result. + */ + num_geometries(&num_of_points1); + DBUG_ASSERT(num_of_points1 >= 1); + g->num_geometries(&num_of_points2); + DBUG_ASSERT(num_of_points2 >= 1); + + for (uint32 i=1; i <= num_of_points1; i++) + { + Geometry_buffer buff_temp; + Geometry *temp; + double temp_res= 0.0; + char s[len]; + // First 4 bytes are handled already, make sure to create a Point + memset(s + 4, Geometry::wkb_point, 1); + memcpy(s + 5, this->get_data_ptr() + 5, 4); + memcpy(s + 4 + WKB_HEADER_SIZE, this->get_data_ptr() + 4 + WKB_HEADER_SIZE*i +\ + POINT_DATA_SIZE*(i-1), POINT_DATA_SIZE); + s[len-1]= '\0'; + temp= Geometry::construct(&buff_temp, s, len); + DBUG_ASSERT(temp); + // Optimization for single Multipoint + if (num_of_points2 == 1) + { + *result= static_cast<Gis_point *>(temp)->calculate_haversine(g, r, err); + return 0; + } + for (uint32 j=1; j<= num_of_points2; j++) + { + Geometry_buffer buff_temp2; + Geometry *temp2; + char s2[len]; + // First 4 bytes are handled already, make sure to create a Point + memset(s2 + 4, Geometry::wkb_point, 1); + memcpy(s2 + 5, g->get_data_ptr() + 5, 4); + memcpy(s2 + 4 + WKB_HEADER_SIZE, g->get_data_ptr() + 4 + WKB_HEADER_SIZE*j +\ + POINT_DATA_SIZE*(j-1), POINT_DATA_SIZE); + s2[len-1]= '\0'; + temp2= Geometry::construct(&buff_temp2, s2, len); + DBUG_ASSERT(temp2); + temp_res= static_cast<Gis_point *>(temp)->calculate_haversine(temp2, r, err); + if (res > temp_res) + res= temp_res; + } + } + *result= res; + return 0; +} + + /***************************** MultiLineString *******************************/ uint32 Gis_multi_line_string::get_data_size() const diff --git a/sql/spatial.h b/sql/spatial.h index e78da6e615d..1da788b07a0 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -332,6 +332,11 @@ public: m_data+= WKB_HEADER_SIZE; } + const char *get_data_ptr() const + { + return m_data; + } + bool envelope(String *result) const; static Class_info *ci_collection[wkb_last+1]; @@ -410,6 +415,17 @@ public: return 0; } + int get_xy_radian(double *x, double *y) const + { + if (!get_xy(x, y)) + { + *x= (*x)*M_PI/180; + *y= (*y)*M_PI/180; + return 0; + } + return 1; + } + int get_x(double *x) const { if (no_data(m_data, SIZEOF_STORED_DOUBLE)) @@ -436,6 +452,10 @@ public: } int store_shapes(Gcalc_shape_transporter *trn) const; const Class_info *get_class_info() const; + double calculate_haversine(const Geometry *g, const double sphere_radius, + int *error); + int spherical_distance_multipoints(Geometry *g, const double r, double *result, + int *error); }; @@ -535,6 +555,8 @@ public: } int store_shapes(Gcalc_shape_transporter *trn) const; const Class_info *get_class_info() const; + int spherical_distance_multipoints(Geometry *g, const double r, double *res, + int *error); }; |