Commit e82963e9 authored by StefanoPetrilli's avatar StefanoPetrilli Committed by Dave Gosselin

MDEV-34177: Implements ST_PointFromGeoHash

The GIS function ST_PointFromGeoHash takes in input a geohash and
returns a point where the x is the longitude and the y is the latitude.
The latitude is returned as a numeric value in the interval [180, -180].
The longitude is returned as a numeric value in the interval [90, -90].
If the argument is NULL, the return value is NULL. If the argument is
invalid, an ER_GIS_INVALID_DATA is thrown.

Author: StefanoPetrilli <stefanop_1999@hotmail.it>
Co-authored-by: default avatarkevincheng2 <chengyf112@gmail.com>
Co-authored-by: default avatarCatalin Besleaga <catalin.besleaga@oracle.com>
Co-authored-by: default avatarGleb Shchepa <gleb.shchepa@oracle.com>
Co-authored-by: default avatarTatiana Azundris Nuernberg <tatjana.nuernberg@oracle.com>
Co-authored-by: default avatarMartin Hansson <martin.hansson@oracle.com>
Co-authored-by: default avatarDeepa Dixit <deepa.dixit@oracle.com>
Co-authored-by: default avatarHans H Melby <hans.h.melby@oracle.com>
Co-authored-by: default avatarJens Even Berg Blomsøy <jens.even.blomsoy@oracle.com>
Co-authored-by: default avatarErlend Dahl <erlend.dahl@oracle.com>
Co-authored-by: default avatarNorvald H. Ryeng <norvald.ryeng@oracle.com>
Co-authored-by: default avatarBennyWang <benny.wang@oracle.com>
Co-authored-by: default avatarDavid.Zhao <david.zhao@oracle.com>
Co-authored-by: default avatarErik Froseth <erik.froseth@oracle.com>
parent 62ec440f
......@@ -3027,6 +3027,7 @@ bool Item_func_latlongfromgeohash::is_invalid_geohash_field(
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_GEOMETRY:
case MYSQL_TYPE_STRING:
return false;
default:
return true;
......@@ -3034,6 +3035,7 @@ bool Item_func_latlongfromgeohash::is_invalid_geohash_field(
}
double Item_func_latlongfromgeohash::val_real()
{
null_value= 1;
......@@ -3076,6 +3078,87 @@ double Item_func_latlongfromgeohash::val_real()
return latitude;
}
bool Item_func_pointfromgeohash::is_invalid_SRID_field
(enum_field_types field_type)
{
switch (field_type)
{
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_LONGLONG:
return false;
default:
return true;
}
}
String *Item_func_pointfromgeohash::val_str(String *str)
{
DBUG_ASSERT(fixed());
null_value= 1;
String *input_value;
uint32 srid;
if (args[0]->null_value || args[1]->null_value)
return NULL;
if (is_invalid_SRID_field(args[1]->field_type()) ||
Item_func_latlongfromgeohash::is_invalid_geohash_field(
args[0]->field_type()
))
{
my_error(ER_GIS_INVALID_DATA, MYF(0), "ST_PointFromGeoHash");
return NULL;
}
input_value= args[0]->val_str(&buf);
if (args[0]->null_value)
{
args[0]->null_value= 0;
return NULL;
}
if (input_value->length() == 0)
{
my_error(ER_WRONG_VALUE_FOR_TYPE, MYF(0), "geohash",
input_value->c_ptr_safe(), func_name());
return NULL;
}
srid= static_cast<uint32>(args[1]->val_uint());
if (args[1]->null_value)
{
my_error(ER_WRONG_VALUE_FOR_TYPE, MYF(0), "geohash",
input_value->c_ptr_safe(), func_name());
return NULL;
}
double latitude= 0.0, longitude= 0.0;
if (Item_func_latlongfromgeohash::decode_geohash(input_value, &latitude, &longitude)) {
my_error(ER_WRONG_VALUE_FOR_TYPE, MYF(0), "geohash",
input_value->c_ptr_safe(), func_name());
return NULL;
}
str->set_charset(&my_charset_bin);
str->length(0);
if (str->reserve(SRID_SIZE + WKB_HEADER_SIZE + POINT_DATA_SIZE))
return NULL;
str->q_append((uint32) srid);
str->q_append((char) Geometry::wkb_ndr);
str->q_append((uint32) Geometry::wkb_point);
str->q_append(longitude);
str->q_append(latitude);
null_value= 0;
return str;
}
String *Item_func_pointonsurface::val_str(String *str)
{
Gcalc_operation_transporter trn(&func, &collector);
......@@ -3551,6 +3634,22 @@ class Create_func_longfromgeohash : public Create_func_arg1
};
class Create_func_pointfromgeohash : public Create_func_arg2
{
public:
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_pointfromgeohash(thd, arg1, arg2);
}
static Create_func_pointfromgeohash s_singleton;
protected:
Create_func_pointfromgeohash() = default;
virtual ~Create_func_pointfromgeohash() = default;
};
class Create_func_endpoint : public Create_func_arg1
{
public:
......@@ -4406,6 +4505,7 @@ Create_func_distance_sphere Create_func_distance_sphere::s_singleton;
Create_func_geohash Create_func_geohash::s_singleton;
Create_func_latfromgeohash Create_func_latfromgeohash ::s_singleton;
Create_func_longfromgeohash Create_func_longfromgeohash ::s_singleton;
Create_func_pointfromgeohash Create_func_pointfromgeohash ::s_singleton;
Create_func_endpoint Create_func_endpoint::s_singleton;
Create_func_envelope Create_func_envelope::s_singleton;
Create_func_equals Create_func_equals::s_singleton;
......@@ -4532,6 +4632,7 @@ static Native_func_registry func_array_geom[] =
{ { STRING_WITH_LEN("GEOHASH") }, GEOM_BUILDER(Create_func_geohash)},
{ { STRING_WITH_LEN("LATFROMGEOHASH") }, GEOM_BUILDER(Create_func_latfromgeohash)},
{ { STRING_WITH_LEN("LONGFROMGEOHASH") }, GEOM_BUILDER(Create_func_longfromgeohash)},
{ { STRING_WITH_LEN("POINTFROMGEOHASH") }, GEOM_BUILDER(Create_func_pointfromgeohash)},
{ { STRING_WITH_LEN("SRID") }, GEOM_BUILDER(Create_func_srid)},
{ { STRING_WITH_LEN("ST_AREA") }, GEOM_BUILDER(Create_func_area)},
{ { STRING_WITH_LEN("STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
......@@ -4616,6 +4717,7 @@ static Native_func_registry func_array_geom[] =
{ { STRING_WITH_LEN("ST_GEOHASH") }, GEOM_BUILDER(Create_func_geohash)},
{ { STRING_WITH_LEN("ST_LATFROMGEOHASH") }, GEOM_BUILDER(Create_func_latfromgeohash)},
{ { STRING_WITH_LEN("ST_LONGFROMGEOHASH") }, GEOM_BUILDER(Create_func_longfromgeohash)},
{ { STRING_WITH_LEN("ST_POINTFROMGEOHASH") }, GEOM_BUILDER(Create_func_pointfromgeohash)},
{ { STRING_WITH_LEN("TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
{ { STRING_WITH_LEN("WITHIN") }, GEOM_BUILDER(Create_func_within)},
{ { STRING_WITH_LEN("X") }, GEOM_BUILDER(Create_func_x)},
......
......@@ -1262,13 +1262,13 @@ class Item_func_latlongfromgeohash : public Item_real_func {
String buf;
static const uint8_t geohash_alphabet[256];
const bool decode_longitude;
static bool is_invalid_geohash_field(enum_field_types field_type);
public:
Item_func_latlongfromgeohash(THD *thd, Item *a, bool start_on_even_bit_arg)
: Item_real_func(thd, a),
decode_longitude(start_on_even_bit_arg) {}
double val_real() override;
static bool is_invalid_geohash_field(const enum_field_types field_type);
static bool decode_geohash(String *geohash, double *result_latitude,
double *result_longitude);
static double round_latlongitude(double latlongitude, double error_range,
......@@ -1306,6 +1306,26 @@ class Item_func_longfromgeohash: public Item_func_latlongfromgeohash
};
class Item_func_pointfromgeohash: public Item_geometry_func
{
private:
String buf;
static bool is_invalid_SRID_field(const enum_field_types field_type);
public:
Item_func_pointfromgeohash(THD *thd, Item *a, Item *b)
:Item_geometry_func(thd, a, b) {}
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("st_pointfromgeohash") };
return name;
}
String *val_str(String *) override;
Item *get_copy(THD *thd) override
{ return get_item_copy<Item_func_pointfromgeohash>(thd, this); }
};
class Item_func_pointonsurface: public Item_geometry_func_args_geometry
{
String tmp_value;
......
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