summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnel Husakovic <anel@mariadb.org>2020-10-29 01:40:31 +0100
committerAnel Husakovic <anel@mariadb.org>2021-03-27 10:42:39 +0100
commit6769d1a0782f140dcd12c9ced6fda34ac0e41d85 (patch)
tree496207894596a5fbd77a23ba313f8e15ff16b87e
parent48141f3c1787de941d969ad1e6675611b2b650c2 (diff)
downloadmariadb-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--.gitignore10
-rw-r--r--mysql-test/r/gis-precise.result111
-rw-r--r--mysql-test/suite/innodb_gis/t/1.test13
-rw-r--r--mysql-test/suite/innodb_gis/t/bug16236208.test1
-rw-r--r--mysql-test/suite/innodb_gis/t/create_spatial_index.test1
-rw-r--r--mysql-test/suite/innodb_gis/t/gis.test13
-rw-r--r--mysql-test/suite/innodb_gis/t/precise.test2
-rw-r--r--mysql-test/suite/innodb_gis/t/rtree.test6
-rw-r--r--mysql-test/t/gis-precise.test78
-rw-r--r--sql/item_create.cc36
-rw-r--r--sql/item_geofunc.cc142
-rw-r--r--sql/item_geofunc.h14
-rw-r--r--sql/spatial.cc188
-rw-r--r--sql/spatial.h22
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);
};