/* Copyright (c) 2003, 2016, Oracle and/or its affiliates.
Copyright ( c ) 2011 , 2022 , 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
the Free Software Foundation ; version 2 of the License .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
/**
@ file
@ brief
This file defines all spatial functions
*/
#include "mariadb.h"
#include "sql_priv.h"
/*
It is necessary to include set_var . h instead of item . h because there
are dependencies on include order for set_var . h and item . h . This
will be resolved later .
*/
#include "sql_class.h" // THD, set_var.h: THD
#include "set_var.h"
#include <m_ctype.h>
#include "opt_range.h"
#include "item_geofunc.h"
#include "item_create.h"
#define MAX_LONGITUDE 180
#define MIN_LONGITUDE -180
#define MAX_LATITUDE 90
#define MIN_LATITUDE -90
#define MAX_GEOHASH_LENGTH 100
#define MIN_GEOHASH_LENGTH 0
bool Item_geometry_func::fix_length_and_dec(THD *thd)
{
collation.set(&my_charset_bin);
decimals=0 ;
max_length= (uint32) UINT_MAX32;
set_maybe_null();
return FALSE ;
}
String *Item_func_geometry_from_text::val_str(String *str)
{
DBUG_ASSERT(fixed());
Geometry_buffer buffer;
String arg_val;
String *wkt= args[0 ]->val_str_ascii(&arg_val);
if ((null_value= args[0 ]->null_value))
return 0 ;
Gis_read_stream trs(wkt->charset(), wkt->ptr(), wkt->length());
uint32 srid= 0 ;
if (arg_count == 2 )
srid= (uint32)args[1 ]->val_int();
str->set_charset(&my_charset_bin);
str->length(0 );
if (str->reserve(SRID_SIZE, 512 ))
return 0 ;
str->q_append(srid);
if ((null_value= !Geometry::create_from_wkt(&buffer, &trs, str, 0 )))
return 0 ;
return str;
}
String *Item_func_geometry_from_wkb::val_str(String *str)
{
DBUG_ASSERT(fixed());
String arg_val;
String *wkb;
Geometry_buffer buffer;
uint32 srid= 0 ;
if (args[0 ]->field_type() == MYSQL_TYPE_GEOMETRY)
{
String *str_ret= args[0 ]->val_str(str);
null_value= args[0 ]->null_value;
if (!null_value && arg_count == 2 )
{
srid= (uint32)args[1 ]->val_int();
if (str->copy(*str_ret))
return 0 ;
int4store(const_cast <char *>(str->ptr()), srid);
return str;
}
return str_ret;
}
wkb= args[0 ]->val_str(&arg_val);
if (arg_count == 2 )
srid= (uint32)args[1 ]->val_int();
str->set_charset(&my_charset_bin);
str->length(0 );
if (str->reserve(SRID_SIZE, 512 ))
{
null_value= TRUE ; /* purecov: inspected */
return 0 ; /* purecov: inspected */
}
str->q_append(srid);
if ((null_value=
(args[0 ]->null_value ||
!Geometry::create_from_wkb(&buffer, wkb->ptr(), wkb->length(), str))))
return 0 ;
return str;
}
bool Item_func_geometry_from_json::fix_length_and_dec(THD *thd)
{
mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM,
&je.stack,
sizeof (int ), NULL,
JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0 ));
return Item_geometry_func::fix_length_and_dec(thd);
}
String *Item_func_geometry_from_json::val_str(String *str)
{
DBUG_ASSERT(fixed());
Geometry_buffer buffer;
String *js= args[0 ]->val_str_ascii(&tmp_js);
uint32 srid= 0 ;
longlong options= 0 ;
if ((null_value= args[0 ]->null_value))
return 0 ;
if (arg_count > 1 )
{
options= args[1 ]->val_int();
if (!args[1 ]->null_value && (options > 4 || options < 1 ))
{
String *sv= args[1 ]->val_str(&tmp_js);
my_error(ER_WRONG_VALUE_FOR_TYPE, MYF(0 ),
"option" , sv->c_ptr_safe(), "ST_GeomFromGeoJSON" );
null_value= 1 ;
return 0 ;
}
}
if (arg_count == 3 )
srid= (uint32)args[2 ]->val_int();
str->set_charset(&my_charset_bin);
str->length(0 );
if (str->reserve(SRID_SIZE, 512 ))
return 0 ;
str->q_append(srid);
json_scan_start(&je, js->charset(), (const uchar *) js->ptr(),
(const uchar *) js->end());
je.killed_ptr= (uint32_t *) ¤t_thd->killed;
if (!json_read_value(&je) &&
(null_value= !Geometry::create_from_json(&buffer, &je, options==1 , str)))
{
int code= 0 ;
switch (je.s.error)
{
case Geometry::GEOJ_INCORRECT_GEOJSON:
code= ER_GEOJSON_INCORRECT;
break ;
case Geometry::GEOJ_TOO_FEW_POINTS:
code= ER_GEOJSON_TOO_FEW_POINTS;
break ;
case Geometry::GEOJ_EMPTY_COORDINATES:
code= ER_GEOJSON_EMPTY_COORDINATES;
break ;
case Geometry::GEOJ_POLYGON_NOT_CLOSED:
code= ER_GEOJSON_NOT_CLOSED;
break ;
case Geometry::GEOJ_DIMENSION_NOT_SUPPORTED:
my_error(ER_GIS_INVALID_DATA, MYF(0 ), "ST_GeomFromGeoJSON" );
break ;
default :
report_json_error_ex(js->ptr(), &je, func_name(), 0 ,
Sql_condition::WARN_LEVEL_WARN);
return NULL;
}
if (code)
{
THD *thd= current_thd;
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, code,
ER_THD(thd, code));
}
return 0 ;
}
return str;
}
String *Item_func_as_wkt::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed());
String arg_val;
String *swkb= args[0 ]->val_str(&arg_val);
Geometry_buffer buffer;
Geometry *geom= NULL;
const char *dummy;
if ((null_value=
(args[0 ]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
return 0 ;
str->length(0 );
str->set_charset(&my_charset_latin1);
if ((null_value= geom->as_wkt(str, &dummy)))
return 0 ;
return str;
}
bool Item_func_as_wkt::fix_length_and_dec(THD *thd)
{
collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
max_length= (uint32) UINT_MAX32;
set_maybe_null();
return FALSE ;
}
String *Item_func_as_wkb::val_str(String *str)
{
DBUG_ASSERT(fixed());
String arg_val;
String *swkb= args[0 ]->val_str(&arg_val);
Geometry_buffer buffer;
if ((null_value=
(args[0 ]->null_value ||
!(Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
return 0 ;
str->copy(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE,
&my_charset_bin);
return str;
}
bool Item_func_as_geojson::fix_length_and_dec(THD *thd)
{
collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
max_length=MAX_BLOB_WIDTH;
set_maybe_null();
return FALSE ;
}
String *Item_func_as_geojson::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed());
String arg_val;
String *swkb= args[0 ]->val_str(&arg_val);
uint max_dec= FLOATING_POINT_DECIMALS;
longlong options= 0 ;
Geometry_buffer buffer;
Geometry *geom= NULL;
const char *dummy;
if ((null_value=
(args[0 ]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
return 0 ;
if (arg_count > 1 )
{
max_dec= (uint) args[1 ]->val_int();
if (args[1 ]->null_value)
max_dec= FLOATING_POINT_DECIMALS;
if (arg_count > 2 )
options= args[2 ]->val_int();
}
str->length(0 );
str->set_charset(&my_charset_latin1);
if (str->reserve(1 , 512 ))
return 0 ;
str->qs_append('{' );
if (options & 1 )
{
if (geom->bbox_as_json(str) || str->append(", " , 2 ))
goto error;
}
if ((geom->as_json(str, max_dec, &dummy) || str->append('}' )))
goto error;
return str;
error:
null_value= 1 ;
return 0 ;
}
String *Item_func_geometry_type::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed());
String *swkb= args[0 ]->val_str(str);
Geometry_buffer buffer;
Geometry *geom= NULL;
if ((null_value=
(args[0 ]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
return 0 ;
/* String will not move */
str->copy(geom->get_class_info()->m_name.str,
geom->get_class_info()->m_name.length,
&my_charset_latin1);
return str;
}
String *Item_func_envelope::val_str(String *str)
{
DBUG_ASSERT(fixed());
String arg_val;
String *swkb= args[0 ]->val_str(&arg_val);
Geometry_buffer buffer;
Geometry *geom= NULL;
uint32 srid;
if ((null_value=
args[0 ]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
return 0 ;
srid= uint4korr(swkb->ptr());
str->set_charset(&my_charset_bin);
str->length(0 );
if (str->reserve(SRID_SIZE, 512 ))
return 0 ;
str->q_append(srid);
return (null_value= geom->envelope(str)) ? 0 : str;
}
int Item_func_boundary::Transporter::single_point(double x, double y)
{
return 0 ;
}
int Item_func_boundary::Transporter::start_line()
{
n_points= 0 ;
current_type= Gcalc_function::shape_line;
return 0 ;
}
int Item_func_boundary::Transporter::complete_line()
{
current_type= (Gcalc_function::shape_type) 0 ;
if (n_points > 1 )
return m_receiver->single_point(last_x, last_y);
return 0 ;
}
int Item_func_boundary::Transporter::start_poly()
{
current_type= Gcalc_function::shape_polygon;
return 0 ;
}
int Item_func_boundary::Transporter::complete_poly()
{
current_type= (Gcalc_function::shape_type) 0 ;
return 0 ;
}
int Item_func_boundary::Transporter::start_ring()
{
n_points= 0 ;
return m_receiver->start_shape(Gcalc_function::shape_line);
}
int Item_func_boundary::Transporter::complete_ring()
{
if (n_points > 1 )
{
m_receiver->add_point(last_x, last_y);
}
m_receiver->complete_shape();
return 0 ;
}
int Item_func_boundary::Transporter::add_point(double x, double y)
{
++n_points;
if (current_type== Gcalc_function::shape_polygon)
{
/* Polygon's ring case */
if (n_points == 1 )
{
last_x= x;
last_y= y;
}
return m_receiver->add_point(x, y);
}
if (current_type== Gcalc_function::shape_line)
{
/* Line's case */
last_x= x;
last_y= y;
if (n_points == 1 )
return m_receiver->single_point(x, y);
}
return 0 ;
}
int Item_func_boundary::Transporter::start_collection(int n_objects)
{
return 0 ;
}
String *Item_func_boundary::val_str(String *str_value)
{
DBUG_ENTER("Item_func_boundary::val_str" );
DBUG_ASSERT(fixed());
String arg_val;
String *swkb= args[0 ]->val_str(&arg_val);
if ((null_value= args[0 ]->null_value))
DBUG_RETURN(0 );
Geometry_buffer buffer;
uint32 srid= 0 ;
Transporter trn(&res_receiver);
Geometry *g= Geometry::construct(&buffer, swkb->ptr(), swkb->length());
if ((null_value= !g))
DBUG_RETURN(0 );
if (g->store_shapes(&trn))
goto mem_error;
str_value->set_charset(&my_charset_bin);
str_value->length(0 );
if (str_value->reserve(SRID_SIZE, 512 ))
goto mem_error;
str_value->q_append(srid);
if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
goto mem_error;
res_receiver.reset();
DBUG_RETURN(str_value);
mem_error:
null_value= 1 ;
DBUG_RETURN(0 );
}
String *Item_func_centroid::val_str(String *str)
{
DBUG_ASSERT(fixed());
String arg_val;
String *swkb= args[0 ]->val_str(&arg_val);
Geometry_buffer buffer;
Geometry *geom= NULL;
uint32 srid;
if ((null_value= args[0 ]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
return 0 ;
str->set_charset(&my_charset_bin);
str->length(0 );
if (str->reserve(SRID_SIZE, 512 ))
return 0 ;
srid= uint4korr(swkb->ptr());
str->q_append(srid);
return (null_value= MY_TEST(geom->centroid(str))) ? 0 : str;
}
int Item_func_convexhull::add_node_to_line(ch_node **p_cur, int dir,
const Gcalc_heap::Info *pi)
{
ch_node *new_node;
ch_node *cur= *p_cur;
while (cur->prev)
{
int v_sign= Gcalc_scan_iterator::point::cmp_dx_dy(
cur->prev->pi, cur->pi, cur->pi, pi);
if (v_sign*dir <0 )
break ;
new_node= cur;
cur= cur->prev;
res_heap.free_item(new_node);
}
if (!(new_node= new_ch_node()))
return 1 ;
cur->next= new_node;
new_node->prev= cur;
new_node->pi= pi;
*p_cur= new_node;
return 0 ;
}
#ifndef HEAVY_CONVEX_HULL
String *Item_func_convexhull::val_str(String *str_value)
{
Geometry_buffer buffer;
Geometry *geom= NULL;
MBR mbr;
const char *c_end;
Gcalc_operation_transporter trn(&func, &collector);
uint32 srid= 0 ;
ch_node *left_first, *left_cur, *right_first, *right_cur;
Gcalc_heap::Info *cur_pi;
DBUG_ENTER("Item_func_convexhull::val_str" );
DBUG_ASSERT(fixed());
String *swkb= args[0 ]->val_str(&tmp_value);
if ((null_value=
args[0 ]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
DBUG_RETURN(0 );
geom->get_mbr(&mbr, &c_end);
collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax);
if ((null_value= geom->store_shapes(&trn)))
{
str_value= 0 ;
goto mem_error;
}
collector.prepare_operation();
if (!(cur_pi= collector.get_first()))
goto build_result; /* An EMPTY GEOMETRY */
if (!cur_pi->get_next())
{
/* Single point. */
if (res_receiver.single_point(cur_pi->node.shape.x, cur_pi->node.shape.y))
goto mem_error;
goto build_result;
}
left_cur= left_first= new_ch_node();
right_cur= right_first= new_ch_node();
right_first->prev= left_first->prev= 0 ;
right_first->pi= left_first->pi= cur_pi;
while ((cur_pi= cur_pi->get_next()))
{
/* Handle left part of the hull, then the right part. */
if (add_node_to_line(&left_cur, 1 , cur_pi))
goto mem_error;
if (add_node_to_line(&right_cur, -1 , cur_pi))
goto mem_error;
}
left_cur->next= 0 ;
if (left_first->get_next()->get_next() == NULL &&
right_cur->prev->prev == NULL)
{
/* We only have 2 nodes in the result, so we create a polyline. */
if (res_receiver.start_shape(Gcalc_function::shape_line) ||
res_receiver.add_point(left_first->pi->node.shape.x, left_first->pi->node.shape.y) ||
res_receiver.add_point(left_cur->pi->node.shape.x, left_cur->pi->node.shape.y) ||
res_receiver.complete_shape())
goto mem_error;
goto build_result;
}
if (res_receiver.start_shape(Gcalc_function::shape_polygon))
goto mem_error;
while (left_first)
{
if (res_receiver.add_point(left_first->pi->node.shape.x, left_first->pi->node.shape.y))
goto mem_error;
left_first= left_first->get_next();
}
/* Skip last point in the right part as it coincides */
/* with the last one in the left. */
right_cur= right_cur->prev;
while (right_cur->prev)
{
if (res_receiver.add_point(right_cur->pi->node.shape.x, right_cur->pi->node.shape.y))
goto mem_error;
right_cur= right_cur->prev;
}
res_receiver.complete_shape();
build_result:
str_value->set_charset(&my_charset_bin);
str_value->length(0 );
if (str_value->reserve(SRID_SIZE, 512 ))
goto mem_error;
str_value->q_append(srid);
if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
goto mem_error;
mem_error:
collector.reset();
func.reset();
res_receiver.reset();
res_heap.reset();
DBUG_RETURN(str_value);
}
#else /*HEAVY_CONVEX_HULL*/
String *Item_func_convexhull::val_str(String *str_value)
{
Geometry_buffer buffer;
Geometry *geom= NULL;
MBR mbr;
const char *c_end;
Gcalc_operation_transporter trn(&func, &collector);
const Gcalc_scan_iterator::event_point *ev;
uint32 srid= 0 ;
ch_node *left_first, *left_cur, *right_first, *right_cur;
DBUG_ENTER("Item_func_convexhull::val_str" );
DBUG_ASSERT(fixed());
String *swkb= args[0 ]->val_str(&tmp_value);
if ((null_value=
args[0 ]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
DBUG_RETURN(0 );
geom->get_mbr(&mbr, &c_end);
collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax);
if ((null_value= geom->store_shapes(&trn)))
{
str_value= 0 ;
goto mem_error;
}
collector.prepare_operation();
scan_it.init(&collector);
scan_it.killed= (int *) &(current_thd->killed);
if (!scan_it.more_points())
goto build_result; /* An EMPTY GEOMETRY */
if (scan_it.step())
goto mem_error;
if (!scan_it.more_points())
{
/* Single point. */
if (res_receiver.single_point(scan_it.get_events()->pi->x,
scan_it.get_events()->pi->y))
goto mem_error;
goto build_result;
}
left_cur= left_first= new_ch_node();
right_cur= right_first= new_ch_node();
right_first->prev= left_first->prev= 0 ;
right_first->pi= left_first->pi= scan_it.get_events()->pi;
while (scan_it.more_points())
{
if (scan_it.step())
goto mem_error;
ev= scan_it.get_events();
/* Skip the intersections-only events. */
while (ev->event == scev_intersection)
{
ev= ev->get_next();
if (!ev)
goto skip_point;
}
{
Gcalc_point_iterator pit(&scan_it);
if (!pit.point() || scan_it.get_event_position() == pit.point())
{
/* Handle left part of the hull. */
if (add_node_to_line(&left_cur, 1 , ev->pi))
goto mem_error;
}
if (pit.point())
{
/* Check the rightmost point */
for (; pit.point()->c_get_next(); ++pit)
;
}
if (!pit.point() || pit.point()->event ||
scan_it.get_event_position() == pit.point()->c_get_next())
{
/* Handle right part of the hull. */
if (add_node_to_line(&right_cur, -1 , ev->pi))
goto mem_error;
}
}
skip_point:;
}
left_cur->next= 0 ;
if (left_first->get_next()->get_next() == NULL &&
right_cur->prev->prev == NULL)
{
/* We only have 2 nodes in the result, so we create a polyline. */
if (res_receiver.start_shape(Gcalc_function::shape_line) ||
res_receiver.add_point(left_first->pi->x, left_first->pi->y) ||
res_receiver.add_point(left_cur->pi->x, left_cur->pi->y) ||
res_receiver.complete_shape())
goto mem_error;
goto build_result;
}
if (res_receiver.start_shape(Gcalc_function::shape_polygon))
goto mem_error;
while (left_first)
{
if (res_receiver.add_point(left_first->pi->x, left_first->pi->y))
goto mem_error;
left_first= left_first->get_next();
}
/* Skip last point in the right part as it coincides */
/* with the last one in the left. */
right_cur= right_cur->prev;
while (right_cur->prev)
{
if (res_receiver.add_point(right_cur->pi->x, right_cur->pi->y))
goto mem_error;
right_cur= right_cur->prev;
}
res_receiver.complete_shape();
build_result:
str_value->set_charset(&my_charset_bin);
str_value->length(0 );
if (str_value->reserve(SRID_SIZE, 512 ))
goto mem_error;
str_value->q_append(srid);
if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
goto mem_error;
mem_error:
collector.reset();
func.reset();
res_receiver.reset();
res_heap.reset();
DBUG_RETURN(str_value);
}
#endif /*HEAVY_CONVEX_HULL*/
/*
Spatial decomposition functions
*/
String *Item_func_spatial_decomp::val_str(String *str)
{
DBUG_ASSERT(fixed());
String arg_val;
String *swkb= args[0 ]->val_str(&arg_val);
Geometry_buffer buffer;
Geometry *geom= NULL;
uint32 srid;
if ((null_value=
(args[0 ]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
return 0 ;
srid= uint4korr(swkb->ptr());
str->set_charset(&my_charset_bin);
str->length(0 );
if (str->reserve(SRID_SIZE, 512 ))
goto err;
str->q_append(srid);
switch (decomp_func) {
case SP_STARTPOINT:
if (geom->start_point(str))
goto err;
break ;
case SP_ENDPOINT:
if (geom->end_point(str))
goto err;
break ;
case SP_EXTERIORRING:
if (geom->exterior_ring(str))
goto err;
break ;
default :
goto err;
}
return str;
err:
null_value= 1 ;
return 0 ;
}
String *Item_func_spatial_decomp_n::val_str(String *str)
{
DBUG_ASSERT(fixed());
String arg_val;
String *swkb= args[0 ]->val_str(&arg_val);
long n= (long ) args[1 ]->val_int();
Geometry_buffer buffer;
Geometry *geom= NULL;
uint32 srid;
if ((null_value=
(args[0 ]->null_value || args[1 ]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
return 0 ;
str->set_charset(&my_charset_bin);
str->length(0 );
if (str->reserve(SRID_SIZE, 512 ))
goto err;
srid= uint4korr(swkb->ptr());
str->q_append(srid);
switch (decomp_func_n)
{
case SP_POINTN:
if (geom->point_n(n,str))
goto err;
break ;
case SP_GEOMETRYN:
if (geom->geometry_n(n,str))
goto err;
break ;
case SP_INTERIORRINGN:
if (geom->interior_ring_n(n,str))
goto err;
break ;
default :
goto err;
}
return str;
err:
null_value=1 ;
return 0 ;
}
/*
Functions to concatenate various spatial objects
*/
/*
* Concatenate doubles into Point
*/
String *Item_func_point::val_str(String *str)
{
DBUG_ASSERT(fixed());
double x= args[0 ]->val_real();
double y= args[1 ]->val_real();
uint32 srid= 0 ;
if ((null_value= (args[0 ]->null_value ||
args[1 ]->null_value ||
str->alloc(4 /*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE * 2))))
return 0 ;
str->set_charset(&my_charset_bin);
str->length(0 );
str->q_append(srid);
str->q_append((char )Geometry::wkb_ndr);
str->q_append((uint32)Geometry::wkb_point);
str->q_append(x);
str->q_append(y);
return str;
}
/**
Concatenates various items into various collections
with checkings for valid wkb type of items .
For example , MultiPoint can be a collection of Points only .
coll_type contains wkb type of target collection .
item_type contains a valid wkb type of items .
In the case when coll_type is wkbGeometryCollection ,
we do not check wkb type of items , any is valid .
*/
String *Item_func_spatial_collection::val_str(String *str)
{
DBUG_ASSERT(fixed());
String arg_value;
uint i;
uint32 srid= 0 ;
str->set_charset(&my_charset_bin);
str->length(0 );
if (str->reserve(4 /*SRID*/ + 1 + 4 + 4, 512))
goto err;
str->q_append(srid);
str->q_append((char ) Geometry::wkb_ndr);
str->q_append((uint32) coll_type);
str->q_append((uint32) arg_count);
for (i= 0 ; i < arg_count; ++i)
{
String *res= args[i]->val_str(&arg_value);
uint32 len;
if (args[i]->null_value || ((len= res->length()) < WKB_HEADER_SIZE))
goto err;
if (coll_type == Geometry::wkb_geometrycollection)
{
/*
In the case of GeometryCollection we don ' t need any checkings
for item types , so just copy them into target collection
*/
if (str->append(res->ptr() + 4 /*SRID*/, len - 4/*SRID*/, (uint32) 512))
goto err;
}
else
{
enum Geometry::wkbType wkb_type;
const uint data_offset= 4 /*SRID*/ + 1;
if (res->length() < data_offset + sizeof (uint32))
goto err;
const char *data= res->ptr() + data_offset;
/*
In the case of named collection we must check that items
are of specific type , let ' s do this checking now
*/
wkb_type= (Geometry::wkbType) uint4korr(data);
data+= 4 ;
len-= 5 + 4 /*SRID*/;
if (wkb_type != item_type)
goto err;
switch (coll_type) {
case Geometry::wkb_multipoint:
case Geometry::wkb_multilinestring:
case Geometry::wkb_multipolygon:
if (len < WKB_HEADER_SIZE ||
str->append(data-WKB_HEADER_SIZE, len+WKB_HEADER_SIZE, 512 ))
goto err;
break ;
case Geometry::wkb_linestring:
if (len < POINT_DATA_SIZE || str->append(data, POINT_DATA_SIZE, 512 ))
goto err;
break ;
case Geometry::wkb_polygon:
{
uint32 n_points;
double x1, y1, x2, y2;
const char *org_data= data;
if (len < 4 )
goto err;
n_points= uint4korr(data);
data+= 4 ;
if (n_points < 2 || len < 4 + n_points * POINT_DATA_SIZE)
goto err;
float8get(x1, data);
data+= SIZEOF_STORED_DOUBLE;
float8get(y1, data);
data+= SIZEOF_STORED_DOUBLE;
data+= (n_points - 2 ) * POINT_DATA_SIZE;
float8get(x2, data);
float8get(y2, data + SIZEOF_STORED_DOUBLE);
if ((x1 != x2) || (y1 != y2) ||
str->append(org_data, len, 512 ))
goto err;
}
break ;
default :
goto err;
}
}
}
if (str->length() > current_thd->variables.max_allowed_packet)
{
THD *thd= current_thd;
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_WARN_ALLOWED_PACKET_OVERFLOWED,
ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
func_name(), thd->variables.max_allowed_packet);
goto err;
}
null_value = 0 ;
return str;
err:
null_value= 1 ;
return 0 ;
}
/*
Functions for spatial relations
*/
static SEL_ARG sel_arg_impossible(SEL_ARG::IMPOSSIBLE);
SEL_ARG *
Item_func_spatial_rel::get_mm_leaf(RANGE_OPT_PARAM *param,
Field *field, KEY_PART *key_part,
Item_func::Functype type, Item *value)
{
DBUG_ENTER("Item_func_spatial_rel::get_mm_leaf" );
if (key_part->image_type != Field::itMBR)
DBUG_RETURN(0 );
if (value->cmp_type() != STRING_RESULT)
DBUG_RETURN(&sel_arg_impossible);
if (param->using_real_indexes &&
!field->optimize_range(param->real_keynr[key_part->key],
key_part->part))
DBUG_RETURN(0 );
Field_geom *field_geom= dynamic_cast <Field_geom*>(field);
DBUG_ASSERT(field_geom);
const Type_handler_geometry *sav_geom_type= field_geom->type_handler_geom();
// We have to be able to store all sorts of spatial features here
field_geom->set_type_handler(&type_handler_geometry);
bool rc= value->save_in_field_no_warnings(field, 1 );
field_geom->set_type_handler(sav_geom_type);
if (rc)
DBUG_RETURN(&sel_arg_impossible); // Bad GEOMETRY value
DBUG_ASSERT(!field->real_maybe_null()); // SPATIAL keys do not support NULL
uchar *str= (uchar*) alloc_root(param->mem_root, key_part->store_length + 1 );
if (!str)
DBUG_RETURN(0 ); // out of memory
field->get_key_image(str, key_part->length, key_part->image_type);
SEL_ARG *tree;
if (!(tree= new (param->mem_root) SEL_ARG(field, str, str)))
DBUG_RETURN(0 ); // out of memory
switch (type) {
case SP_EQUALS_FUNC:
tree->min_flag= GEOM_FLAG | HA_READ_MBR_EQUAL;// NEAR_MIN;//512;
tree->max_flag= NO_MAX_RANGE;
break ;
case SP_DISJOINT_FUNC:
tree->min_flag= GEOM_FLAG | HA_READ_MBR_DISJOINT;// NEAR_MIN;//512;
tree->max_flag= NO_MAX_RANGE;
break ;
case SP_INTERSECTS_FUNC:
tree->min_flag= GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
tree->max_flag= NO_MAX_RANGE;
break ;
case SP_TOUCHES_FUNC:
tree->min_flag= GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
tree->max_flag= NO_MAX_RANGE;
break ;
case SP_CROSSES_FUNC:
tree->min_flag= GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
tree->max_flag= NO_MAX_RANGE;
break ;
case SP_WITHIN_FUNC:
tree->min_flag= GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512;
tree->max_flag= NO_MAX_RANGE;
break ;
case SP_CONTAINS_FUNC:
tree->min_flag= GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512;
tree->max_flag= NO_MAX_RANGE;
break ;
case SP_OVERLAPS_FUNC:
tree->min_flag= GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
tree->max_flag= NO_MAX_RANGE;
break ;
default :
DBUG_ASSERT(0 );
break ;
}
DBUG_RETURN(tree);
}
LEX_CSTRING Item_func_spatial_mbr_rel::func_name_cstring() const
{
switch (spatial_rel) {
case SP_CONTAINS_FUNC:
return { STRING_WITH_LEN("mbrcontains" ) };
case SP_COVEREDBY_FUNC:
return { STRING_WITH_LEN("mbrcoveredby" ) };
case SP_WITHIN_FUNC:
return { STRING_WITH_LEN("mbrwithin" ) } ;
case SP_EQUALS_FUNC:
return { STRING_WITH_LEN("mbrequals" ) };
case SP_DISJOINT_FUNC:
return { STRING_WITH_LEN("mbrdisjoint" ) };
case SP_INTERSECTS_FUNC:
return { STRING_WITH_LEN("mbrintersects" ) };
case SP_TOUCHES_FUNC:
return { STRING_WITH_LEN("mbrtouches" ) };
case SP_CROSSES_FUNC:
return { STRING_WITH_LEN("mbrcrosses" ) };
case SP_OVERLAPS_FUNC:
return { STRING_WITH_LEN("mbroverlaps" ) };
default :
DBUG_ASSERT(0 ); // Should never happened
return { STRING_WITH_LEN("mbrsp_unknown" ) };
}
}
bool Item_func_spatial_mbr_rel::val_bool()
{
DBUG_ASSERT(fixed());
String *res1= args[0 ]->val_str(&tmp_value1);
String *res2= args[1 ]->val_str(&tmp_value2);
Geometry_buffer buffer1, buffer2;
Geometry *g1, *g2;
MBR mbr1, mbr2;
const char *dummy;
if ((null_value=
(args[0 ]->null_value ||
args[1 ]->null_value ||
!(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) ||
!(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) ||
g1->get_mbr(&mbr1, &dummy) || !mbr1.valid() ||
g2->get_mbr(&mbr2, &dummy) || !mbr2.valid())))
return 0 ;
uint32 srid1= uint4korr(res1->ptr()), srid2= uint4korr(res2->ptr());
if (srid1 != srid2)
my_error(ER_GIS_DIFFERENT_SRIDS, MYF(0 ), func_name(), srid1, srid2);
switch (spatial_rel) {
case SP_CONTAINS_FUNC:
return mbr1.contains(&mbr2);
case SP_COVEREDBY_FUNC:
return mbr1.coveredby(&mbr2);
case SP_WITHIN_FUNC:
return mbr1.within(&mbr2);
case SP_EQUALS_FUNC:
return mbr1.equals(&mbr2);
case SP_DISJOINT_FUNC:
return mbr1.disjoint(&mbr2);
case SP_INTERSECTS_FUNC:
return mbr1.intersects(&mbr2);
case SP_TOUCHES_FUNC:
return mbr1.touches(&mbr2);
case SP_OVERLAPS_FUNC:
return mbr1.overlaps(&mbr2);
case SP_CROSSES_FUNC:
return 0 ;
default :
break ;
}
null_value=1 ;
return 0 ;
}
LEX_CSTRING Item_func_spatial_precise_rel::func_name_cstring() const
{
switch (spatial_rel) {
case SP_CONTAINS_FUNC:
return { STRING_WITH_LEN("st_contains" ) };
case SP_COVEREDBY_FUNC:
return { STRING_WITH_LEN("st_coveredby" ) };
case SP_WITHIN_FUNC:
return { STRING_WITH_LEN("st_within" ) };
case SP_EQUALS_FUNC:
return { STRING_WITH_LEN("st_equals" ) };
case SP_DISJOINT_FUNC:
return { STRING_WITH_LEN("st_disjoint" ) };
case SP_INTERSECTS_FUNC:
return { STRING_WITH_LEN("st_intersects" ) };
case SP_TOUCHES_FUNC:
return { STRING_WITH_LEN("st_touches" ) };
case SP_CROSSES_FUNC:
return { STRING_WITH_LEN("st_crosses" ) };
case SP_OVERLAPS_FUNC:
return { STRING_WITH_LEN("st_overlaps" ) } ;
default :
DBUG_ASSERT(0 ); // Should never happened
return { STRING_WITH_LEN("sp_unknown" ) };
}
}
static double count_edge_t(const Gcalc_heap::Info *ea,
const Gcalc_heap::Info *eb,
const Gcalc_heap::Info *v,
double &ex, double &ey, double &vx, double &vy,
double &e_sqrlen)
{
ex= eb->node.shape.x - ea->node.shape.x;
ey= eb->node.shape.y - ea->node.shape.y;
vx= v->node.shape.x - ea->node.shape.x;
vy= v->node.shape.y - ea->node.shape.y;
e_sqrlen= ex * ex + ey * ey;
return (ex * vx + ey * vy) / e_sqrlen;
}
static double distance_to_line(double ex, double ey, double vx, double vy,
double e_sqrlen)
{
return fabs(vx * ey - vy * ex) / sqrt(e_sqrlen);
}
static double distance_points(const Gcalc_heap::Info *a,
const Gcalc_heap::Info *b)
{
double x= a->node.shape.x - b->node.shape.x;
double y= a->node.shape.y - b->node.shape.y;
return sqrt(x * x + y * y);
}
static Gcalc_function::op_type op_matrix(int n)
{
switch (n)
{
case 0 :
return Gcalc_function::op_internals;
case 1 :
return Gcalc_function::op_border;
case 2 :
return (Gcalc_function::op_type)
((int ) Gcalc_function::op_not | (int ) Gcalc_function::op_union);
};
GCALC_DBUG_ASSERT(FALSE );
return Gcalc_function::op_any;
}
static int setup_relate_func(Geometry *g1, Geometry *g2,
Gcalc_operation_transporter *trn, Gcalc_function *func,
const char *mask)
{
int do_store_shapes=1 ;
uint UNINIT_VAR(shape_a), UNINIT_VAR(shape_b);
uint n_operands= 0 ;
int last_shape_pos;
last_shape_pos= func->get_next_expression_pos();
if (func->reserve_op_buffer(1 ))
return 1 ;
func->add_operation(Gcalc_function::op_intersection, 0 );
for (int nc=0 ; nc<9 ; nc++)
{
uint cur_op;
cur_op= Gcalc_function::op_intersection;
switch (mask[nc])
{
case '*' :
continue ;
case 'T' :
case '0' :
case '1' :
case '2' :
cur_op|= Gcalc_function::v_find_t;
break ;
case 'F' :
cur_op|= (Gcalc_function::op_not | Gcalc_function::v_find_f);
break ;
default :
return 1 ;
};
++n_operands;
if (func->reserve_op_buffer(3 ))
return 1 ;
func->add_operation(cur_op, 2 );
func->add_operation(op_matrix(nc/3 ), 1 );
if (do_store_shapes)
{
shape_a= func->get_next_expression_pos();
if (g1->store_shapes(trn))
return 1 ;
}
else
func->repeat_expression(shape_a);
if (func->reserve_op_buffer(1 ))
return 1 ;
func->add_operation(op_matrix(nc%3 ), 1 );
if (do_store_shapes)
{
shape_b= func->get_next_expression_pos();
if (g2->store_shapes(trn))
return 1 ;
do_store_shapes= 0 ;
}
else
func->repeat_expression(shape_b);
}
func->add_operands_to_op(last_shape_pos, n_operands);
return 0 ;
}
#define GIS_ZERO 0 .00000000001
class Geometry_ptr_with_buffer_and_mbr
{
public :
Geometry *geom;
Geometry_buffer buffer;
MBR mbr;
bool construct(Item *item, String *tmp_value)
{
const char *c_end;
String *res= item->val_str(tmp_value);
return
item->null_value ||
!(geom= Geometry::construct(&buffer, res->ptr(), res->length())) ||
geom->get_mbr(&mbr, &c_end) || !mbr.valid();
}
int store_shapes(Gcalc_shape_transporter *trn) const
{ return geom->store_shapes(trn); }
int shape_type() const
{ return geom->get_class_info()->m_type_id; }
};
bool Item_func_spatial_relate::val_bool()
{
DBUG_ENTER("Item_func_spatial_relate::val_int" );
DBUG_ASSERT(fixed());
Geometry_ptr_with_buffer_and_mbr g1, g2;
int result= 0 ;
if ((null_value= (g1.construct(args[0 ], &tmp_value1) ||
g2.construct(args[1 ], &tmp_value2) ||
func.reserve_op_buffer(1 ))))
DBUG_RETURN(0 );
MBR umbr(g1.mbr, g2.mbr);
collector.set_extent(umbr.xmin, umbr.xmax, umbr.ymin, umbr.ymax);
g1.mbr.buffer(1 e-5 );
Gcalc_operation_transporter trn(&func, &collector);
String *matrix= args[2 ]->val_str(&tmp_matrix);
if ((null_value= args[2 ]->null_value || matrix->length() != 9 ||
setup_relate_func(g1.geom, g2.geom,
&trn, &func, matrix->ptr())))
goto exit ;
collector.prepare_operation();
scan_it.init(&collector);
scan_it.killed= (int *) &(current_thd->killed);
if (!func.alloc_states())
result= func.check_function(scan_it);
exit :
collector.reset();
func.reset();
scan_it.reset();
DBUG_RETURN(result);
}
static void handle_sp_crosses_func_case(Gcalc_function &func,
Gcalc_operation_transporter &trn,
Geometry_ptr_with_buffer_and_mbr &g1,
Geometry_ptr_with_buffer_and_mbr &g2,
uint &shape_a, uint &shape_b,
bool &null_value)
{
func.add_operation(Gcalc_function::op_intersection, 2 );
if (func.reserve_op_buffer(3 ))
return ;
func.add_operation(Gcalc_function::v_find_t |
Gcalc_function::op_intersection, 2 );
shape_a= func.get_next_expression_pos();
if ((null_value= g1.store_shapes(&trn)))
return ;
shape_b= func.get_next_expression_pos();
if ((null_value= g2.store_shapes(&trn)))
return ;
if (func.reserve_op_buffer(7 ))
return ;
func.add_operation(Gcalc_function::op_intersection, 2 );
func.add_operation(Gcalc_function::v_find_t |
Gcalc_function::op_difference, 2 );
func.repeat_expression(shape_a);
func.repeat_expression(shape_b);
func.add_operation(Gcalc_function::v_find_t |
Gcalc_function::op_difference, 2 );
func.repeat_expression(shape_b);
func.repeat_expression(shape_a);
}
bool Item_func_spatial_precise_rel::val_bool()
{
DBUG_ENTER("Item_func_spatial_precise_rel::val_int" );
DBUG_ASSERT(fixed());
Geometry_ptr_with_buffer_and_mbr g1, g2;
int result= 0 ;
uint shape_a, shape_b;
if ((null_value= (g1.construct(args[0 ], &tmp_value1) ||
g2.construct(args[1 ], &tmp_value2) ||
func.reserve_op_buffer(1 ))))
DBUG_RETURN(0 );
Gcalc_operation_transporter trn(&func, &collector);
MBR umbr(g1.mbr, g2.mbr);
collector.set_extent(umbr.xmin, umbr.xmax, umbr.ymin, umbr.ymax);
g1.mbr.buffer(1 e-5 );
switch (spatial_rel) {
case SP_CONTAINS_FUNC:
if (!g1.mbr.contains(&g2.mbr))
goto exit ;
func.add_operation(Gcalc_function::v_find_f |
Gcalc_function::op_not |
Gcalc_function::op_difference, 2 );
/* Mind the g2 goes first. */
null_value= g2.store_shapes(&trn) || g1.store_shapes(&trn);
break ;
case SP_WITHIN_FUNC:
g2.mbr.buffer(2 e-5 );
if (!g1.mbr.within(&g2.mbr))
goto exit ;
func.add_operation(Gcalc_function::v_find_f |
Gcalc_function::op_not |
Gcalc_function::op_difference, 2 );
null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn);
break ;
case SP_EQUALS_FUNC:
if (!g1.mbr.contains(&g2.mbr))
goto exit ;
func.add_operation(Gcalc_function::v_find_f |
Gcalc_function::op_not |
Gcalc_function::op_symdifference, 2 );
null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn);
break ;
case SP_DISJOINT_FUNC:
func.add_operation(Gcalc_function::v_find_f |
Gcalc_function::op_not |
Gcalc_function::op_intersection, 2 );
null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn);
break ;
case SP_INTERSECTS_FUNC:
if (!g1.mbr.intersects(&g2.mbr))
goto exit ;
func.add_operation(Gcalc_function::v_find_t |
Gcalc_function::op_intersection, 2 );
null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn);
break ;
case SP_CROSSES_FUNC:
if (g1.shape_type() == Geometry::wkb_polygon ||
g1.shape_type() == Geometry::wkb_multipolygon ||
g2.shape_type() == Geometry::wkb_point ||
g2.shape_type() == Geometry::wkb_multipoint)
{
null_value= true ;
goto exit ;
}
handle_sp_crosses_func_case(func, trn, g1, g2,
shape_a, shape_b, null_value);
break ;
case SP_OVERLAPS_FUNC:
{
// Both geometries must have the same number of dimensions.
uint32 g1_dim, g2_dim;
const char *dummy;
g1.geom->dimension(&g1_dim, &dummy);
g2.geom->dimension(&g2_dim, &dummy);
if (g1_dim != g2_dim)
DBUG_RETURN(0 );
handle_sp_crosses_func_case(func, trn, g1, g2,
shape_a, shape_b, null_value);
break ;
}
case SP_TOUCHES_FUNC:
if (func.reserve_op_buffer(5 ))
break ;
func.add_operation(Gcalc_function::op_intersection, 2 );
func.add_operation(Gcalc_function::v_find_f |
Gcalc_function::op_not |
Gcalc_function::op_intersection, 2 );
func.add_operation(Gcalc_function::op_internals, 1 );
shape_a= func.get_next_expression_pos();
if ((null_value= g1.store_shapes(&trn)) ||
func.reserve_op_buffer(1 ))
break ;
func.add_operation(Gcalc_function::op_internals, 1 );
shape_b= func.get_next_expression_pos();
if ((null_value= g2.store_shapes(&trn)) ||
func.reserve_op_buffer(1 ))
break ;
func.add_operation(Gcalc_function::v_find_t |
Gcalc_function::op_intersection, 2 );
func.repeat_expression(shape_a);
func.repeat_expression(shape_b);
break ;
case SP_COVEREDBY_FUNC:
if (!g1.mbr.coveredby(&g2.mbr))
goto exit ;
func.add_operation(Gcalc_function::v_find_f |
Gcalc_function::op_not |
Gcalc_function::op_difference, 2 );
null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn);
break ;
default :
DBUG_ASSERT(FALSE );
break ;
}
if (null_value)
goto exit ;
collector.prepare_operation();
scan_it.init(&collector);
scan_it.killed= (int *) &(current_thd->killed);
if (func.alloc_states())
goto exit ;
result= func.check_function(scan_it);
exit :
collector.reset();
func.reset();
scan_it.reset();
DBUG_RETURN(result);
}
Item_func_spatial_operation::~Item_func_spatial_operation() = default ;
String *Item_func_spatial_operation::val_str(String *str_value)
{
DBUG_ENTER("Item_func_spatial_operation::val_str" );
DBUG_ASSERT(fixed());
Geometry_ptr_with_buffer_and_mbr g1, g2;
uint32 srid= 0 ;
Gcalc_operation_transporter trn(&func, &collector);
if (func.reserve_op_buffer(1 ))
DBUG_RETURN(0 );
func.add_operation(spatial_op, 2 );
if ((null_value= (g1.construct(args[0 ], &tmp_value1) ||
g2.construct(args[1 ], &tmp_value2))))
{
str_value= 0 ;
goto exit ;
}
g1.mbr.add_mbr(&g2.mbr);
collector.set_extent(g1.mbr.xmin, g1.mbr.xmax, g1.mbr.ymin, g1.mbr.ymax);
if ((null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn)))
{
str_value= 0 ;
goto exit ;
}
collector.prepare_operation();
if (func.alloc_states())
goto exit ;
operation.init(&func);
if (operation.count_all(&collector) ||
operation.get_result(&res_receiver))
goto exit ;
str_value->set_charset(&my_charset_bin);
str_value->length(0 );
if (str_value->reserve(SRID_SIZE, 512 ))
goto exit ;
str_value->q_append(srid);
if (!Geometry::create_from_opresult(&g1.buffer, str_value, res_receiver))
goto exit ;
exit :
collector.reset();
func.reset();
res_receiver.reset();
DBUG_RETURN(str_value);
}
LEX_CSTRING Item_func_spatial_operation::func_name_cstring() const
{
switch (spatial_op) {
case Gcalc_function::op_intersection:
return { STRING_WITH_LEN("st_intersection" ) };
case Gcalc_function::op_difference:
return { STRING_WITH_LEN("st_difference" ) };
case Gcalc_function::op_union:
return { STRING_WITH_LEN("st_union" ) };
case Gcalc_function::op_symdifference:
return { STRING_WITH_LEN("st_symdifference" ) };
default :
DBUG_ASSERT(0 ); // Should never happen
return { STRING_WITH_LEN("sp_unknown" ) };
}
}
static const int SINUSES_CALCULATED= 32 ;
static double n_sinus[SINUSES_CALCULATED+1 ]=
{
0 ,
0 .04906767432741802 ,
0 .0980171403295606 ,
0 .1467304744553618 ,
0 .1950903220161283 ,
0 .2429801799032639 ,
0 .2902846772544623 ,
0 .3368898533922201 ,
0 .3826834323650898 ,
0 .4275550934302821 ,
0 .4713967368259976 ,
0 .5141027441932217 ,
0 .5555702330196022 ,
0 .5956993044924334 ,
0 .6343932841636455 ,
0 .6715589548470183 ,
0 .7071067811865475 ,
0 .7409511253549591 ,
0 .773010453362737 ,
0 .8032075314806448 ,
0 .8314696123025452 ,
0 .8577286100002721 ,
0 .8819212643483549 ,
0 .9039892931234433 ,
0 .9238795325112867 ,
0 .9415440651830208 ,
0 .9569403357322089 ,
0 .970031253194544 ,
0 .9807852804032304 ,
0 .989176509964781 ,
0 .9951847266721968 ,
0 .9987954562051724 ,
1
};
static void get_n_sincos(int n, double *sinus, double *cosinus)
{
DBUG_ASSERT(n > 0 && n < SINUSES_CALCULATED*2 +1 );
if (n < (SINUSES_CALCULATED + 1 ))
{
*sinus= n_sinus[n];
*cosinus= n_sinus[SINUSES_CALCULATED - n];
}
else
{
n-= SINUSES_CALCULATED;
*sinus= n_sinus[SINUSES_CALCULATED - n];
*cosinus= -n_sinus[n];
}
}
static int fill_half_circle(Gcalc_shape_transporter *trn, double x, double y,
double ax, double ay)
{
double n_sin, n_cos;
double x_n, y_n;
for (int n = 1 ; n < (SINUSES_CALCULATED * 2 - 1 ); n++)
{
get_n_sincos(n, &n_sin, &n_cos);
x_n= ax * n_cos - ay * n_sin;
y_n= ax * n_sin + ay * n_cos;
if (trn->add_point(x_n + x, y_n + y))
return 1 ;
}
return 0 ;
}
static int fill_gap(Gcalc_shape_transporter *trn,
double x, double y,
double ax, double ay, double bx, double by, double d,
bool *empty_gap)
{
double ab= ax * bx + ay * by;
double cosab= ab / (d * d) + GIS_ZERO;
double n_sin, n_cos;
double x_n, y_n;
int n=1 ;
*empty_gap= true ;
for (;;)
{
get_n_sincos(n++, &n_sin, &n_cos);
if (n_cos <= cosab)
break ;
*empty_gap= false ;
x_n= ax * n_cos - ay * n_sin;
y_n= ax * n_sin + ay * n_cos;
if (trn->add_point(x_n + x, y_n + y))
return 1 ;
}
return 0 ;
}
/*
Calculates the vector ( p2 , p1 ) and
negatively orthogonal to it with the length of d .
The result is ( ex , ey ) - the vector , ( px , py ) - the orthogonal .
*/
static void calculate_perpendicular(
double x1, double y1, double x2, double y2, double d,
double *ex, double *ey,
double *px, double *py)
{
double q;
*ex= x1 - x2;
*ey= y1 - y2;
q= d / sqrt((*ex) * (*ex) + (*ey) * (*ey));
*px= (*ey) * q;
*py= -(*ex) * q;
}
int Item_func_buffer::Transporter::single_point(double x, double y)
{
if (buffer_op == Gcalc_function::op_difference)
{
if (m_fn->reserve_op_buffer(1 ))
return 1 ;
m_fn->add_operation(Gcalc_function::op_false, 0 );
return 0 ;
}
m_nshapes= 0 ;
return add_point_buffer(x, y);
}
int Item_func_buffer::Transporter::add_edge_buffer(
double x3, double y3, bool round_p1, bool round_p2)
{
Gcalc_operation_transporter trn(m_fn, m_heap);
double e1_x, e1_y, e2_x, e2_y, p1_x, p1_y, p2_x, p2_y;
double e1e2;
double sin1, cos1;
double x_n, y_n;
bool empty_gap1, empty_gap2;
++m_nshapes;
if (trn.start_simple_poly())
return 1 ;
calculate_perpendicular(x1, y1, x2, y2, m_d, &e1_x, &e1_y, &p1_x, &p1_y);
calculate_perpendicular(x3, y3, x2, y2, m_d, &e2_x, &e2_y, &p2_x, &p2_y);
e1e2= e1_x * e2_y - e2_x * e1_y;
sin1= n_sinus[1 ];
cos1= n_sinus[31 ];
if (e1e2 < 0 )
{
empty_gap2= false ;
x_n= x2 + p2_x * cos1 - p2_y * sin1;
y_n= y2 + p2_y * cos1 + p2_x * sin1;
if (fill_gap(&trn, x2, y2, -p1_x,-p1_y, p2_x,p2_y, m_d, &empty_gap1) ||
trn.add_point(x2 + p2_x, y2 + p2_y) ||
trn.add_point(x_n, y_n))
return 1 ;
}
else
{
x_n= x2 - p2_x * cos1 - p2_y * sin1;
y_n= y2 - p2_y * cos1 + p2_x * sin1;
if (trn.add_point(x_n, y_n) ||
trn.add_point(x2 - p2_x, y2 - p2_y) ||
fill_gap(&trn, x2, y2, -p2_x, -p2_y, p1_x, p1_y, m_d, &empty_gap2))
return 1 ;
empty_gap1= false ;
}
if ((!empty_gap2 && trn.add_point(x2 + p1_x, y2 + p1_y)) ||
trn.add_point(x1 + p1_x, y1 + p1_y))
return 1 ;
if (round_p1 && fill_half_circle(&trn, x1, y1, p1_x, p1_y))
return 1 ;
if (trn.add_point(x1 - p1_x, y1 - p1_y) ||
(!empty_gap1 && trn.add_point(x2 - p1_x, y2 - p1_y)))
return 1 ;
return trn.complete_simple_poly();
}
int Item_func_buffer::Transporter::add_last_edge_buffer()
{
Gcalc_operation_transporter trn(m_fn, m_heap);
double e1_x, e1_y, p1_x, p1_y;
++m_nshapes;
if (trn.start_simple_poly())
return 1 ;
calculate_perpendicular(x1, y1, x2, y2, m_d, &e1_x, &e1_y, &p1_x, &p1_y);
if (trn.add_point(x1 + p1_x, y1 + p1_y) ||
trn.add_point(x1 - p1_x, y1 - p1_y) ||
trn.add_point(x2 - p1_x, y2 - p1_y) ||
fill_half_circle(&trn, x2, y2, -p1_x, -p1_y) ||
trn.add_point(x2 + p1_x, y2 + p1_y))
return 1 ;
return trn.complete_simple_poly();
}
int Item_func_buffer::Transporter::add_point_buffer(double x, double y)
{
Gcalc_operation_transporter trn(m_fn, m_heap);
m_nshapes++;
if (trn.start_simple_poly())
return 1 ;
if (trn.add_point(x - m_d, y) ||
fill_half_circle(&trn, x, y, -m_d, 0 .0 ) ||
trn.add_point(x + m_d, y) ||
fill_half_circle(&trn, x, y, m_d, 0 .0 ))
return 1 ;
return trn.complete_simple_poly();
}
int Item_func_buffer::Transporter::start_line()
{
if (buffer_op == Gcalc_function::op_difference)
{
if (m_fn->reserve_op_buffer(1 ))
return 1 ;
m_fn->add_operation(Gcalc_function::op_false, 0 );
skip_line= TRUE ;
return 0 ;
}
m_nshapes= 0 ;
if (m_fn->reserve_op_buffer(2 ))
return 1 ;
last_shape_pos= m_fn->get_next_expression_pos();
m_fn->add_operation(buffer_op, 0 );
m_npoints= 0 ;
int_start_line();
return 0 ;
}
int Item_func_buffer::Transporter::start_poly()
{
m_nshapes= 1 ;
if (m_fn->reserve_op_buffer(2 ))
return 1 ;
last_shape_pos= m_fn->get_next_expression_pos();
m_fn->add_operation(buffer_op, 0 );
return Gcalc_operation_transporter::start_poly();
}
int Item_func_buffer::Transporter::complete_poly()
{
if (Gcalc_operation_transporter::complete_poly())
return 1 ;
m_fn->add_operands_to_op(last_shape_pos, m_nshapes);
return 0 ;
}
int Item_func_buffer::Transporter::start_ring()
{
m_npoints= 0 ;
return Gcalc_operation_transporter::start_ring();
}
int Item_func_buffer::Transporter::start_collection(int n_objects)
{
if (m_fn->reserve_op_buffer(1 ))
return 1 ;
m_fn->add_operation(Gcalc_function::op_union, n_objects);
return 0 ;
}
int Item_func_buffer::Transporter::add_point(double x, double y)
{
if (skip_line)
return 0 ;
if (m_npoints && x == x2 && y == y2)
return 0 ;
++m_npoints;
if (m_npoints == 1 )
{
x00= x;
y00= y;
}
else if (m_npoints == 2 )
{
x01= x;
y01= y;
}
else if (add_edge_buffer(x, y, (m_npoints == 3 ) && line_started(), false ))
return 1 ;
x1= x2;
y1= y2;
x2= x;
y2= y;
return line_started() ? 0 : Gcalc_operation_transporter::add_point(x, y);
}
int Item_func_buffer::Transporter::complete()
{
if (m_npoints)
{
if (m_npoints == 1 )
{
if (add_point_buffer(x2, y2))
return 1 ;
}
else if (m_npoints == 2 )
{
if (add_edge_buffer(x1, y1, true , true ))
return 1 ;
}
else if (line_started())
{
if (add_last_edge_buffer())
return 1 ;
}
else
{
if (x2 != x00 || y2 != y00)
{
if (add_edge_buffer(x00, y00, false , false ))
return 1 ;
x1= x2;
y1= y2;
x2= x00;
y2= y00;
}
if (add_edge_buffer(x01, y01, false , false ))
return 1 ;
}
}
return 0 ;
}
int Item_func_buffer::Transporter::complete_line()
{
if (!skip_line)
{
if (complete())
return 1 ;
int_complete_line();
m_fn->add_operands_to_op(last_shape_pos, m_nshapes);
}
skip_line= FALSE ;
return 0 ;
}
int Item_func_buffer::Transporter::complete_ring()
{
return complete() ||
Gcalc_operation_transporter::complete_ring();
}
String *Item_func_buffer::val_str(String *str_value)
{
DBUG_ENTER("Item_func_buffer::val_str" );
DBUG_ASSERT(fixed());
String *obj= args[0 ]->val_str(str_value);
double dist= args[1 ]->val_real();
Geometry_buffer buffer;
Geometry *g;
uint32 srid= 0 ;
String *str_result= NULL;
Transporter trn(&func, &collector, dist);
MBR mbr;
const char *c_end;
null_value= 1 ;
if (args[0 ]->null_value || args[1 ]->null_value ||
!(g= Geometry::construct(&buffer, obj->ptr(), obj->length())) ||
g->get_mbr(&mbr, &c_end))
goto mem_error;
if (dist > 0 .0 )
mbr.buffer(dist);
else
{
/* This happens when dist is too far negative. */
if (mbr.xmax + dist < mbr.xmin || mbr.ymax + dist < mbr.ymin)
goto return_empty_result;
}
collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax);
/*
If the distance given is 0 , the Buffer function is in fact NOOP ,
so it ' s natural just to return the argument1 .
Besides , internal calculations here can ' t handle zero distance anyway .
*/
if (fabs(dist) < GIS_ZERO)
{
null_value= 0 ;
str_result= obj;
goto mem_error;
}
if (g->store_shapes(&trn))
goto mem_error;
collector.prepare_operation();
if (func.alloc_states())
goto mem_error;
operation.init(&func);
operation.killed= (int *) &(current_thd->killed);
if (operation.count_all(&collector) ||
operation.get_result(&res_receiver))
goto mem_error;
return_empty_result:
str_value->set_charset(&my_charset_bin);
str_value->length(0 );
if (str_value->reserve(SRID_SIZE, 512 ))
goto mem_error;
str_value->q_append(srid);
if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
goto mem_error;
null_value= 0 ;
str_result= str_value;
mem_error:
collector.reset();
func.reset();
res_receiver.reset();
DBUG_RETURN(str_result);
}
longlong Item_func_isvalid::val_int()
{
String *wkb= args[0 ]->val_str(&tmp);
Geometry_buffer buffer;
Geometry *geometry;
null_value= 1 ;
int valid;
if ((args[0 ]->null_value ||
!(geometry= Geometry::construct(&buffer, wkb->ptr(), wkb->length()))))
{
if (!args[0 ]->null_value)
my_error(ER_GIS_INVALID_DATA, MYF(0 ), func_name());
return 1 ;
}
if (geometry->is_valid(&valid))
return 1 ;
null_value= 0 ;
return (longlong) valid;
}
String *Item_func_validate::val_str(String *str_value)
{
DBUG_ENTER("Item_func_buffer::val_str" );
DBUG_ASSERT(fixed());
String *wkb= args[0 ]->val_str(&tmp);
Geometry_buffer buffer;
Geometry *geometry;
int valid= 1 ;
str_value= NULL;
null_value= 1 ;
if (args[0 ]->null_value)
DBUG_RETURN(str_value);
if (!(geometry= Geometry::construct(&buffer, wkb->ptr(), wkb->length())))
{
my_error(ER_GIS_INVALID_DATA, MYF(0 ), func_name());
DBUG_RETURN(str_value);
}
if (geometry->get_class_info()->m_type_id == Geometry::wkb_point)
{
double x, y;
if (((Gis_point *) geometry)->get_xy(&x, &y))
DBUG_RETURN(str_value);
if (x > MAX_LONGITUDE || x <= MIN_LONGITUDE)
{
my_error(ER_LATITUDE_OUT_OF_RANGE, MYF(0 ), x, "st_validate" );
DBUG_RETURN(str_value);
}
else if (y > MAX_LATITUDE || y < MIN_LATITUDE) {
my_error(ER_LONGITUDE_OUT_OF_RANGE, MYF(0 ), y,"st_validate" );
DBUG_RETURN(str_value);
}
null_value= 0 ;
str_value= wkb;
DBUG_RETURN(str_value);
}
if (geometry->is_valid(&valid))
DBUG_RETURN(str_value);
if (!valid)
DBUG_RETURN(str_value);
if (geometry->get_class_info()->m_type_id == Geometry::wkb_polygon ||
geometry->get_class_info()->m_type_id == Geometry::wkb_multipolygon ||
geometry->get_class_info()->m_type_id ==
Geometry::wkb_geometrycollection)
{
String clockwise_wkb;
if (geometry->make_clockwise(&clockwise_wkb))
DBUG_RETURN(str_value);
wkb->length(4 ); // keep the SRID
wkb->append(clockwise_wkb.ptr(), clockwise_wkb.length());
}
null_value= 0 ;
str_value= wkb;
DBUG_RETURN(str_value);
}
bool Item_func_isempty::val_bool()
{
DBUG_ASSERT(fixed());
String tmp;
String *swkb= args[0 ]->val_str(&tmp);
Geometry_buffer buffer;
null_value= args[0 ]->null_value ||
!(Geometry::construct(&buffer, swkb->ptr(), swkb->length()));
return null_value ? 1 : 0 ;
}
longlong Item_func_issimple::val_int()
{
String *swkb= args[0 ]->val_str(&tmp);
Geometry_buffer buffer;
Geometry *geometry;
DBUG_ENTER("Item_func_issimple::val_int" );
DBUG_ASSERT(fixed());
null_value= 0 ;
if ((args[0 ]->null_value ||
!(geometry= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
{
if (!args[0 ]->null_value)
my_error(ER_GIS_INVALID_DATA, MYF(0 ), func_name());
null_value= 1 ;
DBUG_RETURN(0 );
}
if (geometry->get_class_info()->m_type_id == Geometry::wkb_point)
DBUG_RETURN(1 );
int simple;
if (geometry->is_simple(&simple)) {
null_value= 1 ;
DBUG_RETURN(0 );
}
DBUG_RETURN(simple);
}
String *Item_func_simplify::val_str(String *str)
{
DBUG_ENTER("Item_func_simplify::val_str" );
String *res= args[0 ]->val_str(&tmp_value);
double max_distance= (double ) args[1 ]->val_real();
Geometry_buffer buffer;
Geometry *geometry;
uint32 num_points;
null_value= 1 ;
if ((null_value= (args[0 ]->null_value || args[1 ]->null_value)) ||
!(geometry= Geometry::construct(&buffer, res->ptr(), res->length())))
{
null_value= 1 ;
DBUG_RETURN(NULL);
}
if (max_distance <= 0 )
{
my_error(ER_WRONG_ARGUMENTS, MYF(0 ), func_name());
null_value= 1 ;
DBUG_RETURN(NULL);
}
uint32 srid= uint4korr(res->ptr());
if (srid != 0 )
{
my_error(ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS, MYF(0 ), func_name());
null_value= 1 ;
DBUG_RETURN(NULL);
}
if (geometry->get_class_info()->m_type_id == Geometry::wkb_point ||
geometry->get_class_info()->m_type_id == Geometry::wkb_multipoint)
{
str = res;
DBUG_RETURN(str);
}
if (geometry->get_class_info()->m_type_id == Geometry::wkb_linestring)
{
if (geometry->num_points(&num_points))
{
null_value= 1 ;
DBUG_RETURN(NULL);
}
if (num_points < 3 )
{
str = res;
DBUG_RETURN(str);
}
}
/*
ST_SIMPLIFY returns a binary geometry . The simplify methods append the
result with String : : append , which consults the charset of the output
buffer . When that buffer is an element of the comparison array that IN
builds it arrives cleared , with no charset , so mark it binary before
writing .
*/
str->set_charset(&my_charset_bin);
if (geometry->simplify(str, max_distance))
{
null_value= 1 ;
DBUG_RETURN(NULL);
}
DBUG_RETURN(str);
}
longlong Item_func_isclosed::val_int()
{
DBUG_ASSERT(fixed());
String tmp;
String *swkb= args[0 ]->val_str(&tmp);
Geometry_buffer buffer;
Geometry *geom;
int isclosed= 0 ; // In case of error
null_value= 0 ;
if (!swkb ||
args[0 ]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())) ||
geom->is_closed(&isclosed))
{
/* IsClosed(NULL) should return -1 */
return -1 ;
}
return (longlong) isclosed;
}
longlong Item_func_isring::val_int()
{
/* It's actually a combination of two functions - IsClosed and IsSimple */
DBUG_ASSERT(fixed());
String tmp;
String *swkb= args[0 ]->val_str(&tmp);
Geometry_buffer buffer;
Geometry *geom;
int isclosed= 0 ; // In case of error
null_value= 0 ;
if (!swkb ||
args[0 ]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))
{
if (!args[0 ]->null_value)
my_error(ER_GIS_INVALID_DATA, MYF(0 ), func_name());
null_value= 1 ;
return 0 ;
}
if (geom->is_closed(&isclosed) || !isclosed)
return 0 ;
return Item_func_issimple::val_int();
}
/*
Numerical functions
*/
longlong Item_func_dimension::val_int()
{
DBUG_ASSERT(fixed());
uint32 dim= 0 ; // In case of error
String *swkb= args[0 ]->val_str(&value);
Geometry_buffer buffer;
Geometry *geom;
const char *dummy;
null_value= (!swkb ||
args[0 ]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())) ||
geom->dimension(&dim, &dummy));
return (longlong) dim;
}
longlong Item_func_numinteriorring::val_int()
{
DBUG_ASSERT(fixed());
uint32 num= 0 ; // In case of error
String *swkb= args[0 ]->val_str(&value);
Geometry_buffer buffer;
Geometry *geom;
null_value= (!swkb ||
!(geom= Geometry::construct(&buffer,
swkb->ptr(), swkb->length())) ||
geom->num_interior_ring(&num));
return (longlong) num;
}
longlong Item_func_numgeometries::val_int()
{
DBUG_ASSERT(fixed());
uint32 num= 0 ; // In case of errors
String *swkb= args[0 ]->val_str(&value);
Geometry_buffer buffer;
Geometry *geom;
null_value= (!swkb ||
!(geom= Geometry::construct(&buffer,
swkb->ptr(), swkb->length())) ||
geom->num_geometries(&num));
return (longlong) num;
}
longlong Item_func_numpoints::val_int()
{
DBUG_ASSERT(fixed());
uint32 num= 0 ; // In case of errors
String *swkb= args[0 ]->val_str(&value);
Geometry_buffer buffer;
Geometry *geom;
null_value= (!swkb ||
args[0 ]->null_value ||
!(geom= Geometry::construct(&buffer,
swkb->ptr(), swkb->length())) ||
geom->num_points(&num));
return (longlong) num;
}
double Item_func_x::val_real()
{
DBUG_ASSERT(fixed());
double res= 0 .0 ; // In case of errors
String *swkb= args[0 ]->val_str(&value);
Geometry_buffer buffer;
Geometry *geom;
null_value= (!swkb ||
!(geom= Geometry::construct(&buffer,
swkb->ptr(), swkb->length())) ||
geom->get_x(&res));
return res;
}
double Item_func_y::val_real()
{
DBUG_ASSERT(fixed());
double res= 0 ; // In case of errors
String *swkb= args[0 ]->val_str(&value);
Geometry_buffer buffer;
Geometry *geom;
null_value= (!swkb ||
!(geom= Geometry::construct(&buffer,
swkb->ptr(), swkb->length())) ||
geom->get_y(&res));
return res;
}
double Item_func_area::val_real()
{
DBUG_ASSERT(fixed());
double res= 0 ; // In case of errors
String *swkb= args[0 ]->val_str(&value);
Geometry_buffer buffer;
Geometry *geom;
const char *dummy;
null_value= (!swkb ||
!(geom= Geometry::construct(&buffer,
swkb->ptr(), swkb->length())) ||
geom->area(&res, &dummy));
return res;
}
double Item_func_glength::val_real()
{
DBUG_ASSERT(fixed());
double res= 0 ; // In case of errors
String *swkb= args[0 ]->val_str(&value);
Geometry_buffer buffer;
Geometry *geom;
const char *end;
null_value= (!swkb ||
!(geom= Geometry::construct(&buffer,
swkb->ptr(),
swkb->length())) ||
geom->geom_length(&res, &end));
return res;
}
longlong Item_func_srid::val_int()
{
DBUG_ASSERT(fixed());
String *swkb= args[0 ]->val_str(&value);
Geometry_buffer buffer;
null_value= (!swkb ||
!Geometry::construct(&buffer,
swkb->ptr(), swkb->length()));
if (null_value)
return 0 ;
return (longlong) (uint4korr(swkb->ptr()));
}
double Item_func_distance::val_real()
{
bool cur_point_edge;
const Gcalc_scan_iterator::point *evpos;
const Gcalc_heap::Info *cur_point, *dist_point;
const Gcalc_scan_iterator::event_point *ev;
double t, distance, cur_distance;
double x1, x2, y1, y2;
double ex, ey, vx, vy, e_sqrlen;
uint obj2_si;
Gcalc_operation_transporter trn(&func, &collector);
DBUG_ENTER("Item_func_distance::val_real" );
DBUG_ASSERT(fixed());
String *res1= args[0 ]->val_str(&tmp_value1);
String *res2= args[1 ]->val_str(&tmp_value2);
Geometry_buffer buffer1, buffer2;
Geometry *g1, *g2;
MBR mbr1, mbr2;
const char *c_end;
if (args[0 ]->null_value || args[1 ]->null_value)
goto mem_error;
g1= Geometry::construct(&buffer1, res1->ptr(), res1->length());
if (!g1)
goto mem_error;
g2= Geometry::construct(&buffer2, res2->ptr(), res2->length());
if (!g2)
goto mem_error;
if (g1->get_mbr(&mbr1, &c_end) || g2->get_mbr(&mbr2, &c_end))
goto mem_error;
mbr1.add_mbr(&mbr2);
collector.set_extent(mbr1.xmin, mbr1.xmax, mbr1.ymin, mbr1.ymax);
if ((g1->get_class_info()->m_type_id == Geometry::wkb_point) &&
(g2->get_class_info()->m_type_id == Geometry::wkb_point))
{
if (((Gis_point *) g1)->get_xy(&x1, &y1) ||
((Gis_point *) g2)->get_xy(&x2, &y2))
goto mem_error;
ex= x2 - x1;
ey= y2 - y1;
DBUG_RETURN(sqrt(ex * ex + ey * ey));
}
if (func.reserve_op_buffer(1 ))
goto mem_error;
func.add_operation(Gcalc_function::op_intersection, 2 );
if (g1->store_shapes(&trn))
goto mem_error;
obj2_si= func.get_nshapes();
if (g2->store_shapes(&trn) || func.alloc_states())
goto mem_error;
if (obj2_si == 0 || func.get_nshapes() == obj2_si)
{
distance= 0 .0 ;
null_value= 1 ;
goto exit ;
}
collector.prepare_operation();
scan_it.init(&collector);
distance= DBL_MAX;
while (scan_it.more_points())
{
if (scan_it.step())
goto mem_error;
evpos= scan_it.get_event_position();
ev= scan_it.get_events();
if (ev->simple_event())
{
cur_point= ev->pi;
goto count_distance;
}
/*
handling intersection we only need to check if it ' s the intersecion
of objects 1 and 2 . In this case distance is 0
*/
cur_point= NULL;
/*
having these events we need to check for possible intersection
of objects
scev_thread | scev_two_threads | scev_single_point
*/
func.clear_i_states();
for (Gcalc_point_iterator pit(&scan_it); pit.point() != evpos; ++pit)
{
gcalc_shape_info si= pit.point()->get_shape();
if ((func.get_shape_kind(si) == Gcalc_function::shape_polygon))
func.invert_i_state(si);
}
func.clear_b_states();
for (; ev; ev= ev->get_next())
{
if (ev->event != scev_intersection)
cur_point= ev->pi;
func.set_b_state(ev->get_shape());
if (func.count())
{
/* Point of one object is inside the other - intersection found */
distance= 0 ;
goto exit ;
}
}
if (!cur_point)
continue ;
count_distance:
if (cur_point->node.shape.shape >= obj2_si)
continue ;
cur_point_edge= !cur_point->is_bottom();
for (dist_point= collector.get_first(); dist_point; dist_point= dist_point->get_next())
{
/* We only check vertices of object 2 */
if (dist_point->type != Gcalc_heap::nt_shape_node ||
dist_point->node.shape.shape < obj2_si)
continue ;
/* if we have an edge to check */
if (dist_point->node.shape.left)
{
t= count_edge_t(dist_point, dist_point->node.shape.left, cur_point,
ex, ey, vx, vy, e_sqrlen);
if ((t>0 .0 ) && (t<1 .0 ))
{
cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
if (distance > cur_distance)
distance= cur_distance;
}
}
if (cur_point_edge)
{
t= count_edge_t(cur_point, cur_point->node.shape.left, dist_point,
ex, ey, vx, vy, e_sqrlen);
if ((t>0 .0 ) && (t<1 .0 ))
{
cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
if (distance > cur_distance)
distance= cur_distance;
}
}
cur_distance= distance_points(cur_point, dist_point);
if (distance > cur_distance)
distance= cur_distance;
}
}
exit :
collector.reset();
func.reset();
scan_it.reset();
DBUG_RETURN(distance);
mem_error:
null_value= 1 ;
DBUG_RETURN(0 );
}
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_GIS_UNSUPPORTED_ARGUMENT, MYF(0 ), func_name());
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 of unexpected geometry.
my_error(ER_GIS_UNSUPPORTED_ARGUMENT, 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 err_hv= 0 , err_sph= 0 ;
switch (g2->get_class_info()->m_type_id)
{
case Geometry::wkb_point:
{
Gis_point *g2p= static_cast <Gis_point *>(g2);
// Optimization for point-point case
if (g1->get_class_info()->m_type_id == Geometry::wkb_point)
{
res= g2p->calculate_haversine(g1, r, &err_hv);
}
else
{
// Optimization for single point in Multipoint
if (g1->get_data_size() == len)
{
res= g2p->calculate_haversine(g1, r, &err_hv);
}
else
{
// There are multipoints in g1
// g1 is MultiPoint and calculate MP.sphericaldistance from g2 Point
if (g1->get_data_size() != GET_SIZE_ERROR)
err_sph= g2p->spherical_distance_multipoints(g1, r, &res, &err_hv);
}
}
break ;
}
case Geometry::wkb_multipoint:
// Optimization for point-point case
if (g1->get_class_info()->m_type_id == Geometry::wkb_point)
{
Gis_point *g1p= static_cast <Gis_point *>(g1);
// Optimization for single point in Multipoint g2
if (g2->get_data_size() == len)
{
res= g1p->calculate_haversine(g2, r, &err_hv);
}
else
{
if (g2->get_data_size() != GET_SIZE_ERROR)
// g1 is a point (casted to multi_point) and g2 multipoint
err_sph= g1p->spherical_distance_multipoints(g2, r, &res, &err_hv);
}
}
else
{
Gis_multi_point *g1mp= static_cast <Gis_multi_point *>(g1);
// Multipoints in g1 and g2 - no optimization
err_sph= g1mp->spherical_distance_multipoints(g2, r, &res, &err_hv);
}
break ;
default :
DBUG_ASSERT(0 );
break ;
}
if (err_hv == 1 )
my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0 ),
"Longitude should be [-180,180]" , "ST_Distance_Sphere" );
else if (err_hv < 0 )
my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0 ),
"Latitude should be [-90,90]" , "ST_Distance_Sphere" );
else if (err_sph || err_hv == 2 )
my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, MYF(0 ));
return res;
}
String *Item_func_geohash::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed());
double latitude, longitude;
int geohash_length;
Item* length_field;
null_value= 1 ;
if (arg_count == 2 )
{
Geometry_buffer buffer;
Geometry *geometry;
String tmp;
String *wkb= args[0 ]->val_str(&tmp);
if (args[0 ]->null_value)
return 0 ;
length_field= args[1 ];
geometry = Geometry::construct(&buffer, wkb->ptr(), wkb->length());
if (!geometry ||
geometry->get_class_info()->m_type_id != Geometry::wkb_point ||
geometry->get_x(&longitude) || geometry->get_y(&latitude))
{
my_error(ER_GIS_INVALID_DATA, MYF(0 ), "ST_GeoHash" );
return 0 ;
}
}
else
{
if (args[0 ]->null_value || args[1 ]->null_value)
return 0 ;
if (is_invalid_longitude_field(args[0 ]->field_type()) ||
is_invalid_latitude_field(args[1 ]->field_type()))
{
my_error(ER_GIS_INVALID_DATA, MYF(0 ), "ST_GeoHash" );
return 0 ;
}
longitude= args[0 ]->val_real();
latitude= args[1 ]->val_real();
// We need to check again because the val_real calls may set the null
// bit, depending on their implementation.
if (args[0 ]->null_value || args[1 ]->null_value)
return 0 ;
length_field= args[2 ];
}
if (is_invalid_length_field(length_field->field_type()))
{
my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0 ),
"max_length parameter should be an integer in the range [1, 100]" ,
"ST_GeoHash" );
return 0 ;
}
if (longitude > MAX_LONGITUDE || longitude < MIN_LONGITUDE)
{
my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0 ),
"Longitude should be [-180,180]" , "ST_GeoHash" );
return 0 ;
}
if (latitude > MAX_LATITUDE || latitude < MIN_LATITUDE)
{
my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0 ),
"Latitude should be [-90,90]" , "ST_GeoHash" );
return 0 ;
}
geohash_length= static_cast <uint>(length_field->val_int());
if (length_field->null_value)
{
null_value= 1 ;
return 0 ;
}
if (geohash_length <= MIN_GEOHASH_LENGTH ||
geohash_length > MAX_GEOHASH_LENGTH)
{
my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0 ),
"max_length parameter should be an integer in the range [1, 100]" ,
"ST_GeoHash" );
return 0 ;
}
str->length(0 );
str->set_charset(&my_charset_latin1);
if (str->reserve(geohash_length))
return 0 ;
encode_geohash(str, longitude, latitude, geohash_length);
null_value= 0 ;
return str;
}
bool Item_func_geohash::is_invalid_length_field(enum_field_types field_type)
{
switch (field_type)
{
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_LONG_BLOB:
return false ;
default :
return true ;
}
}
bool Item_func_geohash::is_invalid_longitude_field(enum_field_types field_type)
{
switch (field_type)
{
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_GEOMETRY:
case MYSQL_TYPE_DOUBLE:
case MYSQL_TYPE_LONG_BLOB:
return false ;
default :
return true ;
}
}
bool Item_func_geohash::is_invalid_latitude_field(enum_field_types field_type)
{
return is_invalid_longitude_field(field_type);
}
void Item_func_geohash::encode_geohash(String *str, double longitude,
double latitude, uint length)
{
constexpr char BASE32[]= "0123456789bcdefghjkmnpqrstuvwxyz" ;
double tmp_max_latitude= MAX_LATITUDE;
double tmp_min_latitude= MIN_LATITUDE;
double tmp_max_longitude= MAX_LONGITUDE;
double tmp_min_longitude= MIN_LONGITUDE;
std::bitset<5 > base_set;
bool switch_bit= true ;
for (uint i=0 ; i<length; ++i)
{
for (uint bit_index=0 ; bit_index<5 ; ++bit_index)
{
set_bit(switch_bit ? tmp_max_longitude : tmp_max_latitude,
switch_bit ? tmp_min_longitude : tmp_min_latitude,
switch_bit ? longitude : latitude,
base_set, bit_index);
switch_bit = !switch_bit;
}
uint char_index= base_set.to_ulong();
DBUG_ASSERT(char_index <= 31 );
str->append(BASE32[char_index]);
if (latitude == ((tmp_max_latitude + tmp_min_latitude) / 2 .0 ) &&
longitude == ((tmp_max_longitude + tmp_min_longitude) / 2 .0 ))
break ;
}
}
void Item_func_geohash::set_bit(double &max_value, double &min_value, const double &target_value,
std::bitset<5 > &base_set, const uint &bit_index)
{
double mid_value= (max_value + min_value) / 2 .0 ;
if (target_value >= mid_value)
{
base_set[4 - bit_index]= 1 ;
min_value= mid_value;
return ;
}
base_set[4 - bit_index]= 0 ;
max_value= mid_value;
}
const uint8_t Item_func_latlongfromgeohash::geohash_alphabet[256 ] = {
// 0-47
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
255 , 255 , 255 ,
// '0'-'9' (48-57)
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ,
// 58-65
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
// 'B'-'H' (66-73)
10 , 11 , 12 , 13 , 14 , 15 , 16 ,
// 'I' (74)
255 ,
// 'J'-'K' (75-76)
17 , 18 ,
// 'L' (77)
255 ,
// 'M'-'N' (78-79)
19 , 20 ,
// O (80)
255 ,
// 'P'-'Z' (81-92)
21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 ,
255 , 255 , 255 , 255 , 255 , 255 , 255 ,
// 'b'-'h' (97-104)
10 , 11 , 12 , 13 , 14 , 15 , 16 ,
// 'i' (105)
255 ,
// 'j'-'k' (106-107)
17 , 18 ,
// 'l' (108)
255 ,
// 'm'-'n' (109-110)
19 , 20 ,
// 'o' (111)
255 ,
// 'p'-'z' (112-122)
21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 ,
// 123-255
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255
};
/**
converts a geohash character to an int .
@ return false on success , true on valid ( invalid geohash character )
*/
bool Item_func_latlongfromgeohash::convert_character(char in, int &out)
{
#if CHAR_MIN
/* representing signed char, unsigned char always has a map */
if (in < 0 )
return true ;
#endif
out= Item_func_latlongfromgeohash::geohash_alphabet[(int ) in];
return out == 255 ;
}
/**
Decodes a geohash string into longitude and latitude .
The results are rounded , based on the length of input geohash . The function
will stop evaluating when the error range , or " accuracy " , has become 0 . 0 for
both latitude and longitude since no more changes can happen after this .
@ param geohash The geohash to decode .
@ param upper_latitude Upper limit of returned latitude ( normally 90 . 0 ) .
@ param [ out ] result_latitude Calculated latitude .
@ param [ out ] result_longitude Calculated longitude .
@ return false on success , true on failure ( invalid geohash string ) .
*/
bool Item_func_latlongfromgeohash::decode_geohash(
String *geohash, double *result_latitude,
double *result_longitude)
{
double latitude_accuracy= (MAX_LATITUDE - MIN_LATITUDE) / 2 .0 ;
double longitude_accuracy= (MAX_LONGITUDE - MIN_LONGITUDE) / 2 .0 ;
double latitude_value= (MAX_LATITUDE + MIN_LATITUDE) / 2 .0 ;
double longitude_value= (MAX_LONGITUDE + MIN_LONGITUDE) / 2 .0 ;
uint number_of_bits_used= 0 ;
const uint input_length= geohash->length();
for (uint i = 0 ; i < input_length; i++)
{
int converted_character= -1 ;
if (convert_character((*geohash)[i], converted_character))
return true ;
for (int bit_number = 4 ; bit_number >= 0 ; bit_number--)
{
if (number_of_bits_used % 2 ) {
latitude_accuracy/= 2 .0 ;
if (converted_character & (1 << bit_number))
latitude_value+= latitude_accuracy;
else
latitude_value-= latitude_accuracy;
} else {
longitude_accuracy/= 2 .0 ;
if (converted_character & (1 << bit_number))
longitude_value+= longitude_accuracy;
else
longitude_value-= longitude_accuracy;
}
number_of_bits_used++;
}
if (latitude_accuracy <= 0 .0 || longitude_accuracy <= 0 .0 )
break ;
}
*result_latitude= round_latlongitude(latitude_value, latitude_accuracy * 2 .0 ,
latitude_value - latitude_accuracy,
latitude_value + latitude_accuracy);
*result_longitude= round_latlongitude(longitude_value,
longitude_accuracy * 2 .0 ,
longitude_value - longitude_accuracy,
longitude_value + longitude_accuracy);
return false ;
}
/**
Rounds a latitude or longitude value .
This will round a latitude or longitude value , based on error_range .
The error_range is the difference between upper and lower lat / longitude
( e . g upper value of 45 . 0 and a lower value of 22 . 5 , gives an error range of
22 . 5 ) .
The returned result will always be in the range [ lower_limit , upper_limit ]
@ param latlongitude The latitude or longitude to round .
@ param error_range The total error range of the calculated laglongitude .
@ param lower_limit Lower limit of the returned result .
@ param upper_limit Upper limit of the returned result .
@ return A rounded latitude or longitude .
*/
double Item_func_latlongfromgeohash::round_latlongitude(double latlongitude,
double error_range,
double lower_limit,
double upper_limit)
{
if (error_range == 0 .0 )
return latlongitude;
uint number_of_decimals= 0 ;
while (error_range <= 0 .1 && number_of_decimals <= DBL_DIG) {
number_of_decimals++;
error_range*= 10 .0 ;
}
double return_value;
do {
return_value= my_double_round(latlongitude, number_of_decimals, false ,
false );
number_of_decimals++;
} while ((lower_limit > return_value || return_value > upper_limit) &&
number_of_decimals <= DBL_DIG);
// If the result is outside the allowed range, return the input value
if (lower_limit > return_value || return_value > upper_limit)
return_value= latlongitude;
// Avoid printing signed zero
return return_value + 0 .0 ;
}
bool Item_func_latlongfromgeohash::is_invalid_geohash_field(
enum_field_types field_type)
{
switch (field_type)
{
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_GEOMETRY:
case MYSQL_TYPE_STRING:
return false ;
default :
return true ;
}
}
double Item_func_latlongfromgeohash::val_real()
{
null_value= 1 ;
String *input_value;
if (args[0 ]->null_value)
return 0 .0 ;
if (is_invalid_geohash_field(args[0 ]->field_type()))
{
my_error(ER_GIS_INVALID_DATA, MYF(0 ), decode_longitude ?
"ST_LongFromGeoHas" :
"ST_LatFromGeohash" );
return 0 .0 ;
}
input_value= args[0 ]->val_str(&buf);
if (args[0 ]->null_value)
{
args[0 ]->null_value= 0 ;
return 0 .0 ;
}
if (input_value->is_empty())
{
my_error(ER_WRONG_VALUE_FOR_TYPE, MYF(0 ), "geohash" ,
input_value->c_ptr_safe(), func_name());
return 0 .0 ;
}
double latitude= 0 .0 , longitude= 0 .0 ;
if (decode_geohash(input_value, &latitude, &longitude)) {
my_error(ER_WRONG_VALUE_FOR_TYPE, MYF(0 ), "geohash" ,
input_value->c_ptr_safe(), func_name());
return 0 .0 ;
}
null_value= 0 ;
if (decode_longitude) return longitude;
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;
}
static double count_h_x(double x1, double y1, double x2, double y2, double h)
{
double dy= y2 - y1;
double dx= x2 - x1;
double dh= h - y1;
return x1 + dx * dh / dy;
}
String *Item_func_pointonsurface::val_str(String *str)
{
Gcalc_operation_transporter trn(&func, &collector);
String *res= args[0 ]->val_str(&tmp_value);
Geometry_buffer buffer;
Geometry *g;
MBR mbr;
const char *c_end;
double UNINIT_VAR(px), UNINIT_VAR(py);
String *result= 0 ;
const Gcalc_scan_iterator::point *pprev= NULL;
uint32 srid;
DBUG_ENTER("Item_func_pointonsurface::val_str" );
DBUG_ASSERT(fixed());
null_value= 1 ;
if ((args[0 ]->null_value ||
!(g= Geometry::construct(&buffer, res->ptr(), res->length())) ||
g->get_mbr(&mbr, &c_end)))
goto mem_error;
collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax);
if (g->store_shapes(&trn))
goto mem_error;
collector.prepare_operation();
scan_it.init(&collector);
while (scan_it.more_points())
{
double h;
if (scan_it.step())
goto mem_error;
if (!scan_it.more_points())
goto exit ;
if ((h= scan_it.get_h()) <= GIS_ZERO)
continue ;
py= scan_it.get_y() + h/2 .0 ;
for (Gcalc_point_iterator pit(&scan_it); pit.point(); ++pit)
{
const Gcalc_scan_iterator::point *p= pit.point();
double x1, y1, x2, y2, xa, xb;
if (pprev == NULL)
{
pprev= pit.point();
continue ;
}
pprev->pi->get_xy(&x1, &y1);
pprev->next_pi->get_xy(&x2, &y2);
xa= count_h_x(x1, y1, x2, y2, py);
p->pi->get_xy(&x1, &y1);
p->next_pi->get_xy(&x2, &y2);
xb= count_h_x(x1, y1, x2, y2, py);
if (xb - xa > GIS_ZERO)
{
px= (xa + xb) / 2 .0 ;
null_value= 0 ;
goto point_found;
}
pprev= NULL;
}
}
if (null_value)
goto exit ;
point_found:
str->set_charset(&my_charset_bin);
str->length(0 );
if (str->reserve(SRID_SIZE, 512 ))
goto mem_error;
srid= uint4korr(res->ptr());
str->q_append(srid);
if (Geometry::create_point(str, px, py))
goto mem_error;
result= str;
exit :
collector.reset();
func.reset();
scan_it.reset();
DBUG_RETURN(result);
mem_error:
collector.reset();
func.reset();
scan_it.reset();
null_value= 1 ;
DBUG_RETURN(0 );
}
#ifndef DBUG_OFF
longlong Item_func_gis_debug::val_int()
{
/* For now this is just a stub. TODO: implement the internal GIS debugging */
return 0 ;
}
#endif
/**********************************************************************/
class Create_func_area : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_area(thd, arg1);
}
static Create_func_area s_singleton;
protected :
Create_func_area() = default ;
~Create_func_area() override = default ;
};
class Create_func_as_wkb : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_as_wkb(thd, arg1);
}
static Create_func_as_wkb s_singleton;
protected :
Create_func_as_wkb() = default ;
~Create_func_as_wkb() override = default ;
};
class Create_func_as_wkt : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_as_wkt(thd, arg1);
}
static Create_func_as_wkt s_singleton;
protected :
Create_func_as_wkt() = default ;
~Create_func_as_wkt() override = default ;
};
class Create_func_centroid : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_centroid(thd, arg1);
}
static Create_func_centroid s_singleton;
protected :
Create_func_centroid() = default ;
~Create_func_centroid() override = default ;
};
class Create_func_convexhull : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_convexhull(thd, arg1);
}
static Create_func_convexhull s_singleton;
protected :
Create_func_convexhull() = default ;
~Create_func_convexhull() override = default ;
};
class Create_func_pointonsurface : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_pointonsurface(thd, arg1);
}
static Create_func_pointonsurface s_singleton;
protected :
Create_func_pointonsurface() = default ;
~Create_func_pointonsurface() override = default ;
};
class Create_func_mbr_contains : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
Item_func::SP_CONTAINS_FUNC);
}
static Create_func_mbr_contains s_singleton;
protected :
Create_func_mbr_contains() = default ;
~Create_func_mbr_contains() override = default ;
};
class Create_func_contains : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
Item_func::SP_CONTAINS_FUNC);
}
static Create_func_contains s_singleton;
protected :
Create_func_contains() = default ;
~Create_func_contains() override = default ;
};
class Create_func_mbr_coveredby : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
Item_func::SP_COVEREDBY_FUNC);
}
static Create_func_mbr_coveredby s_singleton;
protected :
Create_func_mbr_coveredby() = default ;
~Create_func_mbr_coveredby() override = default ;
};
class Create_func_coveredby : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
Item_func::SP_COVEREDBY_FUNC);
}
static Create_func_coveredby s_singleton;
protected :
Create_func_coveredby() = default ;
~Create_func_coveredby() override = default ;
};
class Create_func_crosses : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
Item_func::SP_CROSSES_FUNC);
}
static Create_func_crosses s_singleton;
protected :
Create_func_crosses() = default ;
~Create_func_crosses() override = default ;
};
class Create_func_dimension : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_dimension(thd, arg1);
}
static Create_func_dimension s_singleton;
protected :
Create_func_dimension() = default ;
~Create_func_dimension() override = default ;
};
class Create_func_mbr_disjoint : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
Item_func::SP_DISJOINT_FUNC);
}
static Create_func_mbr_disjoint s_singleton;
protected :
Create_func_mbr_disjoint() = default ;
~Create_func_mbr_disjoint() override = default ;
};
class Create_func_disjoint : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
Item_func::SP_DISJOINT_FUNC);
}
static Create_func_disjoint s_singleton;
protected :
Create_func_disjoint() = default ;
~Create_func_disjoint() override = default ;
};
class Create_func_distance : public Create_func_arg2
{
public :
Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_distance(thd, arg1, arg2);
}
static Create_func_distance s_singleton;
protected :
Create_func_distance() = default ;
~Create_func_distance() override = default ;
};
class Create_func_distance_sphere: public Create_native_func
{
public :
Item *create_native(THD *thd, const LEX_CSTRING *name, List<Item> *item_list)
override;
static Create_func_distance_sphere s_singleton;
protected :
Create_func_distance_sphere() = default ;
~Create_func_distance_sphere() override = default ;
};
Item*
Create_func_distance_sphere::create_native(THD *thd, const 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);
}
class Create_func_geohash : public Create_native_func
{
public :
Item *create_native(THD *thd, const LEX_CSTRING *name, List<Item> *item_list)
override;
static Create_func_geohash s_singleton;
protected :
Create_func_geohash() = default ;
virtual ~Create_func_geohash() = default ;
};
Item*
Create_func_geohash::create_native(THD *thd, const LEX_CSTRING *name,
List<Item> *item_list)
{
Item *func= NULL;
int arg_count= 0 ;
if (item_list != NULL)
arg_count= item_list->elements;
switch (arg_count) {
case 2 :
{
Item *point= item_list->pop();
Item *max_length= item_list->pop();
func= new (thd->mem_root) Item_func_geohash(thd, point, max_length);
break ;
}
case 3 :
{
Item *longitude= item_list->pop();
Item *latitude= item_list->pop();
Item *max_length= item_list->pop();
func= new (thd->mem_root) Item_func_geohash(thd, longitude, latitude, max_length);
break ;
}
default :
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0 ), name->str);
break ;
}
}
return func;
}
class Create_func_latfromgeohash : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_latfromgeohash(thd, arg1);
}
static Create_func_latfromgeohash s_singleton;
protected :
Create_func_latfromgeohash() = default ;
virtual ~Create_func_latfromgeohash() = default ;
};
class Create_func_longfromgeohash : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_longfromgeohash(thd, arg1);
}
static Create_func_longfromgeohash s_singleton;
protected :
Create_func_longfromgeohash() = default ;
virtual ~Create_func_longfromgeohash() = default ;
};
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 :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
Item_func::SP_ENDPOINT);
}
static Create_func_endpoint s_singleton;
protected :
Create_func_endpoint() = default ;
~Create_func_endpoint() override = default ;
};
class Create_func_envelope : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_envelope(thd, arg1);
}
static Create_func_envelope s_singleton;
protected :
Create_func_envelope() = default ;
~Create_func_envelope() override = default ;
};
class Create_func_boundary : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_boundary(thd, arg1);
}
static Create_func_boundary s_singleton;
protected :
Create_func_boundary() = default ;
~Create_func_boundary() override = default ;
};
class Create_func_mbr_equals : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
Item_func::SP_EQUALS_FUNC);
}
static Create_func_mbr_equals s_singleton;
protected :
Create_func_mbr_equals() = default ;
~Create_func_mbr_equals() override = default ;
};
class Create_func_equals : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
Item_func::SP_EQUALS_FUNC);
}
static Create_func_equals s_singleton;
protected :
Create_func_equals() = default ;
~Create_func_equals() override = default ;
};
class Create_func_exteriorring : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
Item_func::SP_EXTERIORRING);
}
static Create_func_exteriorring s_singleton;
protected :
Create_func_exteriorring() = default ;
~Create_func_exteriorring() override = default ;
};
class Create_func_geometry_from_text : public Create_native_func
{
public :
Item *create_native(THD *thd, const LEX_CSTRING *name, List<Item> *item_list)
override;
static Create_func_geometry_from_text s_singleton;
protected :
Create_func_geometry_from_text() = default ;
~Create_func_geometry_from_text() override = default ;
};
Item*
Create_func_geometry_from_text::create_native(THD *thd,
const LEX_CSTRING *name,
List<Item> *item_list)
{
Item *func= NULL;
int arg_count= 0 ;
if (item_list != NULL)
arg_count= item_list->elements;
switch (arg_count) {
case 1 :
{
Item *param_1= item_list->pop();
func= new (thd->mem_root) Item_func_geometry_from_text(thd, param_1);
thd->lex->uncacheable(UNCACHEABLE_RAND);
break ;
}
case 2 :
{
Item *param_1= item_list->pop();
Item *param_2= item_list->pop();
func= new (thd->mem_root) Item_func_geometry_from_text(thd, param_1, param_2);
break ;
}
default :
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0 ), name->str);
break ;
}
}
return func;
}
class Create_func_geometry_from_wkb : public Create_native_func
{
public :
Item *create_native(THD *thd, const LEX_CSTRING *name, List<Item> *item_list)
override;
static Create_func_geometry_from_wkb s_singleton;
protected :
Create_func_geometry_from_wkb() = default ;
~Create_func_geometry_from_wkb() override = default ;
};
Item*
Create_func_geometry_from_wkb::create_native(THD *thd, const LEX_CSTRING *name,
List<Item> *item_list)
{
Item *func= NULL;
int arg_count= 0 ;
if (item_list != NULL)
arg_count= item_list->elements;
switch (arg_count) {
case 1 :
{
Item *param_1= item_list->pop();
func= new (thd->mem_root) Item_func_geometry_from_wkb(thd, param_1);
thd->lex->uncacheable(UNCACHEABLE_RAND);
break ;
}
case 2 :
{
Item *param_1= item_list->pop();
Item *param_2= item_list->pop();
func= new (thd->mem_root) Item_func_geometry_from_wkb(thd, param_1, param_2);
break ;
}
default :
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0 ), name->str);
break ;
}
}
return func;
}
class Create_func_geometry_from_json : public Create_native_func
{
public :
Item *create_native(THD *thd, const LEX_CSTRING *name, List<Item> *item_list)
override;
static Create_func_geometry_from_json s_singleton;
protected :
Create_func_geometry_from_json() = default ;
~Create_func_geometry_from_json() override = default ;
};
Item*
Create_func_geometry_from_json::create_native(THD *thd,
const LEX_CSTRING *name,
List<Item> *item_list)
{
Item *func= NULL;
int arg_count= 0 ;
if (item_list != NULL)
arg_count= item_list->elements;
switch (arg_count) {
case 1 :
{
Item *json= item_list->pop();
func= new (thd->mem_root) Item_func_geometry_from_json(thd, json);
thd->lex->uncacheable(UNCACHEABLE_RAND);
break ;
}
case 2 :
{
Item *json= item_list->pop();
Item *options= item_list->pop();
func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options);
break ;
}
case 3 :
{
Item *json= item_list->pop();
Item *options= item_list->pop();
Item *srid= item_list->pop();
func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options,
srid);
break ;
}
default :
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0 ), name->str);
break ;
}
}
return func;
}
class Create_func_as_geojson : public Create_native_func
{
public :
Item *create_native(THD *thd, const LEX_CSTRING *name, List<Item> *item_list)
override;
static Create_func_as_geojson s_singleton;
protected :
Create_func_as_geojson() = default ;
~Create_func_as_geojson() override = default ;
};
Item*
Create_func_as_geojson::create_native(THD *thd, const LEX_CSTRING *name,
List<Item> *item_list)
{
Item *func= NULL;
int arg_count= 0 ;
if (item_list != NULL)
arg_count= item_list->elements;
switch (arg_count) {
case 1 :
{
Item *geom= item_list->pop();
func= new (thd->mem_root) Item_func_as_geojson(thd, geom);
thd->lex->uncacheable(UNCACHEABLE_RAND);
break ;
}
case 2 :
{
Item *geom= item_list->pop();
Item *max_dec= item_list->pop();
func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec);
break ;
}
case 3 :
{
Item *geom= item_list->pop();
Item *max_dec= item_list->pop();
Item *options= item_list->pop();
func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec, options);
break ;
}
default :
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0 ), name->str);
break ;
}
}
return func;
}
class Create_func_geometry_type : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_geometry_type(thd, arg1);
}
static Create_func_geometry_type s_singleton;
protected :
Create_func_geometry_type() = default ;
~Create_func_geometry_type() override = default ;
};
class Create_func_geometryn : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
Item_func::SP_GEOMETRYN);
}
static Create_func_geometryn s_singleton;
protected :
Create_func_geometryn() = default ;
~Create_func_geometryn() override = default ;
};
#if !defined (DBUG_OFF)
class Create_func_gis_debug : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_gis_debug(thd, arg1);
}
static Create_func_gis_debug s_singleton;
protected :
Create_func_gis_debug() = default ;
~Create_func_gis_debug() override = default ;
};
#endif
class Create_func_glength : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_glength(thd, arg1);
}
static Create_func_glength s_singleton;
protected :
Create_func_glength() = default ;
~Create_func_glength() override = default ;
};
class Create_func_interiorringn : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
Item_func::SP_INTERIORRINGN);
}
static Create_func_interiorringn s_singleton;
protected :
Create_func_interiorringn() = default ;
~Create_func_interiorringn() override = default ;
};
class Create_func_relate : public Create_func_arg3
{
public :
Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) override
{
return new (thd->mem_root) Item_func_spatial_relate(thd, arg1, arg2, arg3);
}
static Create_func_relate s_singleton;
protected :
Create_func_relate() = default ;
~Create_func_relate() override = default ;
};
class Create_func_mbr_intersects : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
Item_func::SP_INTERSECTS_FUNC);
}
static Create_func_mbr_intersects s_singleton;
protected :
Create_func_mbr_intersects() = default ;
~Create_func_mbr_intersects() override = default ;
};
class Create_func_intersects : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
Item_func::SP_INTERSECTS_FUNC);
}
static Create_func_intersects s_singleton;
protected :
Create_func_intersects() = default ;
~Create_func_intersects() override = default ;
};
class Create_func_intersection : public Create_func_arg2
{
public :
Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
Gcalc_function::op_intersection);
}
static Create_func_intersection s_singleton;
protected :
Create_func_intersection() = default ;
~Create_func_intersection() override = default ;
};
class Create_func_difference : public Create_func_arg2
{
public :
Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
Gcalc_function::op_difference);
}
static Create_func_difference s_singleton;
protected :
Create_func_difference() = default ;
~Create_func_difference() override = default ;
};
class Create_func_union : public Create_func_arg2
{
public :
Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
Gcalc_function::op_union);
}
static Create_func_union s_singleton;
protected :
Create_func_union() = default ;
~Create_func_union() override = default ;
};
class Create_func_symdifference : public Create_func_arg2
{
public :
Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
Gcalc_function::op_symdifference);
}
static Create_func_symdifference s_singleton;
protected :
Create_func_symdifference() = default ;
~Create_func_symdifference() override = default ;
};
class Create_func_buffer : public Create_func_arg2
{
public :
Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_buffer(thd, arg1, arg2);
}
static Create_func_buffer s_singleton;
protected :
Create_func_buffer() = default ;
~Create_func_buffer() override = default ;
};
class Create_func_isclosed : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_isclosed(thd, arg1);
}
static Create_func_isclosed s_singleton;
protected :
Create_func_isclosed() = default ;
~Create_func_isclosed() override = default ;
};
class Create_func_isring : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_isring(thd, arg1);
}
static Create_func_isring s_singleton;
protected :
Create_func_isring() = default ;
~Create_func_isring() override = default ;
};
class Create_func_isempty : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_isempty(thd, arg1);
}
static Create_func_isempty s_singleton;
protected :
Create_func_isempty() = default ;
~Create_func_isempty() override = default ;
};
class Create_func_isvalid : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_isvalid(thd, arg1);
}
static Create_func_isvalid s_singleton;
protected :
Create_func_isvalid() = default ;
virtual ~Create_func_isvalid() = default ;
};
class Create_func_validate : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_validate(thd, arg1);
}
static Create_func_validate s_singleton;
protected :
Create_func_validate() = default ;
virtual ~Create_func_validate() = default ;
};
class Create_func_issimple : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_issimple(thd, arg1);
}
static Create_func_issimple s_singleton;
protected :
Create_func_issimple() = default ;
~Create_func_issimple() override = default ;
};
class Create_func_simplify : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_simplify(thd, arg1, arg2);
}
static Create_func_simplify s_singleton;
protected :
Create_func_simplify() = default ;
~Create_func_simplify() override = default ;
};
class Create_func_numgeometries : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_numgeometries(thd, arg1);
}
static Create_func_numgeometries s_singleton;
protected :
Create_func_numgeometries() = default ;
~Create_func_numgeometries() override = default ;
};
class Create_func_numinteriorring : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_numinteriorring(thd, arg1);
}
static Create_func_numinteriorring s_singleton;
protected :
Create_func_numinteriorring() = default ;
~Create_func_numinteriorring() override = default ;
};
class Create_func_numpoints : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_numpoints(thd, arg1);
}
static Create_func_numpoints s_singleton;
protected :
Create_func_numpoints() = default ;
~Create_func_numpoints() override = default ;
};
class Create_func_mbr_overlaps : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
Item_func::SP_OVERLAPS_FUNC);
}
static Create_func_mbr_overlaps s_singleton;
protected :
Create_func_mbr_overlaps() = default ;
~Create_func_mbr_overlaps() override = default ;
};
class Create_func_overlaps : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
Item_func::SP_OVERLAPS_FUNC);
}
static Create_func_overlaps s_singleton;
protected :
Create_func_overlaps() = default ;
~Create_func_overlaps() override = default ;
};
class Create_func_pointn : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
Item_func::SP_POINTN);
}
static Create_func_pointn s_singleton;
protected :
Create_func_pointn() = default ;
~Create_func_pointn() override = default ;
};
class Create_func_srid : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_srid(thd, arg1);
}
static Create_func_srid s_singleton;
protected :
Create_func_srid() = default ;
~Create_func_srid() override = default ;
};
class Create_func_startpoint : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
Item_func::SP_STARTPOINT);
}
static Create_func_startpoint s_singleton;
protected :
Create_func_startpoint() = default ;
~Create_func_startpoint() override = default ;
};
class Create_func_touches : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
Item_func::SP_TOUCHES_FUNC);
}
static Create_func_touches s_singleton;
protected :
Create_func_touches() = default ;
~Create_func_touches() override = default ;
};
class Create_func_mbr_within : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
Item_func::SP_WITHIN_FUNC);
}
static Create_func_mbr_within s_singleton;
protected :
Create_func_mbr_within() = default ;
~Create_func_mbr_within() override = default ;
};
class Create_func_within : public Create_func_arg2
{
public :
Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
{
return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
Item_func::SP_WITHIN_FUNC);
}
static Create_func_within s_singleton;
protected :
Create_func_within() = default ;
~Create_func_within() override = default ;
};
class Create_func_x : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_x(thd, arg1);
}
static Create_func_x s_singleton;
protected :
Create_func_x() = default ;
~Create_func_x() override = default ;
};
class Create_func_y : public Create_func_arg1
{
public :
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_y(thd, arg1);
}
static Create_func_y s_singleton;
protected :
Create_func_y() = default ;
~Create_func_y() override = default ;
};
/*****************************************************************/
/*************************************************************************/
#if !defined (DBUG_OFF)
Create_func_gis_debug Create_func_gis_debug::s_singleton;
#endif
Create_func_area Create_func_area::s_singleton;
Create_func_as_geojson Create_func_as_geojson::s_singleton;
Create_func_as_wkb Create_func_as_wkb::s_singleton;
Create_func_as_wkt Create_func_as_wkt::s_singleton;
Create_func_boundary Create_func_boundary::s_singleton;
Create_func_buffer Create_func_buffer::s_singleton;
Create_func_centroid Create_func_centroid::s_singleton;
Create_func_contains Create_func_contains::s_singleton;
Create_func_coveredby Create_func_coveredby::s_singleton;
Create_func_convexhull Create_func_convexhull::s_singleton;
Create_func_crosses Create_func_crosses::s_singleton;
Create_func_difference Create_func_difference::s_singleton;
Create_func_dimension Create_func_dimension::s_singleton;
Create_func_disjoint Create_func_disjoint::s_singleton;
Create_func_distance Create_func_distance::s_singleton;
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;
Create_func_exteriorring Create_func_exteriorring::s_singleton;
Create_func_geometry_from_json Create_func_geometry_from_json::s_singleton;
Create_func_geometry_from_text Create_func_geometry_from_text::s_singleton;
Create_func_geometry_from_wkb Create_func_geometry_from_wkb::s_singleton;
Create_func_geometryn Create_func_geometryn::s_singleton;
Create_func_geometry_type Create_func_geometry_type::s_singleton;
Create_func_glength Create_func_glength::s_singleton;
Create_func_interiorringn Create_func_interiorringn::s_singleton;
Create_func_intersection Create_func_intersection::s_singleton;
Create_func_intersects Create_func_intersects::s_singleton;
Create_func_isclosed Create_func_isclosed::s_singleton;
Create_func_isempty Create_func_isempty::s_singleton;
Create_func_isvalid Create_func_isvalid::s_singleton;
Create_func_validate Create_func_validate::s_singleton;
Create_func_isring Create_func_isring::s_singleton;
Create_func_issimple Create_func_issimple::s_singleton;
Create_func_simplify Create_func_simplify::s_singleton;
Create_func_mbr_contains Create_func_mbr_contains::s_singleton;
Create_func_mbr_coveredby Create_func_mbr_coveredby::s_singleton;
Create_func_mbr_disjoint Create_func_mbr_disjoint::s_singleton;
Create_func_mbr_equals Create_func_mbr_equals::s_singleton;
Create_func_mbr_intersects Create_func_mbr_intersects::s_singleton;
Create_func_mbr_overlaps Create_func_mbr_overlaps::s_singleton;
Create_func_mbr_within Create_func_mbr_within::s_singleton;
Create_func_numgeometries Create_func_numgeometries::s_singleton;
Create_func_numinteriorring Create_func_numinteriorring::s_singleton;
Create_func_numpoints Create_func_numpoints::s_singleton;
Create_func_overlaps Create_func_overlaps::s_singleton;
Create_func_pointn Create_func_pointn::s_singleton;
Create_func_pointonsurface Create_func_pointonsurface::s_singleton;
Create_func_relate Create_func_relate::s_singleton;
Create_func_srid Create_func_srid::s_singleton;
Create_func_startpoint Create_func_startpoint::s_singleton;
Create_func_symdifference Create_func_symdifference::s_singleton;
Create_func_touches Create_func_touches::s_singleton;
Create_func_union Create_func_union::s_singleton;
Create_func_within Create_func_within::s_singleton;
Create_func_x Create_func_x::s_singleton;
Create_func_y Create_func_y::s_singleton;
/*************************************************************************/
#define GEOM_BUILDER(F) & F::s_singleton
static Native_func_registry func_array_geom[] =
{
#ifndef DBUG_OFF
{ { STRING_WITH_LEN("ST_GIS_DEBUG" ) }, GEOM_BUILDER(Create_func_gis_debug)},
#endif
{ { STRING_WITH_LEN("AREA" ) }, GEOM_BUILDER(Create_func_area)},
{ { STRING_WITH_LEN("ASBINARY" ) }, GEOM_BUILDER(Create_func_as_wkb)},
{ { STRING_WITH_LEN("ASTEXT" ) }, GEOM_BUILDER(Create_func_as_wkt)},
{ { STRING_WITH_LEN("ASWKB" ) }, GEOM_BUILDER(Create_func_as_wkb)},
{ { STRING_WITH_LEN("ASWKT" ) }, GEOM_BUILDER(Create_func_as_wkt)},
{ { STRING_WITH_LEN("BOUNDARY" ) }, GEOM_BUILDER(Create_func_boundary)},
{ { STRING_WITH_LEN("BUFFER" ) }, GEOM_BUILDER(Create_func_buffer)},
{ { STRING_WITH_LEN("CENTROID" ) }, GEOM_BUILDER(Create_func_centroid)},
{ { STRING_WITH_LEN("CONTAINS" ) }, GEOM_BUILDER(Create_func_contains)},
{ { STRING_WITH_LEN("COVEREDBY" ) }, GEOM_BUILDER(Create_func_coveredby)},
{ { STRING_WITH_LEN("CONVEXHULL" ) }, GEOM_BUILDER(Create_func_convexhull)},
{ { STRING_WITH_LEN("CROSSES" ) }, GEOM_BUILDER(Create_func_crosses)},
{ { STRING_WITH_LEN("DIMENSION" ) }, GEOM_BUILDER(Create_func_dimension)},
{ { STRING_WITH_LEN("DISJOINT" ) }, GEOM_BUILDER(Create_func_mbr_disjoint)},
{ { STRING_WITH_LEN("ENDPOINT" ) }, GEOM_BUILDER(Create_func_endpoint)},
{ { STRING_WITH_LEN("ENVELOPE" ) }, GEOM_BUILDER(Create_func_envelope)},
{ { STRING_WITH_LEN("EQUALS" ) }, GEOM_BUILDER(Create_func_equals)},
{ { STRING_WITH_LEN("EXTERIORRING" ) }, GEOM_BUILDER(Create_func_exteriorring)},
{ { STRING_WITH_LEN("GEOMCOLLFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("GEOMCOLLFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("GEOMETRYFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("GEOMETRYFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("GEOMETRYN" ) }, GEOM_BUILDER(Create_func_geometryn)},
{ { STRING_WITH_LEN("GEOMETRYTYPE" ) }, GEOM_BUILDER(Create_func_geometry_type)},
{ { STRING_WITH_LEN("GEOMFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("GEOMFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("GLENGTH" ) }, GEOM_BUILDER(Create_func_glength)},
{ { STRING_WITH_LEN("INTERIORRINGN" ) }, GEOM_BUILDER(Create_func_interiorringn)},
{ { STRING_WITH_LEN("INTERSECTS" ) }, GEOM_BUILDER(Create_func_mbr_intersects)},
{ { STRING_WITH_LEN("ISCLOSED" ) }, GEOM_BUILDER(Create_func_isclosed)},
{ { STRING_WITH_LEN("ISEMPTY" ) }, GEOM_BUILDER(Create_func_isempty)},
{ { STRING_WITH_LEN("ISVALID" ) }, GEOM_BUILDER(Create_func_isvalid)},
{ { STRING_WITH_LEN("VALIDATE" ) }, GEOM_BUILDER(Create_func_validate)},
{ { STRING_WITH_LEN("ISRING" ) }, GEOM_BUILDER(Create_func_isring)},
{ { STRING_WITH_LEN("ISSIMPLE" ) }, GEOM_BUILDER(Create_func_issimple)},
{ { STRING_WITH_LEN("SIMPLIFY" ) }, GEOM_BUILDER(Create_func_simplify)},
{ { STRING_WITH_LEN("LINEFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("LINEFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("LINESTRINGFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("LINESTRINGFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("MBRCONTAINS" ) }, GEOM_BUILDER(Create_func_mbr_contains)},
{ { STRING_WITH_LEN("MBRCOVEREDBY" ) }, GEOM_BUILDER(Create_func_mbr_coveredby)},
{ { STRING_WITH_LEN("MBRDISJOINT" ) }, GEOM_BUILDER(Create_func_mbr_disjoint)},
{ { STRING_WITH_LEN("MBREQUAL" ) }, GEOM_BUILDER(Create_func_mbr_equals)},
{ { STRING_WITH_LEN("MBREQUALS" ) }, GEOM_BUILDER(Create_func_mbr_equals)},
{ { STRING_WITH_LEN("MBRINTERSECTS" ) }, GEOM_BUILDER(Create_func_mbr_intersects)},
{ { STRING_WITH_LEN("MBROVERLAPS" ) }, GEOM_BUILDER(Create_func_mbr_overlaps)},
{ { STRING_WITH_LEN("MBRTOUCHES" ) }, GEOM_BUILDER(Create_func_touches)},
{ { STRING_WITH_LEN("MBRWITHIN" ) }, GEOM_BUILDER(Create_func_mbr_within)},
{ { STRING_WITH_LEN("MLINEFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("MLINEFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("MPOINTFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("MPOINTFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("MPOLYFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("MPOLYFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("MULTILINESTRINGFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("MULTILINESTRINGFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("MULTIPOINTFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("MULTIPOINTFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("MULTIPOLYGONFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("MULTIPOLYGONFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("NUMGEOMETRIES" ) }, GEOM_BUILDER(Create_func_numgeometries)},
{ { STRING_WITH_LEN("NUMINTERIORRINGS" ) }, GEOM_BUILDER(Create_func_numinteriorring)},
{ { STRING_WITH_LEN("NUMPOINTS" ) }, GEOM_BUILDER(Create_func_numpoints)},
{ { STRING_WITH_LEN("OVERLAPS" ) }, GEOM_BUILDER(Create_func_mbr_overlaps)},
{ { STRING_WITH_LEN("POINTFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("POINTFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("POINTN" ) }, GEOM_BUILDER(Create_func_pointn)},
{ { STRING_WITH_LEN("POINTONSURFACE" ) }, GEOM_BUILDER(Create_func_pointonsurface)},
{ { STRING_WITH_LEN("POLYFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("POLYFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("POLYGONFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("POLYGONFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { 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)},
{ { STRING_WITH_LEN("ST_ASBINARY" ) }, GEOM_BUILDER(Create_func_as_wkb)},
{ { STRING_WITH_LEN("ST_ASGEOJSON" ) }, GEOM_BUILDER(Create_func_as_geojson)},
{ { STRING_WITH_LEN("ST_ASTEXT" ) }, GEOM_BUILDER(Create_func_as_wkt)},
{ { STRING_WITH_LEN("ST_ASWKB" ) }, GEOM_BUILDER(Create_func_as_wkb)},
{ { STRING_WITH_LEN("ST_ASWKT" ) }, GEOM_BUILDER(Create_func_as_wkt)},
{ { STRING_WITH_LEN("ST_BOUNDARY" ) }, GEOM_BUILDER(Create_func_boundary)},
{ { STRING_WITH_LEN("ST_BUFFER" ) }, GEOM_BUILDER(Create_func_buffer)},
{ { STRING_WITH_LEN("ST_CENTROID" ) }, GEOM_BUILDER(Create_func_centroid)},
{ { STRING_WITH_LEN("ST_CONTAINS" ) }, GEOM_BUILDER(Create_func_contains)},
{ { STRING_WITH_LEN("ST_COVEREDBY" ) }, GEOM_BUILDER(Create_func_coveredby)},
{ { STRING_WITH_LEN("ST_CONVEXHULL" ) }, GEOM_BUILDER(Create_func_convexhull)},
{ { STRING_WITH_LEN("ST_CROSSES" ) }, GEOM_BUILDER(Create_func_crosses)},
{ { STRING_WITH_LEN("ST_DIFFERENCE" ) }, GEOM_BUILDER(Create_func_difference)},
{ { STRING_WITH_LEN("ST_DIMENSION" ) }, GEOM_BUILDER(Create_func_dimension)},
{ { STRING_WITH_LEN("ST_DISJOINT" ) }, GEOM_BUILDER(Create_func_disjoint)},
{ { STRING_WITH_LEN("ST_DISTANCE" ) }, GEOM_BUILDER(Create_func_distance)},
{ { STRING_WITH_LEN("ST_ENDPOINT" ) }, GEOM_BUILDER(Create_func_endpoint)},
{ { STRING_WITH_LEN("ST_ENVELOPE" ) }, GEOM_BUILDER(Create_func_envelope)},
{ { STRING_WITH_LEN("ST_EQUALS" ) }, GEOM_BUILDER(Create_func_equals)},
{ { STRING_WITH_LEN("ST_EXTERIORRING" ) }, GEOM_BUILDER(Create_func_exteriorring)},
{ { STRING_WITH_LEN("ST_GEOMCOLLFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_GEOMCOLLFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_GEOMETRYFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_GEOMETRYFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_GEOMETRYN" ) }, GEOM_BUILDER(Create_func_geometryn)},
{ { STRING_WITH_LEN("ST_GEOMETRYTYPE" ) }, GEOM_BUILDER(Create_func_geometry_type)},
{ { STRING_WITH_LEN("ST_GEOMFROMGEOJSON" ) }, GEOM_BUILDER(Create_func_geometry_from_json)},
{ { STRING_WITH_LEN("ST_GEOMFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_GEOMFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_INTERIORRINGN" ) }, GEOM_BUILDER(Create_func_interiorringn)},
{ { STRING_WITH_LEN("ST_INTERSECTION" ) }, GEOM_BUILDER(Create_func_intersection)},
{ { STRING_WITH_LEN("ST_INTERSECTS" ) }, GEOM_BUILDER(Create_func_intersects)},
{ { STRING_WITH_LEN("ST_ISCLOSED" ) }, GEOM_BUILDER(Create_func_isclosed)},
{ { STRING_WITH_LEN("ST_ISEMPTY" ) }, GEOM_BUILDER(Create_func_isempty)},
{ { STRING_WITH_LEN("ST_ISVALID" ) }, GEOM_BUILDER(Create_func_isvalid)},
{ { STRING_WITH_LEN("ST_VALIDATE" ) }, GEOM_BUILDER(Create_func_validate)},
{ { STRING_WITH_LEN("ST_ISRING" ) }, GEOM_BUILDER(Create_func_isring)},
{ { STRING_WITH_LEN("ST_ISSIMPLE" ) }, GEOM_BUILDER(Create_func_issimple)},
{ { STRING_WITH_LEN("ST_SIMPLIFY" ) }, GEOM_BUILDER(Create_func_simplify)},
{ { STRING_WITH_LEN("ST_LENGTH" ) }, GEOM_BUILDER(Create_func_glength)},
{ { STRING_WITH_LEN("ST_LINEFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_LINEFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_LINESTRINGFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_LINESTRINGFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_MLINEFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_MLINEFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_MPOINTFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_MPOINTFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_MPOLYFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_MPOLYFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_MULTILINESTRINGFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_MULTILINESTRINGFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_MULTIPOINTFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_MULTIPOINTFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_MULTIPOLYGONFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_MULTIPOLYGONFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_NUMGEOMETRIES" ) }, GEOM_BUILDER(Create_func_numgeometries)},
{ { STRING_WITH_LEN("ST_NUMINTERIORRINGS" ) }, GEOM_BUILDER(Create_func_numinteriorring)},
{ { STRING_WITH_LEN("ST_NUMPOINTS" ) }, GEOM_BUILDER(Create_func_numpoints)},
{ { STRING_WITH_LEN("ST_OVERLAPS" ) }, GEOM_BUILDER(Create_func_overlaps)},
{ { STRING_WITH_LEN("ST_POINTFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_POINTFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_POINTN" ) }, GEOM_BUILDER(Create_func_pointn)},
{ { STRING_WITH_LEN("ST_POINTONSURFACE" ) }, GEOM_BUILDER(Create_func_pointonsurface)},
{ { STRING_WITH_LEN("ST_POLYFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_POLYFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_POLYGONFROMTEXT" ) }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { STRING_WITH_LEN("ST_POLYGONFROMWKB" ) }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("ST_RELATE" ) }, GEOM_BUILDER(Create_func_relate)},
{ { STRING_WITH_LEN("ST_SRID" ) }, GEOM_BUILDER(Create_func_srid)},
{ { STRING_WITH_LEN("ST_STARTPOINT" ) }, GEOM_BUILDER(Create_func_startpoint)},
{ { STRING_WITH_LEN("ST_SYMDIFFERENCE" ) }, GEOM_BUILDER(Create_func_symdifference)},
{ { STRING_WITH_LEN("ST_TOUCHES" ) }, GEOM_BUILDER(Create_func_touches)},
{ { STRING_WITH_LEN("ST_UNION" ) }, GEOM_BUILDER(Create_func_union)},
{ { 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)},
{ { STRING_WITH_LEN("ST_DISTANCE_SPHERE" ) }, GEOM_BUILDER(Create_func_distance_sphere)},
{ { 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)},
{ { STRING_WITH_LEN("Y" ) }, GEOM_BUILDER(Create_func_y)},
};
Native_func_registry_array
native_func_registry_array_geom(func_array_geom,
array_elements(func_array_geom));
Messung V0.5 in Prozent C=98 H=87 G=92
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.170Bemerkung:
(vorverarbeitet am 2026-10-08)
¤
*Bot Zugriff