mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 12:56:14 +01:00 
			
		
		
		
	When invoking st_distance_sphere with unexpected geometries, the error message now given is: ERROR HY000: Internal error: Point or multipoint geometries expected This commit fixes a few formatting issues in the affected function.
		
			
				
	
	
		
			4094 lines
		
	
	
	
		
			107 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			4094 lines
		
	
	
	
		
			107 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* 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()
 | 
						|
{
 | 
						|
  collation.set(&my_charset_bin);
 | 
						|
  decimals=0;
 | 
						|
  max_length= (uint32) UINT_MAX32;
 | 
						|
  maybe_null= 1;
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
String *Item_func_geometry_from_text::val_str(String *str)
 | 
						|
{
 | 
						|
  DBUG_ASSERT(fixed == 1);
 | 
						|
  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 == 1);
 | 
						|
  String arg_val;
 | 
						|
  String *wkb;
 | 
						|
  Geometry_buffer buffer;
 | 
						|
  uint32 srid= 0;
 | 
						|
 | 
						|
  if (args[0]->field_type() == MYSQL_TYPE_GEOMETRY)
 | 
						|
  {
 | 
						|
    String *str_ret= args[0]->val_str(str);
 | 
						|
    null_value= args[0]->null_value;
 | 
						|
    if (!null_value && arg_count == 2 && !args[1]->null_value) {
 | 
						|
      srid= (uint32)args[1]->val_int();
 | 
						|
 | 
						|
      if (str->copy(*str_ret))
 | 
						|
        return 0;
 | 
						|
 | 
						|
      int4store(str->ptr(), srid);
 | 
						|
      return str;
 | 
						|
    }
 | 
						|
    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);
 | 
						|
  if (str->reserve(SRID_SIZE, 512))
 | 
						|
  {
 | 
						|
    null_value= TRUE;                           /* purecov: inspected */
 | 
						|
    return 0;                                   /* purecov: inspected */
 | 
						|
  }
 | 
						|
  str->length(0);
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void report_json_error_ex(String *js, json_engine_t *je,
 | 
						|
                          const char *fname, int n_param,
 | 
						|
                          Sql_condition::enum_warning_level lv);
 | 
						|
 | 
						|
String *Item_func_geometry_from_json::val_str(String *str)
 | 
						|
{
 | 
						|
  DBUG_ASSERT(fixed == 1);
 | 
						|
  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);
 | 
						|
  if (str->reserve(SRID_SIZE, 512))
 | 
						|
    return 0;
 | 
						|
  str->length(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, &je, func_name(), 0, Sql_condition::WARN_LEVEL_WARN);
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (code)
 | 
						|
    {
 | 
						|
      THD *thd= current_thd;
 | 
						|
      push_warning(thd, Sql_condition::WARN_LEVEL_WARN, code,
 | 
						|
                   ER_THD(thd, code));
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
  return str;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
String *Item_func_as_wkt::val_str_ascii(String *str)
 | 
						|
{
 | 
						|
  DBUG_ASSERT(fixed == 1);
 | 
						|
  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()
 | 
						|
{
 | 
						|
  collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
 | 
						|
  max_length= (uint32) UINT_MAX32;
 | 
						|
  maybe_null= 1;
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
String *Item_func_as_wkb::val_str(String *str)
 | 
						|
{
 | 
						|
  DBUG_ASSERT(fixed == 1);
 | 
						|
  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()
 | 
						|
{
 | 
						|
  collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
 | 
						|
  max_length=MAX_BLOB_WIDTH;
 | 
						|
  maybe_null= 1;
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
String *Item_func_as_geojson::val_str_ascii(String *str)
 | 
						|
{
 | 
						|
  DBUG_ASSERT(fixed == 1);
 | 
						|
  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("}", 1)))
 | 
						|
      goto error;
 | 
						|
 | 
						|
  return str;
 | 
						|
 | 
						|
error:
 | 
						|
  null_value= 1;
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
String *Item_func_geometry_type::val_str_ascii(String *str)
 | 
						|
{
 | 
						|
  DBUG_ASSERT(fixed == 1);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  String arg_val;
 | 
						|
  String *swkb= args[0]->val_str(&arg_val);
 | 
						|
 | 
						|
  if ((null_value= args[0]->null_value))
 | 
						|
    DBUG_RETURN(0);
 | 
						|
 | 
						|
  Geometry_buffer buffer;
 | 
						|
  uint32 srid= 0;
 | 
						|
  Transporter trn(&res_receiver);
 | 
						|
 | 
						|
  Geometry *g= Geometry::construct(&buffer, swkb->ptr(), swkb->length());
 | 
						|
  if ((null_value= !g))
 | 
						|
    DBUG_RETURN(0);
 | 
						|
 | 
						|
  if (g->store_shapes(&trn))
 | 
						|
    goto mem_error;
 | 
						|
 | 
						|
  str_value->set_charset(&my_charset_bin);
 | 
						|
  if (str_value->reserve(SRID_SIZE, 512))
 | 
						|
    goto mem_error;
 | 
						|
  str_value->length(0);
 | 
						|
  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 == 1);
 | 
						|
  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);
 | 
						|
  if (str->reserve(SRID_SIZE, 512))
 | 
						|
    return 0;
 | 
						|
  str->length(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 == 1);
 | 
						|
  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);
 | 
						|
  if (str_value->reserve(SRID_SIZE, 512))
 | 
						|
    goto mem_error;
 | 
						|
  str_value->length(0);
 | 
						|
  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 == 1);
 | 
						|
  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);
 | 
						|
  if (str_value->reserve(SRID_SIZE, 512))
 | 
						|
    goto mem_error;
 | 
						|
  str_value->length(0);
 | 
						|
  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 == 1);
 | 
						|
  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);
 | 
						|
  if (str->reserve(SRID_SIZE, 512))
 | 
						|
    goto err;
 | 
						|
  str->length(0);
 | 
						|
  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 == 1);
 | 
						|
  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);
 | 
						|
  if (str->reserve(SRID_SIZE, 512))
 | 
						|
    goto err;
 | 
						|
  srid= uint4korr(swkb->ptr());
 | 
						|
  str->length(0);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
const char *Item_func_spatial_mbr_rel::func_name() const 
 | 
						|
{ 
 | 
						|
  switch (spatial_rel) {
 | 
						|
    case SP_CONTAINS_FUNC:
 | 
						|
      return "mbrcontains";
 | 
						|
    case SP_WITHIN_FUNC:
 | 
						|
      return "mbrwithin";
 | 
						|
    case SP_EQUALS_FUNC:
 | 
						|
      return "mbrequals";
 | 
						|
    case SP_DISJOINT_FUNC:
 | 
						|
      return "mbrdisjoint";
 | 
						|
    case SP_INTERSECTS_FUNC:
 | 
						|
      return "mbrintersects";
 | 
						|
    case SP_TOUCHES_FUNC:
 | 
						|
      return "mbrtouches";
 | 
						|
    case SP_CROSSES_FUNC:
 | 
						|
      return "mbrcrosses";
 | 
						|
    case SP_OVERLAPS_FUNC:
 | 
						|
      return "mbroverlaps";
 | 
						|
    default:
 | 
						|
      DBUG_ASSERT(0);  // Should never happened
 | 
						|
      return "mbrsp_unknown"; 
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
longlong Item_func_spatial_mbr_rel::val_int()
 | 
						|
{
 | 
						|
  DBUG_ASSERT(fixed == 1);
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
const char *Item_func_spatial_precise_rel::func_name() const 
 | 
						|
{ 
 | 
						|
  switch (spatial_rel) {
 | 
						|
    case SP_CONTAINS_FUNC:
 | 
						|
      return "st_contains";
 | 
						|
    case SP_WITHIN_FUNC:
 | 
						|
      return "st_within";
 | 
						|
    case SP_EQUALS_FUNC:
 | 
						|
      return "st_equals";
 | 
						|
    case SP_DISJOINT_FUNC:
 | 
						|
      return "st_disjoint";
 | 
						|
    case SP_INTERSECTS_FUNC:
 | 
						|
      return "st_intersects";
 | 
						|
    case SP_TOUCHES_FUNC:
 | 
						|
      return "st_touches";
 | 
						|
    case SP_CROSSES_FUNC:
 | 
						|
      return "st_crosses";
 | 
						|
    case SP_OVERLAPS_FUNC:
 | 
						|
      return "st_overlaps";
 | 
						|
    default:
 | 
						|
      DBUG_ASSERT(0);  // Should never happened
 | 
						|
      return "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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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);
 | 
						|
  if (str_value->reserve(SRID_SIZE, 512))
 | 
						|
    goto exit;
 | 
						|
  str_value->length(0);
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
const char *Item_func_spatial_operation::func_name() const
 | 
						|
{ 
 | 
						|
  switch (spatial_op) {
 | 
						|
    case Gcalc_function::op_intersection:
 | 
						|
      return "st_intersection";
 | 
						|
    case Gcalc_function::op_difference:
 | 
						|
      return "st_difference";
 | 
						|
    case Gcalc_function::op_union:
 | 
						|
      return "st_union";
 | 
						|
    case Gcalc_function::op_symdifference:
 | 
						|
      return "st_symdifference";
 | 
						|
    default:
 | 
						|
      DBUG_ASSERT(0);  // Should never happen
 | 
						|
      return "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 == 1);
 | 
						|
  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);
 | 
						|
  if (str_value->reserve(SRID_SIZE, 512))
 | 
						|
    goto mem_error;
 | 
						|
  str_value->length(0);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  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 == 1);
 | 
						|
  String *res1= args[0]->val_str(&tmp_value1);
 | 
						|
  String *res2= args[1]->val_str(&tmp_value2);
 | 
						|
  Geometry_buffer buffer1, buffer2;
 | 
						|
  Geometry *g1, *g2;
 | 
						|
  MBR mbr1, mbr2;
 | 
						|
  const char *c_end;
 | 
						|
 | 
						|
  if (args[0]->null_value || args[1]->null_value)
 | 
						|
    goto mem_error;
 | 
						|
  g1= Geometry::construct(&buffer1, res1->ptr(), res1->length());
 | 
						|
  if (!g1)
 | 
						|
    goto mem_error;
 | 
						|
  g2= Geometry::construct(&buffer2, res2->ptr(), res2->length());
 | 
						|
  if (!g2)
 | 
						|
    goto mem_error;
 | 
						|
  if (g1->get_mbr(&mbr1, &c_end) || g2->get_mbr(&mbr2, &c_end))
 | 
						|
    goto mem_error;
 | 
						|
 | 
						|
  mbr1.add_mbr(&mbr2);
 | 
						|
  collector.set_extent(mbr1.xmin, mbr1.xmax, mbr1.ymin, mbr1.ymax);
 | 
						|
 | 
						|
  if ((g1->get_class_info()->m_type_id == Geometry::wkb_point) &&
 | 
						|
      (g2->get_class_info()->m_type_id == Geometry::wkb_point))
 | 
						|
  {
 | 
						|
    if (((Gis_point *) g1)->get_xy(&x1, &y1) ||
 | 
						|
        ((Gis_point *) g2)->get_xy(&x2, &y2))
 | 
						|
      goto mem_error;
 | 
						|
    ex= x2 - x1;
 | 
						|
    ey= y2 - y1;
 | 
						|
    DBUG_RETURN(sqrt(ex * ex + ey * ey));
 | 
						|
  }
 | 
						|
 | 
						|
  if (func.reserve_op_buffer(1))
 | 
						|
    goto mem_error;
 | 
						|
  func.add_operation(Gcalc_function::op_intersection, 2);
 | 
						|
 | 
						|
  if (g1->store_shapes(&trn))
 | 
						|
    goto mem_error;
 | 
						|
  obj2_si= func.get_nshapes();
 | 
						|
  if (g2->store_shapes(&trn) || func.alloc_states())
 | 
						|
    goto mem_error;
 | 
						|
 | 
						|
  if (obj2_si == 0 || func.get_nshapes() == obj2_si)
 | 
						|
  {
 | 
						|
    distance= 0.0;
 | 
						|
    null_value= 1;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  collector.prepare_operation();
 | 
						|
  scan_it.init(&collector);
 | 
						|
 | 
						|
  distance= DBL_MAX;
 | 
						|
  while (scan_it.more_points())
 | 
						|
  {
 | 
						|
    if (scan_it.step())
 | 
						|
      goto mem_error;
 | 
						|
    evpos= scan_it.get_event_position();
 | 
						|
    ev= scan_it.get_events();
 | 
						|
 | 
						|
    if (ev->simple_event())
 | 
						|
    {
 | 
						|
      cur_point= ev->pi;
 | 
						|
      goto count_distance;
 | 
						|
    }
 | 
						|
    /*
 | 
						|
       handling intersection we only need to check if it's the intersecion
 | 
						|
       of objects 1 and 2. In this case distance is 0
 | 
						|
    */
 | 
						|
    cur_point= NULL;
 | 
						|
 | 
						|
    /*
 | 
						|
       having these events we need to check for possible intersection
 | 
						|
       of objects
 | 
						|
       scev_thread | scev_two_threads | scev_single_point
 | 
						|
    */
 | 
						|
    func.clear_i_states();
 | 
						|
    for (Gcalc_point_iterator pit(&scan_it); pit.point() != evpos; ++pit)
 | 
						|
    {
 | 
						|
      gcalc_shape_info si= pit.point()->get_shape();
 | 
						|
      if ((func.get_shape_kind(si) == Gcalc_function::shape_polygon))
 | 
						|
        func.invert_i_state(si);
 | 
						|
    }
 | 
						|
 | 
						|
    func.clear_b_states();
 | 
						|
    for (; ev; ev= ev->get_next())
 | 
						|
    {
 | 
						|
      if (ev->event != scev_intersection)
 | 
						|
        cur_point= ev->pi;
 | 
						|
      func.set_b_state(ev->get_shape());
 | 
						|
      if (func.count())
 | 
						|
      {
 | 
						|
        /* Point of one object is inside the other - intersection found */
 | 
						|
        distance= 0;
 | 
						|
        goto exit;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!cur_point)
 | 
						|
      continue;
 | 
						|
 | 
						|
count_distance:
 | 
						|
    if (cur_point->node.shape.shape >= obj2_si)
 | 
						|
      continue;
 | 
						|
    cur_point_edge= !cur_point->is_bottom();
 | 
						|
 | 
						|
    for (dist_point= collector.get_first(); dist_point; dist_point= dist_point->get_next())
 | 
						|
    {
 | 
						|
      /* We only check vertices of object 2 */
 | 
						|
      if (dist_point->type != Gcalc_heap::nt_shape_node ||
 | 
						|
          dist_point->node.shape.shape < obj2_si)
 | 
						|
        continue;
 | 
						|
 | 
						|
      /* if we have an edge to check */
 | 
						|
      if (dist_point->node.shape.left)
 | 
						|
      {
 | 
						|
        t= count_edge_t(dist_point, dist_point->node.shape.left, cur_point,
 | 
						|
                        ex, ey, vx, vy, e_sqrlen);
 | 
						|
        if ((t>0.0) && (t<1.0))
 | 
						|
        {
 | 
						|
          cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
 | 
						|
          if (distance > cur_distance)
 | 
						|
            distance= cur_distance;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (cur_point_edge)
 | 
						|
      {
 | 
						|
        t= count_edge_t(cur_point, cur_point->node.shape.left, dist_point,
 | 
						|
                        ex, ey, vx, vy, e_sqrlen);
 | 
						|
        if ((t>0.0) && (t<1.0))
 | 
						|
        {
 | 
						|
          cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
 | 
						|
          if (distance > cur_distance)
 | 
						|
            distance= cur_distance;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      cur_distance= distance_points(cur_point, dist_point);
 | 
						|
      if (distance > cur_distance)
 | 
						|
        distance= cur_distance;
 | 
						|
    }
 | 
						|
  }
 | 
						|
exit:
 | 
						|
  collector.reset();
 | 
						|
  func.reset();
 | 
						|
  scan_it.reset();
 | 
						|
  DBUG_RETURN(distance);
 | 
						|
mem_error:
 | 
						|
  null_value= 1;
 | 
						|
  DBUG_RETURN(0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
double Item_func_sphere_distance::val_real()
 | 
						|
{
 | 
						|
  /* To test null_value of item, first get well-known bytes as a backups */
 | 
						|
  String bak1, bak2;
 | 
						|
  String *arg1= args[0]->val_str(&bak1);
 | 
						|
  String *arg2= args[1]->val_str(&bak2);
 | 
						|
  double distance= 0.0;
 | 
						|
  double sphere_radius= 6370986.0; // Default radius equals Earth radius
 | 
						|
 | 
						|
  null_value= (args[0]->null_value || args[1]->null_value);
 | 
						|
  if (null_value)
 | 
						|
  {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (arg_count == 3)
 | 
						|
  {
 | 
						|
    sphere_radius= args[2]->val_real();
 | 
						|
    // Radius cannot be Null
 | 
						|
    if (args[2]->null_value)
 | 
						|
    {
 | 
						|
      null_value= true;
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
    if (sphere_radius <= 0)
 | 
						|
    {
 | 
						|
      my_error(ER_GIS_UNSUPPORTED_ARGUMENT, MYF(0), func_name());
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  Geometry_buffer buffer1, buffer2;
 | 
						|
  Geometry *g1, *g2;
 | 
						|
  if (!(g1= Geometry::construct(&buffer1, arg1->ptr(), arg1->length())) ||
 | 
						|
      !(g2= Geometry::construct(&buffer2, arg2->ptr(), arg2->length())))
 | 
						|
  {
 | 
						|
    my_error(ER_GIS_INVALID_DATA, MYF(0), "ST_Distance_Sphere");
 | 
						|
    goto handle_errors;
 | 
						|
  }
 | 
						|
  // Method allowed for points and multipoints
 | 
						|
  if (!(g1->get_class_info()->m_type_id == Geometry::wkb_point ||
 | 
						|
        g1->get_class_info()->m_type_id == Geometry::wkb_multipoint) ||
 | 
						|
      !(g2->get_class_info()->m_type_id == Geometry::wkb_point ||
 | 
						|
        g2->get_class_info()->m_type_id == Geometry::wkb_multipoint))
 | 
						|
  {
 | 
						|
    // Generate error message in case of unexpected geometry.
 | 
						|
    my_error(ER_GIS_UNSUPPORTED_ARGUMENT, MYF(0), func_name());
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
  distance= spherical_distance_points(g1, g2, sphere_radius);
 | 
						|
  if (distance < 0)
 | 
						|
  {
 | 
						|
    my_error(ER_INTERNAL_ERROR, MYF(0),
 | 
						|
             "Returned distance cannot be negative.");
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
  return distance;
 | 
						|
 | 
						|
handle_errors:
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
double Item_func_sphere_distance::spherical_distance_points(Geometry *g1,
 | 
						|
                                                            Geometry *g2,
 | 
						|
                                                            const double r)
 | 
						|
{
 | 
						|
  double res= 0.0;
 | 
						|
   // Length for the single point (25 Bytes)
 | 
						|
  uint32 len= SRID_SIZE + POINT_DATA_SIZE + WKB_HEADER_SIZE;
 | 
						|
  int err_hv= 0, err_sph= 0;
 | 
						|
 | 
						|
  switch (g2->get_class_info()->m_type_id)
 | 
						|
  {
 | 
						|
    case Geometry::wkb_point:
 | 
						|
    {
 | 
						|
      Gis_point *g2p= static_cast<Gis_point *>(g2);
 | 
						|
      // Optimization for point-point case
 | 
						|
      if (g1->get_class_info()->m_type_id == Geometry::wkb_point)
 | 
						|
      {
 | 
						|
        res= g2p->calculate_haversine(g1, r, &err_hv);
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        // Optimization for single point in Multipoint
 | 
						|
        if (g1->get_data_size() == len)
 | 
						|
        {
 | 
						|
          res= g2p->calculate_haversine(g1, r, &err_hv);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          // There are multipoints in g1
 | 
						|
          // g1 is MultiPoint and calculate MP.sphericaldistance from g2 Point
 | 
						|
          if (g1->get_data_size() != GET_SIZE_ERROR)
 | 
						|
            err_sph= g2p->spherical_distance_multipoints(g1, r, &res, &err_hv);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    case Geometry::wkb_multipoint:
 | 
						|
      // Optimization for point-point case
 | 
						|
      if (g1->get_class_info()->m_type_id == Geometry::wkb_point)
 | 
						|
      {
 | 
						|
        Gis_point *g1p= static_cast<Gis_point *>(g1);
 | 
						|
         // Optimization for single point in Multipoint g2
 | 
						|
        if (g2->get_data_size() == len)
 | 
						|
        {
 | 
						|
          res= g1p->calculate_haversine(g2, r, &err_hv);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          if (g2->get_data_size() != GET_SIZE_ERROR)
 | 
						|
          // g1 is a point (casted to multi_point) and g2 multipoint
 | 
						|
            err_sph= g1p->spherical_distance_multipoints(g2, r, &res, &err_hv);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        Gis_multi_point *g1mp= static_cast<Gis_multi_point *>(g1);
 | 
						|
        // Multipoints in g1 and g2 - no optimization
 | 
						|
        err_sph= g1mp->spherical_distance_multipoints(g2, r, &res, &err_hv);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      DBUG_ASSERT(0);
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  if (err_hv == 1)
 | 
						|
    my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0),
 | 
						|
             "Longitude should be [-180,180]", "ST_Distance_Sphere");
 | 
						|
  else if(err_hv < 0)
 | 
						|
    my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0),
 | 
						|
             "Latitude should be [-90,90]", "ST_Distance_Sphere");
 | 
						|
  else if (err_sph || err_hv == 2)
 | 
						|
    my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, MYF(0));
 | 
						|
  return res;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
String *Item_func_pointonsurface::val_str(String *str)
 | 
						|
{
 | 
						|
  Gcalc_operation_transporter trn(&func, &collector);
 | 
						|
 | 
						|
  DBUG_ENTER("Item_func_pointonsurface::val_str");
 | 
						|
  DBUG_ASSERT(fixed == 1);
 | 
						|
  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;
 | 
						|
 | 
						|
  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);
 | 
						|
  if (str->reserve(SRID_SIZE, 512))
 | 
						|
    goto mem_error;
 | 
						|
 | 
						|
  str->length(0);
 | 
						|
  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;
 | 
						|
  ~Create_func_area() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_as_wkb : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_as_wkb(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_as_wkb s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_as_wkb() = default;
 | 
						|
  ~Create_func_as_wkb() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_as_wkt : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_as_wkt(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_as_wkt s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_as_wkt() = default;
 | 
						|
  ~Create_func_as_wkt() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
class Create_func_centroid : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_centroid(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_centroid s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_centroid() = default;
 | 
						|
  ~Create_func_centroid() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_convexhull : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_convexhull(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_convexhull s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_convexhull() = default;
 | 
						|
  ~Create_func_convexhull() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_pointonsurface : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_pointonsurface(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_pointonsurface s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_pointonsurface() = default;
 | 
						|
  ~Create_func_pointonsurface() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_mbr_contains : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
 | 
						|
      Item_func::SP_CONTAINS_FUNC);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_mbr_contains s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_mbr_contains() = default;
 | 
						|
  ~Create_func_mbr_contains() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_contains : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
 | 
						|
                                                 Item_func::SP_CONTAINS_FUNC);
 | 
						|
  }
 | 
						|
  static Create_func_contains s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_contains() = default;
 | 
						|
  ~Create_func_contains() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_crosses : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
 | 
						|
                                                   Item_func::SP_CROSSES_FUNC);
 | 
						|
  }
 | 
						|
  static Create_func_crosses s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_crosses() = default;
 | 
						|
  ~Create_func_crosses() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_dimension : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_dimension(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_dimension s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_dimension() = default;
 | 
						|
  ~Create_func_dimension() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_mbr_disjoint : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
 | 
						|
                                                  Item_func::SP_DISJOINT_FUNC);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_mbr_disjoint s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_mbr_disjoint() = default;
 | 
						|
  ~Create_func_mbr_disjoint() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_disjoint : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
 | 
						|
                                                  Item_func::SP_DISJOINT_FUNC);
 | 
						|
  }
 | 
						|
  static Create_func_disjoint s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_disjoint() = default;
 | 
						|
  ~Create_func_disjoint() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_distance : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_distance(thd, arg1, arg2);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_distance s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_distance() = default;
 | 
						|
  ~Create_func_distance() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_distance_sphere: public Create_native_func
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_native(THD *thd, const LEX_CSTRING *name, List<Item> *item_list)
 | 
						|
    override;
 | 
						|
  static Create_func_distance_sphere s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_distance_sphere() = default;
 | 
						|
  ~Create_func_distance_sphere() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
Item*
 | 
						|
Create_func_distance_sphere::create_native(THD *thd, const LEX_CSTRING *name,
 | 
						|
                                           List<Item> *item_list)
 | 
						|
{
 | 
						|
  int arg_count= 0;
 | 
						|
 | 
						|
  if (item_list != NULL)
 | 
						|
    arg_count= item_list->elements;
 | 
						|
 | 
						|
  if (arg_count < 2)
 | 
						|
  {
 | 
						|
    my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
  return new (thd->mem_root) Item_func_sphere_distance(thd, *item_list);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class Create_func_endpoint : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
 | 
						|
                                                        Item_func::SP_ENDPOINT);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_endpoint s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_endpoint() = default;
 | 
						|
  ~Create_func_endpoint() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_envelope : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_envelope(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_envelope s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_envelope() = default;
 | 
						|
  ~Create_func_envelope() override = default;
 | 
						|
};
 | 
						|
 | 
						|
class Create_func_boundary : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_boundary(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_boundary s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_boundary() = default;
 | 
						|
  ~Create_func_boundary() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_mbr_equals : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
 | 
						|
                                                     Item_func::SP_EQUALS_FUNC);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_mbr_equals s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_mbr_equals() = default;
 | 
						|
  ~Create_func_mbr_equals() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_equals : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
      return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
 | 
						|
                                                    Item_func::SP_EQUALS_FUNC);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_equals s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_equals() = default;
 | 
						|
  ~Create_func_equals() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_exteriorring : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
 | 
						|
                                                      Item_func::SP_EXTERIORRING);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_exteriorring s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_exteriorring() = default;
 | 
						|
  ~Create_func_exteriorring() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
class Create_func_geometry_from_text : public Create_native_func
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_native(THD *thd, const LEX_CSTRING *name, List<Item> *item_list)
 | 
						|
    override;
 | 
						|
 | 
						|
  static Create_func_geometry_from_text s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_geometry_from_text() = default;
 | 
						|
  ~Create_func_geometry_from_text() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
Item*
 | 
						|
Create_func_geometry_from_text::create_native(THD *thd,
 | 
						|
                                              const LEX_CSTRING *name,
 | 
						|
                                              List<Item> *item_list)
 | 
						|
{
 | 
						|
  Item *func= NULL;
 | 
						|
  int arg_count= 0;
 | 
						|
 | 
						|
  if (item_list != NULL)
 | 
						|
    arg_count= item_list->elements;
 | 
						|
 | 
						|
  switch (arg_count) {
 | 
						|
  case 1:
 | 
						|
  {
 | 
						|
    Item *param_1= item_list->pop();
 | 
						|
    func= new (thd->mem_root) Item_func_geometry_from_text(thd, param_1);
 | 
						|
    thd->lex->uncacheable(UNCACHEABLE_RAND);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case 2:
 | 
						|
  {
 | 
						|
    Item *param_1= item_list->pop();
 | 
						|
    Item *param_2= item_list->pop();
 | 
						|
    func= new (thd->mem_root) Item_func_geometry_from_text(thd, param_1, param_2);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  default:
 | 
						|
  {
 | 
						|
    my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  }
 | 
						|
 | 
						|
  return func;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class Create_func_geometry_from_wkb : public Create_native_func
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_native(THD *thd, const LEX_CSTRING *name, List<Item> *item_list)
 | 
						|
    override;
 | 
						|
 | 
						|
  static Create_func_geometry_from_wkb s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_geometry_from_wkb() = default;
 | 
						|
  ~Create_func_geometry_from_wkb() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
Item*
 | 
						|
Create_func_geometry_from_wkb::create_native(THD *thd, const LEX_CSTRING *name,
 | 
						|
                                             List<Item> *item_list)
 | 
						|
{
 | 
						|
  Item *func= NULL;
 | 
						|
  int arg_count= 0;
 | 
						|
 | 
						|
  if (item_list != NULL)
 | 
						|
    arg_count= item_list->elements;
 | 
						|
 | 
						|
  switch (arg_count) {
 | 
						|
  case 1:
 | 
						|
  {
 | 
						|
    Item *param_1= item_list->pop();
 | 
						|
    func= new (thd->mem_root) Item_func_geometry_from_wkb(thd, param_1);
 | 
						|
    thd->lex->uncacheable(UNCACHEABLE_RAND);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case 2:
 | 
						|
  {
 | 
						|
    Item *param_1= item_list->pop();
 | 
						|
    Item *param_2= item_list->pop();
 | 
						|
    func= new (thd->mem_root) Item_func_geometry_from_wkb(thd, param_1, param_2);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  default:
 | 
						|
  {
 | 
						|
    my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  }
 | 
						|
 | 
						|
  return func;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class Create_func_geometry_from_json : public Create_native_func
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_native(THD *thd, const LEX_CSTRING *name, List<Item> *item_list)
 | 
						|
    override;
 | 
						|
 | 
						|
  static Create_func_geometry_from_json s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_geometry_from_json() = default;
 | 
						|
  ~Create_func_geometry_from_json() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
Item*
 | 
						|
Create_func_geometry_from_json::create_native(THD *thd,
 | 
						|
                                              const LEX_CSTRING *name,
 | 
						|
                                              List<Item> *item_list)
 | 
						|
{
 | 
						|
  Item *func= NULL;
 | 
						|
  int arg_count= 0;
 | 
						|
 | 
						|
  if (item_list != NULL)
 | 
						|
    arg_count= item_list->elements;
 | 
						|
 | 
						|
  switch (arg_count) {
 | 
						|
  case 1:
 | 
						|
  {
 | 
						|
    Item *json= item_list->pop();
 | 
						|
    func= new (thd->mem_root) Item_func_geometry_from_json(thd, json);
 | 
						|
    thd->lex->uncacheable(UNCACHEABLE_RAND);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case 2:
 | 
						|
  {
 | 
						|
    Item *json= item_list->pop();
 | 
						|
    Item *options= item_list->pop();
 | 
						|
    func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case 3:
 | 
						|
  {
 | 
						|
    Item *json= item_list->pop();
 | 
						|
    Item *options= item_list->pop();
 | 
						|
    Item *srid= item_list->pop();
 | 
						|
    func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options,
 | 
						|
                                                           srid);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  default:
 | 
						|
  {
 | 
						|
    my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  }
 | 
						|
 | 
						|
  return func;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class Create_func_as_geojson : public Create_native_func
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_native(THD *thd, const LEX_CSTRING *name, List<Item> *item_list)
 | 
						|
    override;
 | 
						|
 | 
						|
  static Create_func_as_geojson s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_as_geojson() = default;
 | 
						|
  ~Create_func_as_geojson() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
Item*
 | 
						|
Create_func_as_geojson::create_native(THD *thd, const LEX_CSTRING *name,
 | 
						|
                                      List<Item> *item_list)
 | 
						|
{
 | 
						|
  Item *func= NULL;
 | 
						|
  int arg_count= 0;
 | 
						|
 | 
						|
  if (item_list != NULL)
 | 
						|
    arg_count= item_list->elements;
 | 
						|
 | 
						|
  switch (arg_count) {
 | 
						|
  case 1:
 | 
						|
  {
 | 
						|
    Item *geom= item_list->pop();
 | 
						|
    func= new (thd->mem_root) Item_func_as_geojson(thd, geom);
 | 
						|
    thd->lex->uncacheable(UNCACHEABLE_RAND);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case 2:
 | 
						|
  {
 | 
						|
    Item *geom= item_list->pop();
 | 
						|
    Item *max_dec= item_list->pop();
 | 
						|
    func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case 3:
 | 
						|
  {
 | 
						|
    Item *geom= item_list->pop();
 | 
						|
    Item *max_dec= item_list->pop();
 | 
						|
    Item *options= item_list->pop();
 | 
						|
    func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec, options);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  default:
 | 
						|
  {
 | 
						|
    my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  }
 | 
						|
 | 
						|
  return func;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class Create_func_geometry_type : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_geometry_type(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_geometry_type s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_geometry_type() = default;
 | 
						|
  ~Create_func_geometry_type() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_geometryn : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
 | 
						|
                                                      Item_func::SP_GEOMETRYN);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_geometryn s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_geometryn() = default;
 | 
						|
  ~Create_func_geometryn() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
#if !defined(DBUG_OFF)
 | 
						|
class Create_func_gis_debug : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_gis_debug(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_gis_debug s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_gis_debug() = default;
 | 
						|
  ~Create_func_gis_debug() override = default;
 | 
						|
};
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
class Create_func_glength : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_glength(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_glength s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_glength() = default;
 | 
						|
  ~Create_func_glength() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_interiorringn : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
 | 
						|
                                                  Item_func::SP_INTERIORRINGN);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_interiorringn s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_interiorringn() = default;
 | 
						|
  ~Create_func_interiorringn() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_relate : public Create_func_arg3
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_relate(thd, arg1, arg2, arg3);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_relate s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_relate() = default;
 | 
						|
  ~Create_func_relate() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_mbr_intersects : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
 | 
						|
        Item_func::SP_INTERSECTS_FUNC);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_mbr_intersects s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_mbr_intersects() = default;
 | 
						|
  ~Create_func_mbr_intersects() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_intersects : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
 | 
						|
                                               Item_func::SP_INTERSECTS_FUNC);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_intersects s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_intersects() = default;
 | 
						|
  ~Create_func_intersects() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_intersection : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
 | 
						|
                                 Gcalc_function::op_intersection);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_intersection s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_intersection() = default;
 | 
						|
  ~Create_func_intersection() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_difference : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
 | 
						|
                                 Gcalc_function::op_difference);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_difference s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_difference() = default;
 | 
						|
  ~Create_func_difference() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_union : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
 | 
						|
                                 Gcalc_function::op_union);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_union s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_union() = default;
 | 
						|
  ~Create_func_union() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_symdifference : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
 | 
						|
                                 Gcalc_function::op_symdifference);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_symdifference s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_symdifference() = default;
 | 
						|
  ~Create_func_symdifference() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_buffer : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_buffer(thd, arg1, arg2);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_buffer s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_buffer() = default;
 | 
						|
  ~Create_func_buffer() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_isclosed : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_isclosed(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_isclosed s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_isclosed() = default;
 | 
						|
  ~Create_func_isclosed() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_isring : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_isring(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_isring s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_isring() = default;
 | 
						|
  ~Create_func_isring() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_isempty : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_isempty(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_isempty s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_isempty() = default;
 | 
						|
  ~Create_func_isempty() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_issimple : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_issimple(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_issimple s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_issimple() = default;
 | 
						|
  ~Create_func_issimple() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
class Create_func_numgeometries : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_numgeometries(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_numgeometries s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_numgeometries() = default;
 | 
						|
  ~Create_func_numgeometries() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_numinteriorring : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_numinteriorring(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_numinteriorring s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_numinteriorring() = default;
 | 
						|
  ~Create_func_numinteriorring() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_numpoints : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_numpoints(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_numpoints s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_numpoints() = default;
 | 
						|
  ~Create_func_numpoints() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_mbr_overlaps : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
 | 
						|
        Item_func::SP_OVERLAPS_FUNC);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_mbr_overlaps s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_mbr_overlaps() = default;
 | 
						|
  ~Create_func_mbr_overlaps() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_overlaps : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
 | 
						|
                                                  Item_func::SP_OVERLAPS_FUNC);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_overlaps s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_overlaps() = default;
 | 
						|
  ~Create_func_overlaps() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
class Create_func_pointn : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
 | 
						|
                                                          Item_func::SP_POINTN);
 | 
						|
  }
 | 
						|
  static Create_func_pointn s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_pointn() = default;
 | 
						|
  ~Create_func_pointn() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
class Create_func_srid : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_srid(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_srid s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_srid() = default;
 | 
						|
  ~Create_func_srid() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_startpoint : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
 | 
						|
                                                     Item_func::SP_STARTPOINT);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_startpoint s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_startpoint() = default;
 | 
						|
  ~Create_func_startpoint() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
class Create_func_touches : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
 | 
						|
                                                   Item_func::SP_TOUCHES_FUNC);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_touches s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_touches() = default;
 | 
						|
  ~Create_func_touches() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_mbr_within : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
 | 
						|
      Item_func::SP_WITHIN_FUNC);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_mbr_within s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_mbr_within() = default;
 | 
						|
  ~Create_func_mbr_within() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_within : public Create_func_arg2
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
 | 
						|
                                                   Item_func::SP_WITHIN_FUNC);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_within s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_within() = default;
 | 
						|
  ~Create_func_within() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_x : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_x(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_x s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_x() = default;
 | 
						|
  ~Create_func_x() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
class Create_func_y : public Create_func_arg1
 | 
						|
{
 | 
						|
public:
 | 
						|
  Item *create_1_arg(THD *thd, Item *arg1) override
 | 
						|
  {
 | 
						|
    return new (thd->mem_root) Item_func_y(thd, arg1);
 | 
						|
  }
 | 
						|
 | 
						|
  static Create_func_y s_singleton;
 | 
						|
 | 
						|
protected:
 | 
						|
  Create_func_y() = default;
 | 
						|
  ~Create_func_y() override = default;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/*****************************************************************/
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*************************************************************************/
 | 
						|
 | 
						|
#if !defined(DBUG_OFF)
 | 
						|
Create_func_gis_debug Create_func_gis_debug::s_singleton;
 | 
						|
#endif
 | 
						|
 | 
						|
Create_func_area Create_func_area::s_singleton;
 | 
						|
Create_func_as_geojson Create_func_as_geojson::s_singleton;
 | 
						|
Create_func_as_wkb Create_func_as_wkb::s_singleton;
 | 
						|
Create_func_as_wkt Create_func_as_wkt::s_singleton;
 | 
						|
Create_func_boundary Create_func_boundary::s_singleton;
 | 
						|
Create_func_buffer Create_func_buffer::s_singleton;
 | 
						|
Create_func_centroid Create_func_centroid::s_singleton;
 | 
						|
Create_func_contains Create_func_contains::s_singleton;
 | 
						|
Create_func_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_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*/
 |