Commit 6769d1a0 authored by Anel Husakovic's avatar Anel Husakovic

MDEV-13467: Feature request: Support for ST_Distance_Sphere()

- Cherry-pick 51e48b9f - vscode gitignore
- Thanks Robin Dupret for the review.

Reviewed by:daniel@mariadb.org
            holyfoot@mariadb.com
parent 48141f3c
...@@ -507,3 +507,13 @@ FakesAssemblies/ ...@@ -507,3 +507,13 @@ FakesAssemblies/
# QtCreator && CodeBlocks # QtCreator && CodeBlocks
*.cbp *.cbp
compile_commands.json
.clang-format
.kscope/
.vimrc
.editorconfig
.kateconfig
*.kdev4
# Visual Studio Code workspace
.vscode/
...@@ -807,3 +807,114 @@ SRID(GEOMETRYFROMTEXT(' MULTIPOINT(8 4,5 0,7 8,6 9,3 4,7 3,5 5) ')))); ...@@ -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))'), 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) ')))) 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)) 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
...@@ -393,7 +393,6 @@ insert into t1 values (1); ...@@ -393,7 +393,6 @@ insert into t1 values (1);
insert into t1 values (1.11); insert into t1 values (1.11);
--error 1416 --error 1416
insert into t1 values ("qwerty"); insert into t1 values ("qwerty");
# --error ER_GIS_INVALID_DATA
--error ER_BAD_NULL_ERROR --error ER_BAD_NULL_ERROR
insert into t1 values (ST_pointfromtext('point(1,1)')); insert into t1 values (ST_pointfromtext('point(1,1)'));
...@@ -437,7 +436,6 @@ select ...@@ -437,7 +436,6 @@ select
ST_y(b) IS NULL ST_y(b) IS NULL
from t1; from t1;
# --error ER_GIS_INVALID_DATA
select select
MBRwithin(b, b) IS NULL, MBRcontains(b, b) IS NULL, MBRoverlaps(b, b) IS NULL, 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, MBRequals(b, b) IS NULL, MBRdisjoint(b, b) IS NULL, ST_touches(b, b) IS NULL,
...@@ -466,7 +464,6 @@ DROP TABLE t1; ...@@ -466,7 +464,6 @@ DROP TABLE t1;
# #
CREATE TABLE `t1` ( `col9` set('a'), `col89` date); CREATE TABLE `t1` ( `col9` set('a'), `col89` date);
INSERT IGNORE INTO `t1` VALUES ('','0000-00-00'); INSERT IGNORE INTO `t1` VALUES ('','0000-00-00');
# --error ER_GIS_INVALID_DATA
select ST_geomfromtext(col9,col89) as a from t1; select ST_geomfromtext(col9,col89) as a from t1;
DROP TABLE t1; DROP TABLE t1;
...@@ -623,17 +620,11 @@ SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS MBRwithin FROM t1 a1 JOIN ...@@ -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 # 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))'); 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))'); 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))'); 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))'); SET @horiz3 = ST_GeomFromText('POLYGON ((2 0, 3 0, 2 0))');
# --error ER_GIS_INVALID_DATA
SET @point1 = ST_GeomFromText('POLYGON ((0 0))'); SET @point1 = ST_GeomFromText('POLYGON ((0 0))');
# --error ER_GIS_INVALID_DATA
SET @point2 = ST_GeomFromText('POLYGON ((-2 0))'); 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; 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 ...@@ -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 # BUG#51875: crash when loading data into geometry function ST_polyfromwkb
--echo # --echo #
SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440;
# --error ER_GIS_INVALID_DATA
SET @a=ST_POLYFROMWKB(@a); SET @a=ST_POLYFROMWKB(@a);
SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440;
# --error ER_GIS_INVALID_DATA
SET @a=ST_POLYFROMWKB(@a); SET @a=ST_POLYFROMWKB(@a);
...@@ -899,7 +888,6 @@ DROP TABLE g1; ...@@ -899,7 +888,6 @@ DROP TABLE g1;
CREATE TABLE g1(a TEXT NOT NULL, KEY(a(255))); CREATE TABLE g1(a TEXT NOT NULL, KEY(a(255)));
INSERT INTO g1 VALUES ('a'),('a'); INSERT INTO g1 VALUES ('a'),('a');
# --error ER_GIS_INVALID_DATA
SELECT 1 FROM g1 WHERE a >= ANY SELECT 1 FROM g1 WHERE a >= ANY
(SELECT 1 FROM g1 WHERE a = ST_geomfromtext('') OR a) ; (SELECT 1 FROM g1 WHERE a = ST_geomfromtext('') OR a) ;
...@@ -1447,5 +1435,4 @@ DROP DATABASE gis_ogs; ...@@ -1447,5 +1435,4 @@ DROP DATABASE gis_ogs;
--echo # Bug#13362660 ASSERTION `FIELD_POS < FIELD_COUNT' FAILED. IN PROTOCOL_TEXT::STORE --echo # Bug#13362660 ASSERTION `FIELD_POS < FIELD_COUNT' FAILED. IN PROTOCOL_TEXT::STORE
--echo # --echo #
# --error ER_GIS_INVALID_DATA
SELECT ST_Union('', ''), md5(1); SELECT ST_Union('', ''), md5(1);
...@@ -47,7 +47,6 @@ ST_GeomFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')); ...@@ -47,7 +47,6 @@ ST_GeomFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))'));
CREATE INDEX linestring_index ON linestring(linestring_nokey(5)); CREATE INDEX linestring_index ON linestring(linestring_nokey(5));
ALTER TABLE linestring ADD KEY (linestring_key(5)); ALTER TABLE linestring ADD KEY (linestring_key(5));
# --error ER_GIS_INVALID_DATA
SELECT ST_AsText(linestring_nokey) FROM linestring FORCE KEY ( SELECT ST_AsText(linestring_nokey) FROM linestring FORCE KEY (
linestring_key ) WHERE ST_CONTAINS( ST_GeomFromText('POLYGON( ( 3923 2815 , 4246 linestring_key ) WHERE ST_CONTAINS( ST_GeomFromText('POLYGON( ( 3923 2815 , 4246
2122 , 4028 2971 , 4017 3019 , 3923 2815 ) )') , linestring_key ) AND 2122 , 4028 2971 , 4017 3019 , 3923 2815 ) )') , linestring_key ) AND
......
...@@ -1141,7 +1141,6 @@ insert into `t1` values( ...@@ -1141,7 +1141,6 @@ insert into `t1` values(
linestring(point(1,1),point(1,1)) linestring(point(1,1),point(1,1))
); );
# --error ER_GIS_INVALID_DATA
--error ER_BAD_NULL_ERROR --error ER_BAD_NULL_ERROR
insert into `t1` values insert into `t1` values
( (
......
...@@ -388,7 +388,6 @@ insert into t1 values (1.11); ...@@ -388,7 +388,6 @@ insert into t1 values (1.11);
--error 1416 --error 1416
insert into t1 values ("qwerty"); insert into t1 values ("qwerty");
--error 1048 --error 1048
# --error ER_GIS_INVALID_DATA
insert into t1 values (ST_pointfromtext('point(1,1)')); insert into t1 values (ST_pointfromtext('point(1,1)'));
drop table t1; drop table t1;
...@@ -431,7 +430,6 @@ select ...@@ -431,7 +430,6 @@ select
ST_y(b) IS NULL ST_y(b) IS NULL
from t1; from t1;
# --error ER_GIS_INVALID_DATA
select select
MBRwithin(b, b) IS NULL, MBRcontains(b, b) IS NULL, MBRoverlaps(b, b) IS NULL, 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, MBRequals(b, b) IS NULL, MBRdisjoint(b, b) IS NULL, ST_touches(b, b) IS NULL,
...@@ -460,7 +458,6 @@ DROP TABLE t1; ...@@ -460,7 +458,6 @@ DROP TABLE t1;
# #
CREATE TABLE `t1` ( `col9` set('a'), `col89` date); CREATE TABLE `t1` ( `col9` set('a'), `col89` date);
INSERT IGNORE INTO `t1` VALUES ('','0000-00-00'); INSERT IGNORE INTO `t1` VALUES ('','0000-00-00');
# --error ER_GIS_INVALID_DATA
select ST_geomfromtext(col9,col89) as a from t1; select ST_geomfromtext(col9,col89) as a from t1;
DROP TABLE t1; DROP TABLE t1;
...@@ -617,17 +614,11 @@ SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS MBRwithin FROM t1 a1 JOIN ...@@ -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 # 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))'); 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))'); 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))'); 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))'); SET @horiz3 = ST_GeomFromText('POLYGON ((2 0, 3 0, 2 0))');
# --error ER_GIS_INVALID_DATA
SET @point1 = ST_GeomFromText('POLYGON ((0 0))'); SET @point1 = ST_GeomFromText('POLYGON ((0 0))');
# --error ER_GIS_INVALID_DATA
SET @point2 = ST_GeomFromText('POLYGON ((-2 0))'); 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; 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 ...@@ -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 # BUG#51875: crash when loading data into geometry function ST_polyfromwkb
--echo # --echo #
SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440;
# --error ER_GIS_INVALID_DATA
SET @a=ST_POLYFROMWKB(@a); SET @a=ST_POLYFROMWKB(@a);
SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440;
# --error ER_GIS_INVALID_DATA
SET @a=ST_POLYFROMWKB(@a); SET @a=ST_POLYFROMWKB(@a);
...@@ -901,7 +890,6 @@ DROP TABLE g1; ...@@ -901,7 +890,6 @@ DROP TABLE g1;
CREATE TABLE g1(a TEXT NOT NULL, KEY(a(255))); CREATE TABLE g1(a TEXT NOT NULL, KEY(a(255)));
INSERT INTO g1 VALUES ('a'),('a'); INSERT INTO g1 VALUES ('a'),('a');
# --error ER_GIS_INVALID_DATA
SELECT 1 FROM g1 WHERE a >= ANY SELECT 1 FROM g1 WHERE a >= ANY
(SELECT 1 FROM g1 WHERE a = ST_geomfromtext('') OR a) ; (SELECT 1 FROM g1 WHERE a = ST_geomfromtext('') OR a) ;
...@@ -1440,5 +1428,4 @@ DROP DATABASE gis_ogs; ...@@ -1440,5 +1428,4 @@ DROP DATABASE gis_ogs;
--echo # Bug#13362660 ASSERTION `FIELD_POS < FIELD_COUNT' FAILED. IN PROTOCOL_TEXT::STORE --echo # Bug#13362660 ASSERTION `FIELD_POS < FIELD_COUNT' FAILED. IN PROTOCOL_TEXT::STORE
--echo # --echo #
# --error ER_GIS_INVALID_DATA
SELECT ST_Union('', ''), md5(1); SELECT ST_Union('', ''), md5(1);
...@@ -122,7 +122,6 @@ SELECT ST_Equals(ST_PointFromText('POINT (12 13)'),ST_PointFromText('POINT (12 1 ...@@ -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 # BUG#11759650/51979: UNION/INTERSECTION OF POLYGONS CRASHES MYSQL
--echo # --echo #
# --error ER_GIS_INVALID_DATA
SELECT ST_ASTEXT(ST_UNION(ST_GEOMFROMTEXT('POLYGON((525000 183300,525400 SELECT ST_ASTEXT(ST_UNION(ST_GEOMFROMTEXT('POLYGON((525000 183300,525400
183300,525400 18370, 525000 183700,525000 183300))'), 183300,525400 18370, 525000 183700,525000 183300))'),
ST_geomfromtext('POLYGON((525298.67 183511.53,525296.57 ST_geomfromtext('POLYGON((525298.67 183511.53,525296.57
...@@ -140,7 +139,6 @@ 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; 183491.55))'))) st_u;
SET @a=0x0000000001030000000200000005000000000000000000000000000000000000000000000000002440000000000000000000000000000024400000000000002440000000000000000000000000000024400000000000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000F03F00000000000000400000000000000040000000000000F03F0000000000000040000000000000F03F000000000000F03F; SET @a=0x0000000001030000000200000005000000000000000000000000000000000000000000000000002440000000000000000000000000000024400000000000002440000000000000000000000000000024400000000000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000F03F00000000000000400000000000000040000000000000F03F0000000000000040000000000000F03F000000000000F03F;
# --error ER_GIS_INVALID_DATA
SELECT ST_ASTEXT(ST_TOUCHES(@a, ST_GEOMFROMTEXT('point(0 0)'))) t; SELECT ST_ASTEXT(ST_TOUCHES(@a, ST_GEOMFROMTEXT('point(0 0)'))) t;
......
...@@ -78,17 +78,11 @@ SELECT name, ST_AsText(square) from t1 where MBRWithin(@p, square); ...@@ -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 # 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))'); 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))'); 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))'); 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))'); SET @horiz3 = ST_GeomFromText('POLYGON ((2 0, 3 0, 2 0))');
# --error ER_GIS_INVALID_DATA
SET @point1 = ST_GeomFromText('POLYGON ((0 0))'); SET @point1 = ST_GeomFromText('POLYGON ((0 0))');
# --error ER_GIS_INVALID_DATA
SET @point2 = ST_GeomFromText('POLYGON ((-2 0))'); 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; SELECT GROUP_CONCAT(a1.name ORDER BY a1.name) AS MBRoverlaps FROM t1 a1 WHERE MBROverlaps(a1.square, @vert1) GROUP BY a1.name;
......
...@@ -393,3 +393,81 @@ with cte1 as( select (st_symdifference(point(1,1),point(1,1))) as a1 ), cte2 a ...@@ -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 --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);
...@@ -202,7 +202,6 @@ class Create_func_arg2 : public Create_func ...@@ -202,7 +202,6 @@ class Create_func_arg2 : public Create_func
@return An item representing the function call @return An item representing the function call
*/ */
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) = 0; virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) = 0;
protected: protected:
/** Constructor. */ /** Constructor. */
Create_func_arg2() {} Create_func_arg2() {}
...@@ -229,7 +228,6 @@ class Create_func_arg3 : public Create_func ...@@ -229,7 +228,6 @@ class Create_func_arg3 : public Create_func
@return An item representing the function call @return An item representing the function call
*/ */
virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0; virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0;
protected: protected:
/** Constructor. */ /** Constructor. */
Create_func_arg3() {} Create_func_arg3() {}
...@@ -975,6 +973,19 @@ class Create_func_distance : public Create_func_arg2 ...@@ -975,6 +973,19 @@ class Create_func_distance : public Create_func_arg2
Create_func_distance() {} Create_func_distance() {}
virtual ~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 #endif
...@@ -4761,6 +4772,26 @@ Create_func_glength::create_1_arg(THD *thd, Item *arg1) ...@@ -4761,6 +4772,26 @@ Create_func_glength::create_1_arg(THD *thd, Item *arg1)
{ {
return new (thd->mem_root) Item_func_glength(thd, 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 #endif
...@@ -7051,6 +7082,7 @@ static Native_func_registry func_array[] = ...@@ -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_WITHIN") }, GEOM_BUILDER(Create_func_within)},
{ { C_STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)}, { { 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_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("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)},
{ { C_STRING_WITH_LEN("SUBTIME") }, BUILDER(Create_func_subtime)}, { { C_STRING_WITH_LEN("SUBTIME") }, BUILDER(Create_func_subtime)},
{ { C_STRING_WITH_LEN("TAN") }, BUILDER(Create_func_tan)}, { { C_STRING_WITH_LEN("TAN") }, BUILDER(Create_func_tan)},
......
...@@ -2537,11 +2537,151 @@ double Item_func_distance::val_real() ...@@ -2537,11 +2537,151 @@ double Item_func_distance::val_real()
} }
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) String *Item_func_pointonsurface::val_str(String *str)
{ {
Gcalc_operation_transporter trn(&func, &collector); Gcalc_operation_transporter trn(&func, &collector);
DBUG_ENTER("Item_func_pointonsurface::val_real"); DBUG_ENTER("Item_func_pointonsurface::val_str");
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
String *res= args[0]->val_str(&tmp_value); String *res= args[0]->val_str(&tmp_value);
Geometry_buffer buffer; Geometry_buffer buffer;
......
...@@ -714,6 +714,20 @@ class Item_func_distance: public Item_real_func ...@@ -714,6 +714,20 @@ class Item_func_distance: public Item_real_func
}; };
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 class Item_func_pointonsurface: public Item_geometry_func
{ {
String tmp_value; String tmp_value;
......
...@@ -1032,6 +1032,119 @@ const Geometry::Class_info *Gis_point::get_class_info() const ...@@ -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 *******************************/ /***************************** LineString *******************************/
uint32 Gis_line_string::get_data_size() const uint32 Gis_line_string::get_data_size() const
...@@ -2162,6 +2275,81 @@ const Geometry::Class_info *Gis_multi_point::get_class_info() 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 *******************************/ /***************************** MultiLineString *******************************/
uint32 Gis_multi_line_string::get_data_size() const uint32 Gis_multi_line_string::get_data_size() const
......
...@@ -332,6 +332,11 @@ class Geometry ...@@ -332,6 +332,11 @@ class Geometry
m_data+= WKB_HEADER_SIZE; m_data+= WKB_HEADER_SIZE;
} }
const char *get_data_ptr() const
{
return m_data;
}
bool envelope(String *result) const; bool envelope(String *result) const;
static Class_info *ci_collection[wkb_last+1]; static Class_info *ci_collection[wkb_last+1];
...@@ -410,6 +415,17 @@ class Gis_point: public Geometry ...@@ -410,6 +415,17 @@ class Gis_point: public Geometry
return 0; 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 int get_x(double *x) const
{ {
if (no_data(m_data, SIZEOF_STORED_DOUBLE)) if (no_data(m_data, SIZEOF_STORED_DOUBLE))
...@@ -436,6 +452,10 @@ class Gis_point: public Geometry ...@@ -436,6 +452,10 @@ class Gis_point: public Geometry
} }
int store_shapes(Gcalc_shape_transporter *trn) const; int store_shapes(Gcalc_shape_transporter *trn) const;
const Class_info *get_class_info() 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 @@ class Gis_multi_point: public Geometry ...@@ -535,6 +555,8 @@ class Gis_multi_point: public Geometry
} }
int store_shapes(Gcalc_shape_transporter *trn) const; int store_shapes(Gcalc_shape_transporter *trn) const;
const Class_info *get_class_info() const; const Class_info *get_class_info() const;
int spherical_distance_multipoints(Geometry *g, const double r, double *res,
int *error);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment