summaryrefslogtreecommitdiff
path: root/sql/item_geofunc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_geofunc.cc')
-rw-r--r--sql/item_geofunc.cc310
1 files changed, 211 insertions, 99 deletions
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index fc7367dcd67..07059fed4be 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -38,6 +38,7 @@
#include "set_var.h"
#ifdef HAVE_SPATIAL
#include <m_ctype.h>
+#include "opt_range.h"
Field *Item_geometry_func::tmp_table_field(TABLE *t_arg)
@@ -908,10 +909,11 @@ String *Item_func_spatial_collection::val_str(String *str)
}
if (str->length() > current_thd->variables.max_allowed_packet)
{
- push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ THD *thd= current_thd;
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_WARN_ALLOWED_PACKET_OVERFLOWED,
- ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED),
- func_name(), current_thd->variables.max_allowed_packet);
+ ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
+ func_name(), thd->variables.max_allowed_packet);
goto err;
}
@@ -928,6 +930,78 @@ err:
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);
+
+ if (value->save_in_field_no_warnings(field, 1))
+ 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_WITHIN;// NEAR_MIN;//512;
+ tree->max_flag= NO_MAX_RANGE;
+ break;
+ case SP_CONTAINS_FUNC:
+ tree->min_flag= GEOM_FLAG | HA_READ_MBR_CONTAIN;// 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) {
@@ -1018,8 +1092,6 @@ const char *Item_func_spatial_precise_rel::func_name() const
return "st_crosses";
case SP_OVERLAPS_FUNC:
return "st_overlaps";
- case SP_RELATE_FUNC:
- return "st_relate";
default:
DBUG_ASSERT(0); // Should never happened
return "sp_unknown";
@@ -1080,7 +1152,7 @@ static int setup_relate_func(Geometry *g1, Geometry *g2,
const char *mask)
{
int do_store_shapes=1;
- uint shape_a, shape_b;
+ uint UNINIT_VAR(shape_a), UNINIT_VAR(shape_b);
uint n_operands= 0;
int last_shape_pos;
@@ -1104,8 +1176,10 @@ static int setup_relate_func(Geometry *g1, Geometry *g2,
cur_op|= Gcalc_function::v_find_t;
break;
case 'F':
- cur_op|= (Gcalc_function::op_not | Gcalc_function::v_find_t);
+ cur_op|= (Gcalc_function::op_not | Gcalc_function::v_find_f);
break;
+ default:
+ return 1;
};
++n_operands;
if (func->reserve_op_buffer(3))
@@ -1140,94 +1214,139 @@ static int setup_relate_func(Geometry *g1, Geometry *g2,
#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);
- String *res1;
- String *res2;
- String *res3;
- Geometry_buffer buffer1, buffer2;
- Geometry *g1, *g2;
+ Geometry_ptr_with_buffer_and_mbr g1, g2;
int result= 0;
- int mask= 0;
uint shape_a, shape_b;
- MBR umbr, mbr1, mbr2;
- const char *c_end;
- res1= args[0]->val_str(&tmp_value1);
- res2= args[1]->val_str(&tmp_value2);
- Gcalc_operation_transporter trn(&func, &collector);
-
- if (func.reserve_op_buffer(1))
+ if ((null_value= (g1.construct(args[0], &tmp_value1) ||
+ g2.construct(args[1], &tmp_value2) ||
+ func.reserve_op_buffer(1))))
DBUG_RETURN(0);
- 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, &c_end) || !mbr1.valid() ||
- g2->get_mbr(&mbr2, &c_end) || !mbr2.valid())))
- goto exit;
+ Gcalc_operation_transporter trn(&func, &collector);
- umbr= mbr1;
- umbr.add_mbr(&mbr2);
+ MBR umbr(g1.mbr, g2.mbr);
collector.set_extent(umbr.xmin, umbr.xmax, umbr.ymin, umbr.ymax);
- mbr1.buffer(1e-5);
+ g1.mbr.buffer(1e-5);
switch (spatial_rel) {
case SP_CONTAINS_FUNC:
- if (!mbr1.contains(&mbr2))
+ if (!g1.mbr.contains(&g2.mbr))
goto exit;
- mask= 1;
- func.add_operation(Gcalc_function::op_difference, 2);
+ 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);
+ null_value= g2.store_shapes(&trn) || g1.store_shapes(&trn);
break;
case SP_WITHIN_FUNC:
- mbr2.buffer(2e-5);
- if (!mbr1.within(&mbr2))
+ g2.mbr.buffer(2e-5);
+ if (!g1.mbr.within(&g2.mbr))
goto exit;
- mask= 1;
- func.add_operation(Gcalc_function::op_difference, 2);
- null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn);
+ 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 (!mbr1.contains(&mbr2))
+ if (!g1.mbr.contains(&g2.mbr))
goto exit;
- mask= 1;
- func.add_operation(Gcalc_function::op_symdifference, 2);
- null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn);
+ 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:
- mask= 1;
- func.add_operation(Gcalc_function::op_intersection, 2);
- null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn);
+ 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 (!mbr1.intersects(&mbr2))
+ if (!g1.mbr.intersects(&g2.mbr))
goto exit;
- func.add_operation(Gcalc_function::op_intersection, 2);
- null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn);
+ 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(1))
+ 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)))
+ if ((null_value= g1.store_shapes(&trn)))
break;
shape_b= func.get_next_expression_pos();
- if ((null_value= g2->store_shapes(&trn)))
+ if ((null_value= g2.store_shapes(&trn)))
break;
if (func.reserve_op_buffer(7))
break;
- func.add_operation(Gcalc_function::v_find_t |
- Gcalc_function::op_intersection, 2);
+ 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);
@@ -1238,7 +1357,7 @@ longlong Item_func_spatial_precise_rel::val_int()
func.repeat_expression(shape_a);
break;
case SP_TOUCHES_FUNC:
- if (func.reserve_op_buffer(2))
+ if (func.reserve_op_buffer(5))
break;
func.add_operation(Gcalc_function::op_intersection, 2);
func.add_operation(Gcalc_function::v_find_f |
@@ -1246,26 +1365,17 @@ longlong Item_func_spatial_precise_rel::val_int()
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)))
+ if ((null_value= g1.store_shapes(&trn)))
break;
func.add_operation(Gcalc_function::op_internals, 1);
shape_b= func.get_next_expression_pos();
- if ((null_value= g2->store_shapes(&trn)))
+ if ((null_value= g2.store_shapes(&trn)))
break;
func.add_operation(Gcalc_function::v_find_t |
Gcalc_function::op_intersection, 2);
- func.add_operation(Gcalc_function::op_border, 1);
func.repeat_expression(shape_a);
- func.add_operation(Gcalc_function::op_border, 1);
func.repeat_expression(shape_b);
break;
- case SP_RELATE_FUNC:
- res3= args[2]->val_str(&tmp_matrix);
- if ((null_value= args[2]->null_value))
- break;
- null_value= (res3->length() != 9) ||
- setup_relate_func(g1, g2, &trn, &func, res3->ptr());
- break;
default:
DBUG_ASSERT(FALSE);
break;
@@ -1281,7 +1391,7 @@ longlong Item_func_spatial_precise_rel::val_int()
if (func.alloc_states())
goto exit;
- result= func.check_function(scan_it) ^ mask;
+ result= func.check_function(scan_it);
exit:
collector.reset();
@@ -1300,34 +1410,25 @@ String *Item_func_spatial_operation::val_str(String *str_value)
{
DBUG_ENTER("Item_func_spatial_operation::val_str");
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;
+ Geometry_ptr_with_buffer_and_mbr g1, g2;
uint32 srid= 0;
Gcalc_operation_transporter trn(&func, &collector);
- MBR mbr1, mbr2;
- const char *c_end;
if (func.reserve_op_buffer(1))
DBUG_RETURN(0);
func.add_operation(spatial_op, 2);
- 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, &c_end) || !mbr1.valid() ||
- g2->get_mbr(&mbr2, &c_end) || !mbr2.valid())))
+ if ((null_value= (g1.construct(args[0], &tmp_value1) ||
+ g2.construct(args[1], &tmp_value2))))
{
str_value= 0;
goto exit;
}
- mbr1.add_mbr(&mbr2);
- collector.set_extent(mbr1.xmin, mbr1.xmax, mbr1.ymin, mbr1.ymax);
+ 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)))
+ if ((null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn)))
{
str_value= 0;
goto exit;
@@ -1350,7 +1451,7 @@ String *Item_func_spatial_operation::val_str(String *str_value)
str_value->length(0);
str_value->q_append(srid);
- if (!Geometry::create_from_opresult(&buffer1, str_value, res_receiver))
+ if (!Geometry::create_from_opresult(&g1.buffer, str_value, res_receiver))
goto exit;
exit:
@@ -1857,10 +1958,14 @@ longlong Item_func_issimple::val_int()
DBUG_ENTER("Item_func_issimple::val_int");
DBUG_ASSERT(fixed == 1);
- if ((null_value= (args[0]->null_value ||
- !(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length())) ||
- g->get_mbr(&mbr, &c_end))))
- DBUG_RETURN(0);
+ 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);
@@ -1921,11 +2026,15 @@ longlong Item_func_isclosed::val_int()
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));
+ 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;
}
@@ -1941,11 +2050,15 @@ longlong Item_func_isring::val_int()
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));
+ 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;
@@ -2281,12 +2394,11 @@ String *Item_func_pointonsurface::val_str(String *str)
Geometry *g;
MBR mbr;
const char *c_end;
- double px, py, x0, y0;
+ double UNINIT_VAR(px), UNINIT_VAR(py), x0, 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())) ||