diff options
Diffstat (limited to 'sql/item_geofunc.cc')
-rw-r--r-- | sql/item_geofunc.cc | 4082 |
1 files changed, 4082 insertions, 0 deletions
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc new file mode 100644 index 00000000..8714417a --- /dev/null +++ b/sql/item_geofunc.cc @@ -0,0 +1,4082 @@ +/* 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 +*/ + +#ifdef USE_PRAGMA_IMPLEMENTATION +#pragma implementation // gcc: Class implementation +#endif + +#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" +#ifdef HAVE_SPATIAL +#include <m_ctype.h> +#include "opt_range.h" +#include "item_geofunc.h" +#include "item_create.h" + + +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) && !args[1]->null_value) + 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; + return str_ret; + } + + wkb= args[0]->val_str(&arg_val); + + if ((arg_count == 2) && !args[1]->null_value) + 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; +} + + +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; + json_engine_t je; + + if ((null_value= args[0]->null_value)) + return 0; + + if (arg_count > 1 && !args[1]->null_value) + { + options= args[1]->val_int(); + if (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) && !args[2]->null_value) + 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()); + + if ((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_printf(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(); + if (args[2]->null_value) + options= 0; + } + } + + 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 (!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_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") }; + } +} + + +longlong Item_func_spatial_mbr_rel::val_int() +{ + 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; + + switch (spatial_rel) { + case SP_CONTAINS_FUNC: + return mbr1.contains(&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_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); } +}; + + +longlong Item_func_spatial_relate::val_int() +{ + 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(1e-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); +} + + +longlong Item_func_spatial_precise_rel::val_int() +{ + 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(1e-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(2e-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_OVERLAPS_FUNC: + case SP_CROSSES_FUNC: + func.add_operation(Gcalc_function::op_intersection, 2); + if (func.reserve_op_buffer(3)) + break; + 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))) + break; + shape_b= func.get_next_expression_pos(); + if ((null_value= g2.store_shapes(&trn))) + break; + if (func.reserve_op_buffer(7)) + break; + 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); + 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; + 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_isempty::val_int() +{ + 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; + Gcalc_operation_transporter trn(&func, &collector); + Geometry *g; + int result= 1; + MBR mbr; + const char *c_end; + + DBUG_ENTER("Item_func_issimple::val_int"); + DBUG_ASSERT(fixed()); + + null_value= 0; + if ((args[0]->null_value || + !(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length())) || + g->get_mbr(&mbr, &c_end))) + { + /* We got NULL as an argument. Have to return -1 */ + DBUG_RETURN(-1); + } + + collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax); + + if (g->get_class_info()->m_type_id == Geometry::wkb_point) + DBUG_RETURN(1); + + if (g->store_shapes(&trn)) + goto mem_error; + + collector.prepare_operation(); + scan_it.init(&collector); + + while (scan_it.more_points()) + { + const Gcalc_scan_iterator::event_point *ev, *next_ev; + + if (scan_it.step()) + goto mem_error; + + ev= scan_it.get_events(); + if (ev->simple_event()) + continue; + + next_ev= ev->get_next(); + if ((ev->event & (scev_thread | scev_single_point)) && !next_ev) + continue; + + if ((ev->event == scev_two_threads) && !next_ev->get_next()) + continue; + + /* If the first and last points of a curve coincide - that is */ + /* an exception to the rule and the line is considered as simple. */ + if ((next_ev && !next_ev->get_next()) && + (ev->event & (scev_thread | scev_end)) && + (next_ev->event & (scev_thread | scev_end))) + continue; + + result= 0; + break; + } + + collector.reset(); + func.reset(); + scan_it.reset(); + DBUG_RETURN(result); +mem_error: + null_value= 1; + DBUG_RETURN(0); +} + + +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())) || + geom->is_closed(&isclosed)) + { + /* IsRing(NULL) should return -1 */ + return -1; + } + + if (!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_INTERNAL_ERROR, MYF(0), "Radius must be greater than zero."); + return 1; + } + } + Geometry_buffer buffer1, buffer2; + Geometry *g1, *g2; + if (!(g1= Geometry::construct(&buffer1, arg1->ptr(), arg1->length())) || + !(g2= Geometry::construct(&buffer2, arg2->ptr(), arg2->length()))) + { + my_error(ER_GIS_INVALID_DATA, MYF(0), "ST_Distance_Sphere"); + goto handle_errors; + } +// Method allowed for points and multipoints + if (!(g1->get_class_info()->m_type_id == Geometry::wkb_point || + g1->get_class_info()->m_type_id == Geometry::wkb_multipoint) || + !(g2->get_class_info()->m_type_id == Geometry::wkb_point || + g2->get_class_info()->m_type_id == Geometry::wkb_multipoint)) + { + // Generate error message in case different geometry is used? + my_error(ER_INTERNAL_ERROR, MYF(0), func_name()); + return 0; + } + distance= spherical_distance_points(g1, g2, sphere_radius); + if (distance < 0) + { + my_error(ER_INTERNAL_ERROR, MYF(0), "Returned distance cannot be negative."); + return 1; + } + return distance; + + handle_errors: + return 0; +} + + +double Item_func_sphere_distance::spherical_distance_points(Geometry *g1, + Geometry *g2, + const double r) +{ + double res= 0.0; + // Length for the single point (25 Bytes) + uint32 len= SRID_SIZE + POINT_DATA_SIZE + WKB_HEADER_SIZE; + int 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_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), x0, UNINIT_VAR(y0); + 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()) + { + if (scan_it.step()) + goto mem_error; + + if (scan_it.get_h() > GIS_ZERO) + { + y0= scan_it.get_y(); + break; + } + } + + if (!scan_it.more_points()) + { + goto exit; + } + + if (scan_it.step()) + goto mem_error; + + for (Gcalc_point_iterator pit(&scan_it); pit.point(); ++pit) + { + if (pprev == NULL) + { + pprev= pit.point(); + continue; + } + x0= scan_it.get_sp_x(pprev); + px= scan_it.get_sp_x(pit.point()); + if (px - x0 > GIS_ZERO) + { + if (scan_it.get_h() > GIS_ZERO) + { + px= (px + x0) / 2.0; + py= scan_it.get_y(); + } + else + { + px= (px + x0) / 2.0; + py= (y0 + scan_it.get_y()) / 2.0; + } + null_value= 0; + break; + } + pprev= NULL; + } + + if (null_value) + goto exit; + + 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 debuggign */ + 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; + virtual ~Create_func_area() = 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; + virtual ~Create_func_as_wkb() = 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; + virtual ~Create_func_as_wkt() = 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; + virtual ~Create_func_centroid() = 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; + virtual ~Create_func_convexhull() = 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; + virtual ~Create_func_pointonsurface() = 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; + virtual ~Create_func_mbr_contains() = 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; + virtual ~Create_func_contains() = 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; + virtual ~Create_func_crosses() = 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; + virtual ~Create_func_dimension() = 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; + virtual ~Create_func_mbr_disjoint() = 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; + virtual ~Create_func_disjoint() = 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; + virtual ~Create_func_distance() = 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; + virtual ~Create_func_distance_sphere() = 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_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; + virtual ~Create_func_endpoint() = 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; + virtual ~Create_func_envelope() = 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; + virtual ~Create_func_boundary() = 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; + virtual ~Create_func_mbr_equals() = 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; + virtual ~Create_func_equals() = 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; + virtual ~Create_func_exteriorring() = 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; + virtual ~Create_func_geometry_from_text() = 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; + virtual ~Create_func_geometry_from_wkb() = 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; + virtual ~Create_func_geometry_from_json() = 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; + virtual ~Create_func_as_geojson() = 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; + virtual ~Create_func_geometry_type() = 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; + virtual ~Create_func_geometryn() = 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; + virtual ~Create_func_gis_debug() = 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; + virtual ~Create_func_glength() = 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; + virtual ~Create_func_interiorringn() = 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; + virtual ~Create_func_relate() = 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; + virtual ~Create_func_mbr_intersects() = 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; + virtual ~Create_func_intersects() = 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; + virtual ~Create_func_intersection() = 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; + virtual ~Create_func_difference() = 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; + virtual ~Create_func_union() = 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; + virtual ~Create_func_symdifference() = 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; + virtual ~Create_func_buffer() = 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; + virtual ~Create_func_isclosed() = 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; + virtual ~Create_func_isring() = 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; + virtual ~Create_func_isempty() = 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; + virtual ~Create_func_issimple() = 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; + virtual ~Create_func_numgeometries() = 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; + virtual ~Create_func_numinteriorring() = 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; + virtual ~Create_func_numpoints() = 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; + virtual ~Create_func_mbr_overlaps() = 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; + virtual ~Create_func_overlaps() = 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; + virtual ~Create_func_pointn() = 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; + virtual ~Create_func_srid() = 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; + virtual ~Create_func_startpoint() = 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; + virtual ~Create_func_touches() = 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; + virtual ~Create_func_mbr_within() = 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; + virtual ~Create_func_within() = 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; + virtual ~Create_func_x() = 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; + virtual ~Create_func_y() = 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_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_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_isring Create_func_isring::s_singleton; +Create_func_issimple Create_func_issimple::s_singleton; +Create_func_mbr_contains Create_func_mbr_contains::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("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("ISRING") }, GEOM_BUILDER(Create_func_isring)}, + { { STRING_WITH_LEN("ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)}, + { { 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("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("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_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_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_ISRING") }, GEOM_BUILDER(Create_func_isring)}, + { { STRING_WITH_LEN("ST_ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)}, + { { 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("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)); + +#endif /*HAVE_SPATIAL*/ |