From 6769d1a0782f140dcd12c9ced6fda34ac0e41d85 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Thu, 29 Oct 2020 01:40:31 +0100 Subject: 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 --- sql/item_geofunc.cc | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 1 deletion(-) (limited to 'sql/item_geofunc.cc') 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(g2)->calculate_haversine(g1, r, &error); + } + else + { + // Optimization for single point in Multipoint + if (g1->get_data_size() == len) + { + res= static_cast(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(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(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(g1)->spherical_distance_multipoints( + (Gis_multi_point *)g2, r, &res, &error); + } + } + else + { + // Multipoints in g1 and g2 - no optimization + static_cast(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; -- cgit v1.2.1 From 5eda18f0cac6e6520cc1bbeec28c7c653da737df Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Sat, 27 Mar 2021 10:54:57 +0100 Subject: MDEV-25272: Wrong function name in error messages upon ST_GeomFromGeoJSON call - Invalid function name during ER_WRONG_VALUE_FOR_TYPE and ER_GIS_INVALID_DATA --- sql/item_geofunc.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql/item_geofunc.cc') diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 2b0f67f4ddc..83a9cabf7b2 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -145,7 +145,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; } @@ -182,7 +182,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); -- cgit v1.2.1 From 2fc76a50229ab29f6524dc08d21ab52b750b2918 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Sat, 27 Mar 2021 21:02:09 +0100 Subject: MDEV-13467: Feature request: Support for ST_Distance_Sphere() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - jump to label ‘handle_errors’ can enter to the scope of non-POD ‘Geometry_buffer buffer2’ --- sql/item_geofunc.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql/item_geofunc.cc') diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 83a9cabf7b2..0daf9da4a81 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -2549,7 +2549,7 @@ double Item_func_sphere_distance::val_real() null_value= (args[0]->null_value || args[1]->null_value); if (null_value) { - goto handle_errors; + return 0; } if (arg_count == 3) @@ -2559,7 +2559,7 @@ double Item_func_sphere_distance::val_real() if (args[2]->null_value) { null_value= true; - goto handle_errors; + return 0; } if (sphere_radius <= 0) { -- cgit v1.2.1