mariadb/sql/item_geofunc.cc
unknown 295732b580 Merge bk-internal.mysql.com:/home/bk/mysql-5.1-maint
into  janus.mylan:/usr/home/serg/Abk/mysql-5.1


configure.in:
  Auto merged
libmysql/CMakeLists.txt:
  Auto merged
libmysqld/lib_sql.cc:
  Auto merged
mysql-test/mysql-test-run.pl:
  Auto merged
mysql-test/r/information_schema.result:
  Auto merged
mysql-test/t/information_schema.test:
  Auto merged
sql/Makefile.am:
  Auto merged
sql/field.cc:
  Auto merged
sql/handler.cc:
  Auto merged
sql/item.cc:
  Auto merged
sql/item_func.cc:
  Auto merged
sql/item_geofunc.cc:
  Auto merged
sql/item_subselect.cc:
  Auto merged
sql/key.cc:
  Auto merged
sql/lock.cc:
  Auto merged
sql/log.cc:
  Auto merged
sql/log_event.cc:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/mysqld.cc:
  Auto merged
sql/net_serv.cc:
  Auto merged
sql/opt_sum.cc:
  Auto merged
sql/protocol.h:
  Auto merged
sql/repl_failsafe.cc:
  Auto merged
sql/set_var.cc:
  Auto merged
sql/set_var.h:
  Auto merged
sql/sp_head.cc:
  Auto merged
sql/sql_base.cc:
  Auto merged
sql/sql_cache.cc:
  Auto merged
sql/sql_class.cc:
  Auto merged
sql/sql_delete.cc:
  Auto merged
sql/sql_insert.cc:
  Auto merged
sql/sql_lex.cc:
  Auto merged
sql/sql_prepare.cc:
  Auto merged
sql/sql_select.cc:
  Auto merged
sql/sql_select.h:
  Auto merged
sql/sql_show.cc:
  Auto merged
sql/sql_table.cc:
  Auto merged
sql/sql_update.cc:
  Auto merged
sql/sql_yacc.yy:
  Auto merged
sql/table.h:
  Auto merged
storage/archive/ha_archive.cc:
  Auto merged
storage/innobase/buf/buf0buf.c:
  Auto merged
storage/innobase/buf/buf0flu.c:
  Auto merged
storage/innobase/buf/buf0lru.c:
  Auto merged
storage/innobase/include/buf0buf.h:
  Auto merged
storage/innobase/include/buf0buf.ic:
  Auto merged
storage/innobase/include/sync0arr.h:
  Auto merged
storage/innobase/include/sync0rw.h:
  Auto merged
storage/innobase/include/sync0rw.ic:
  Auto merged
storage/innobase/include/sync0sync.h:
  Auto merged
storage/innobase/os/os0sync.c:
  Auto merged
storage/innobase/sync/sync0arr.c:
  Auto merged
storage/innobase/sync/sync0rw.c:
  Auto merged
storage/innobase/sync/sync0sync.c:
  Auto merged
storage/myisam/ha_myisam.cc:
  Auto merged
storage/myisam/mi_open.c:
  Auto merged
storage/myisammrg/ha_myisammrg.cc:
  Auto merged
sql/ha_ndbcluster.cc:
  merged
sql/item_cmpfunc.cc:
  merged
sql/protocol.cc:
  merged
sql/slave.cc:
  merged
sql/sql_class.h:
  merged
sql/sql_parse.cc:
  merged
2007-12-20 22:11:37 +01:00

732 lines
16 KiB
C++

/* Copyright (C) 2003-2006 MySQL AB
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/**
@file
@brief
This file defines all spatial functions
*/
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
#include "mysql_priv.h"
#ifdef HAVE_SPATIAL
#include <m_ctype.h>
Field *Item_geometry_func::tmp_table_field(TABLE *t_arg)
{
Field *result;
if ((result= new Field_geom(max_length, maybe_null, name, t_arg->s,
get_geometry_type())))
result->init(t_arg);
return result;
}
void Item_geometry_func::fix_length_and_dec()
{
collation.set(&my_charset_bin);
decimals=0;
max_length= max_field_size;
maybe_null= 1;
}
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(&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);
if (str->reserve(SRID_SIZE, 512))
return 0;
str->length(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= args[0]->val_str(&arg_val);
Geometry_buffer buffer;
uint32 srid= 0;
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))
return 0;
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;
}
String *Item_func_as_wkt::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;
const char *dummy;
if ((null_value=
(args[0]->null_value ||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
return 0;
str->length(0);
if ((null_value= geom->as_wkt(str, &dummy)))
return 0;
return str;
}
void Item_func_as_wkt::fix_length_and_dec()
{
max_length=MAX_BLOB_WIDTH;
maybe_null= 1;
}
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;
}
String *Item_func_geometry_type::val_str(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,
default_charset());
return str;
}
Field::geometry_type Item_func_envelope::get_geometry_type() const
{
return Field::GEOM_POLYGON;
}
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;
}
Field::geometry_type Item_func_centroid::get_geometry_type() const
{
return Field::GEOM_POINT;
}
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= test(geom->centroid(str))) ? 0 : str;
}
/*
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
*/
Field::geometry_type Item_func_point::get_geometry_type() const
{
return Field::GEOM_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();
if ((null_value= (args[0]->null_value ||
args[1]->null_value ||
str->realloc(1 + 4 + SIZEOF_STORED_DOUBLE*2))))
return 0;
str->set_charset(&my_charset_bin);
str->length(0);
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;
str->set_charset(&my_charset_bin);
str->length(0);
if (str->reserve(1 + 4 + 4, 512))
goto err;
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(), len, (uint32) 512))
goto err;
}
else
{
enum Geometry::wkbType wkb_type;
const char *data= res->ptr() + 1;
/*
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;
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 (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 + 2 * POINT_DATA_SIZE)
goto err;
n_points= uint4korr(data);
data+= 4;
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)
{
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_ALLOWED_PACKET_OVERFLOWED,
ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED),
func_name(), current_thd->variables.max_allowed_packet);
goto err;
}
null_value = 0;
return str;
err:
null_value= 1;
return 0;
}
/*
Functions for spatial relations
*/
longlong Item_func_spatial_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) ||
g2->get_mbr(&mbr2, &dummy))))
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;
}
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;
}
/**
@todo
Ramil or Holyfoot, add real IsSimple calculation
*/
longlong Item_func_issimple::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()));
/* TODO: Ramil or Holyfoot, add real IsSimple calculation */
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= (!swkb ||
args[0]->null_value ||
!(geom=
Geometry::construct(&buffer, swkb->ptr(), swkb->length())) ||
geom->is_closed(&isclosed));
return (longlong) isclosed;
}
/*
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;
null_value= (!swkb ||
!(geom= Geometry::construct(&buffer,
swkb->ptr(),
swkb->length())) ||
geom->geom_length(&res));
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()));
}
#endif /*HAVE_SPATIAL*/