summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/item_create.cc38
-rw-r--r--sql/item_geofunc.cc146
-rw-r--r--sql/item_geofunc.h16
-rw-r--r--sql/signal_handler.cc14
-rw-r--r--sql/spatial.cc188
-rw-r--r--sql/spatial.h22
-rw-r--r--sql/sql_test.cc2
7 files changed, 417 insertions, 9 deletions
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 5f6e7b29d5c..a80781259ca 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2008, 2020, MariaDB Corporation.
+ Copyright (c) 2008, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -109,7 +109,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() {}
@@ -136,7 +135,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() {}
@@ -908,6 +906,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:
+ Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+ static Create_func_distance_sphere s_singleton;
+
+ protected:
+ Create_func_distance_sphere() {}
+ virtual ~Create_func_distance_sphere() {}
+};
+
#endif
@@ -4878,6 +4889,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_CSTRING *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
@@ -7457,6 +7488,7 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_within)},
{ { STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)},
{ { STRING_WITH_LEN("ST_Y") }, GEOM_BUILDER(Create_func_y)},
+ { { C_STRING_WITH_LEN("ST_DISTANCE_SPHERE") }, GEOM_BUILDER(Create_func_distance_sphere)},
{ { STRING_WITH_LEN("SUBSTR_ORACLE") },
BUILDER(Create_func_substr_oracle)},
{ { STRING_WITH_LEN("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)},
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 682051f2448..ef7ccf1dad6 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -136,7 +136,7 @@ String *Item_func_geometry_from_json::val_str(String *str)
{
String *sv= args[1]->val_str(&tmp_js);
my_error(ER_WRONG_VALUE_FOR_TYPE, MYF(0),
- "option", sv->c_ptr_safe(), "ST_GeometryFromJSON");
+ "option", sv->c_ptr_safe(), "ST_GeomFromGeoJSON");
null_value= 1;
return 0;
}
@@ -173,7 +173,7 @@ String *Item_func_geometry_from_json::val_str(String *str)
code= ER_GEOJSON_NOT_CLOSED;
break;
case Geometry::GEOJ_DIMENSION_NOT_SUPPORTED:
- my_error(ER_GIS_INVALID_DATA, MYF(0), "ST_GeometryFromJSON");
+ my_error(ER_GIS_INVALID_DATA, MYF(0), "ST_GeomFromGeoJSON");
break;
default:
report_json_error_ex(js, &je, func_name(), 0, Sql_condition::WARN_LEVEL_WARN);
@@ -2528,11 +2528,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)
+ {
+ return 0;
+ }
+
+ if (arg_count == 3)
+ {
+ sphere_radius= args[2]->val_real();
+ // Radius cannot be Null
+ if (args[2]->null_value)
+ {
+ null_value= true;
+ return 0;
+ }
+ 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 4e7cda137c2..245a8353d35 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -2,7 +2,7 @@
#define ITEM_GEOFUNC_INCLUDED
/* Copyright (c) 2000, 2016 Oracle and/or its affiliates.
- Copyright (C) 2011, 2016, MariaDB
+ Copyright (C) 2011, 2021, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -934,6 +934,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)
+ { return get_item_copy<Item_func_sphere_distance>(thd, this); }
+};
+
+
class Item_func_pointonsurface: public Item_geometry_func_args_geometry
{
String tmp_value;
diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc
index 4b9149abe30..34908137a9c 100644
--- a/sql/signal_handler.cc
+++ b/sql/signal_handler.cc
@@ -31,6 +31,11 @@
#define SIGNAL_FMT "signal %d"
#endif
+
+#ifdef __APPLE__
+#include <sys/sysctl.h>
+#endif
+
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
@@ -52,7 +57,7 @@ extern const char *optimizer_switch_names[];
static inline void output_core_info()
{
/* proc is optional on some BSDs so it can't hurt to look */
-#ifdef HAVE_READLINK
+#if defined(HAVE_READLINK) && !defined(__APPLE__)
char buff[PATH_MAX];
ssize_t len;
int fd;
@@ -78,6 +83,13 @@ static inline void output_core_info()
my_close(fd, MYF(0));
}
#endif
+#elif defined(__APPLE__)
+ char buff[PATH_MAX];
+ size_t len = sizeof(buff);
+ if (sysctlbyname("kern.corefile", buff, &len, NULL, 0) == 0)
+ {
+ my_safe_printf_stderr("Core pattern: %.*s\n", (int) len, buff);
+ }
#else
char buff[80];
my_getwd(buff, sizeof(buff), 0);
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 84a05532532..2482a21bb5f 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
@@ -2163,6 +2276,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 55f450b1b1b..0c00482c09b 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);
};
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index ca3b9a759b7..28e3cdc9d69 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -620,7 +620,7 @@ Next alarm time: %lu\n",
#if defined(HAVE_MALLINFO2)
struct mallinfo2 info = mallinfo2();
#elif defined(HAVE_MALLINFO)
- struct mallinfo info= mallinfo();
+ struct mallinfo info= mallinfo();
#endif
#if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2)
char llbuff[10][22];