diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 1dcbd25d..0c9e99de 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -317,6 +317,7 @@ SET(SQL_GIS_SOURCES gis/line_interpolate.cc gis/mbr_utils.cc gis/overlaps.cc + gis/perimeter.cc gis/ring_flip_visitor.cc gis/rtree_support.cc gis/simplify.cc diff --git a/sql/item_create.cc b/sql/item_create.cc index d715e661..5b9b8818 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -1623,6 +1623,7 @@ static const std::pair func_array[] = { {"ST_NUMINTERIORRINGS", SQL_FN(Item_func_numinteriorring, 1)}, {"ST_NUMPOINTS", SQL_FN(Item_func_numpoints, 1)}, {"ST_OVERLAPS", SQL_FN(Item_func_st_overlaps, 2)}, + {"ST_PERIMETER", SQL_FN(Item_func_st_perimeter, 1)}, {"ST_POINTATDISTANCE", SQL_FN(Item_func_st_pointatdistance, 2)}, {"ST_POINTFROMGEOHASH", SQL_FN(Item_func_pointfromgeohash, 2)}, {"ST_POINTFROMTEXT", SQL_FACTORY(Pointfromtext_instantiator)}, diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index d9e30027..4c3f2751 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -73,6 +73,7 @@ #include "sql/gis/is_valid.h" #include "sql/gis/length.h" #include "sql/gis/line_interpolate.h" +#include "sql/gis/perimeter.h" #include "sql/gis/relops.h" #include "sql/gis/ring_flip_visitor.h" #include "sql/gis/setops.h" @@ -5166,6 +5167,59 @@ double Item_func_st_area::val_real() { return result; } +/* Add by sakaik START*/ +double Item_func_st_perimeter::val_real() { + assert(fixed); + + String backing_unparsed_geometry; + String *unparsed_geometry = args[0]->val_str(&backing_unparsed_geometry); + + null_value = args[0]->null_value; + if (null_value) { + assert(is_nullable()); + return 0.0; + } + + if (!unparsed_geometry) { + /* purecov: begin deadcode */ + // Item.val_str should not have returned nullptr if Item.null_value is + // false. + assert(false); + my_error(ER_INTERNAL_ERROR, MYF(0), func_name()); + return error_real(); + /* purecov: end */ + } + + const dd::Spatial_reference_system *srs; + std::unique_ptr releaser( + new dd::cache::Dictionary_client::Auto_releaser( + current_thd->dd_client())); + std::unique_ptr geometry; + if (gis::parse_geometry(current_thd, func_name(), unparsed_geometry, &srs, + &geometry)) { + assert(current_thd->is_error()); + return error_real(); + } + assert(geometry); + + // This function is defined only on polygons and multipolygons for now. + if (geometry->type() != gis::Geometry_type::kPolygon && + geometry->type() != gis::Geometry_type::kMultipolygon) { + my_error(ER_UNEXPECTED_GEOMETRY_TYPE, MYF(0), "POLYGON/MULTIPOLYGON", + gis::type_to_name(geometry->type()), func_name()); + return error_real(); + } + + double result; + if (gis::perimeter(srs, geometry.get(), func_name(), &result, &null_value)) { + assert(current_thd->is_error()); + return error_real(); + } + + return result; +} +/* Add by sakaik END*/ + String *Item_func_st_buffer::val_str(String *str) { assert(fixed); null_value = false; diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 91fbc3f3..143c234d 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -1573,6 +1573,21 @@ class Item_func_st_area : public Item_real_func { } }; +/* Add by sakaik START*/ +class Item_func_st_perimeter : public Item_real_func { + public: + Item_func_st_perimeter(const POS &pos, Item *a) : Item_real_func(pos, a) {} + double val_real() override; + const char *func_name() const override { return "st_perimeter"; } + bool resolve_type(THD *thd) override { + if (param_type_is_default(thd, 0, -1, MYSQL_TYPE_GEOMETRY)) return true; + // ST_Perimeter returns NULL if the geometry is empty. + set_nullable(true); + return false; + } +}; +/* Add by sakaik END*/ + class Item_func_st_buffer : public Item_geometry_func { public: /// Parses strategy stored in String object, and sets values in strats.