summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexey Botchkov <holyfoot@askmonty.org>2011-09-22 18:53:36 +0500
committerAlexey Botchkov <holyfoot@askmonty.org>2011-09-22 18:53:36 +0500
commit5123f59ed2b363ac25fdef374af607f93ec9d762 (patch)
treea5cca669b6ba71be91edb191f4c4da015d254e64 /sql
parentd0f2e1e55176c7f674832444ea174c2445058ef7 (diff)
downloadmariadb-git-5123f59ed2b363ac25fdef374af607f93ec9d762.tar.gz
fixed bugs
855485 ST_CROSSES returns different result than PostGIS for overlapping polygons 855487 ST_WITHIN returns wrong result for partially overlapping polygons 855492 ST_WITHIN returns TRUE on point on the edge of a polygon 855497 ST_ENVELOPE of GEOMETRYCOLLECTION EMPTY returns NULL and not GEOMETRYCOLLECTION EMPTY 855503 ST_EQUALS reports TRUE between a POLYGON and a MULTILINESTRING 855505 ST_TOUCHES reports TRUE for intersecting polygon and linestring Changed the way weird functions like Crosses or Touches treated. Added BORDER handling to the Gcalc_function. per-file comments: mysql-test/r/gis-precise.result GIS bugs fixed. test result updated. mysql-test/t/gis-precise.test GIS bugs fixed. test cases added. sql/gcalc_slicescan.h GIS bugs fixed. sql/gcalc_tools.cc GIS bugs fixed. sql/gcalc_tools.h GIS bugs fixed. sql/item_create.cc GIS bugs fixed. sql/item_geofunc.cc GIS bugs fixed. sql/item_geofunc.h GIS bugs fixed. sql/spatial.cc GIS bugs fixed.
Diffstat (limited to 'sql')
-rw-r--r--sql/gcalc_slicescan.h1
-rw-r--r--sql/gcalc_tools.cc211
-rw-r--r--sql/gcalc_tools.h60
-rw-r--r--sql/item_create.cc6
-rw-r--r--sql/item_geofunc.cc213
-rw-r--r--sql/item_geofunc.h3
-rw-r--r--sql/spatial.cc6
7 files changed, 278 insertions, 222 deletions
diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h
index d1c81ca4648..fe7959c4172 100644
--- a/sql/gcalc_slicescan.h
+++ b/sql/gcalc_slicescan.h
@@ -307,6 +307,7 @@ public:
virtual int complete_ring()=0;
virtual int add_point(double x, double y)=0;
virtual int start_collection(int n_objects) { return 0; }
+ virtual int empty_shape() { return 0; }
int start_simple_poly()
{
return start_poly() || start_ring();
diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc
index 90c39f08d0b..6a2fdbccacb 100644
--- a/sql/gcalc_tools.cc
+++ b/sql/gcalc_tools.cc
@@ -43,7 +43,7 @@ gcalc_shape_info Gcalc_function::add_new_shape(uint32 shape_id,
in prefix style.
*/
-void Gcalc_function::add_operation(op_type operation, uint32 n_operands)
+void Gcalc_function::add_operation(uint operation, uint32 n_operands)
{
uint32 op_code= (uint32 ) operation + n_operands;
function_buffer.q_append(op_code);
@@ -84,6 +84,15 @@ int Gcalc_function::single_shape_op(shape_type shape_kind, gcalc_shape_info *si)
}
+int Gcalc_function::repeat_expression(uint32 exp_pos)
+{
+ if (reserve_op_buffer(1))
+ return 1;
+ add_operation(op_repeat, exp_pos);
+ return 0;
+}
+
+
/*
Specify how many arguments we're going to have.
*/
@@ -109,42 +118,61 @@ int Gcalc_function::alloc_states()
if (function_buffer.reserve((n_shapes+1) * 2 * sizeof(int)))
return 1;
i_states= (int *) (function_buffer.ptr() + ALIGN_SIZE(function_buffer.length()));
- saved_i_states= i_states + (n_shapes + 1);
+ b_states= i_states + (n_shapes + 1);
return 0;
}
-void Gcalc_function::save_states()
+int Gcalc_function::count_internal(const char *cur_func, uint set_type,
+ const char **end)
{
- memcpy(saved_i_states, i_states, (n_shapes+1) * sizeof(int));
-}
-
-
-void Gcalc_function::restore_states()
-{
- memcpy(i_states, saved_i_states, (n_shapes+1) * sizeof(int));
-}
-
-
-int Gcalc_function::count_internal()
-{
- int c_op= uint4korr(cur_func);
+ uint c_op= uint4korr(cur_func);
op_type next_func= (op_type) (c_op & op_any);
int mask= (c_op & op_not) ? 1:0;
- int n_ops= c_op & ~op_any;
+ uint n_ops= c_op & ~(op_any | op_not | v_mask);
+ uint n_shape= c_op & ~(op_any | op_not | v_mask); /* same as n_ops */
+ value v_state= (value) (c_op & v_mask);
int result;
+ const char *sav_cur_func= cur_func;
cur_func+= 4;
if (next_func == op_shape)
- return i_states[c_op & ~(op_any | op_not)] ^ mask;
+ {
+ if (set_type == 0)
+ result= i_states[n_shape] | b_states[n_shape];
+ else if (set_type == op_border)
+ result= b_states[n_shape];
+ else if (set_type == op_internals)
+ result= i_states[n_shape] && !b_states[n_shape];
+ goto exit;
+ }
+
+ if (next_func == op_false)
+ {
+ result= 0;
+ goto exit;
+ }
+
+ if (next_func == op_border || next_func == op_internals)
+ {
+ result= count_internal(cur_func, next_func, &cur_func);
+ goto exit;
+ }
+
+ if (next_func == op_repeat)
+ {
+ result= count_internal(function_buffer.ptr() + n_ops, set_type, 0);
+ goto exit;
+ }
+
if (n_ops == 0)
return mask;
- result= count_internal();
+ result= count_internal(cur_func, set_type, &cur_func);
while (--n_ops)
{
- int next_res= count_internal();
+ int next_res= count_internal(cur_func, set_type, &cur_func);
switch (next_func)
{
case op_union:
@@ -159,15 +187,59 @@ int Gcalc_function::count_internal()
case op_difference:
result= result & !next_res;
break;
- case op_backdifference:
- result= !result & next_res;
- break;
default:
DBUG_ASSERT(FALSE);
};
}
- return result ^ mask;
+exit:
+ result^= mask;
+ if (v_state != v_empty)
+ {
+ switch (v_state)
+ {
+ case v_find_t:
+ if (result)
+ {
+ c_op= (c_op & ~v_mask) | v_t_found;
+ int4store(sav_cur_func, c_op);
+ };
+ break;
+ case v_find_f:
+ if (!result)
+ {
+ c_op= (c_op & ~v_mask) | v_f_found;
+ int4store(sav_cur_func, c_op);
+ };
+ break;
+ case v_t_found:
+ result= 1;
+ break;
+ case v_f_found:
+ result= 0;
+ break;
+ default:
+ DBUG_ASSERT(0);
+ };
+ }
+
+ if (end)
+ *end= cur_func;
+ return result;
+}
+
+
+void Gcalc_function::clear_i_states()
+{
+ for (uint i= 0; i < n_shapes; i++)
+ i_states[i]= 0;
+}
+
+
+void Gcalc_function::clear_b_states()
+{
+ for (uint i= 0; i < n_shapes; i++)
+ b_states[i]= 0;
}
@@ -183,7 +255,7 @@ void Gcalc_function::reset()
}
-int Gcalc_function::find_function(Gcalc_scan_iterator &scan_it)
+int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it)
{
const Gcalc_scan_iterator::point *eq_start, *cur_eq, *events;
@@ -194,31 +266,58 @@ int Gcalc_function::find_function(Gcalc_scan_iterator &scan_it)
events= scan_it.get_events();
/* these kinds of events don't change the function */
- if (events->simple_event())
- continue;
-
Gcalc_point_iterator pit(&scan_it);
- clear_state();
+ clear_b_states();
+ clear_i_states();
/* Walk to the event, marking polygons we met */
for (; pit.point() != scan_it.get_event_position(); ++pit)
{
gcalc_shape_info si= pit.point()->get_shape();
if ((get_shape_kind(si) == Gcalc_function::shape_polygon))
- invert_state(si);
+ invert_i_state(si);
}
- save_states();
+ if (events->simple_event())
+ {
+ if (events->event == scev_end)
+ set_b_state(events->get_shape());
+
+ if (count())
+ return 1;
+ clear_b_states();
+ continue;
+ }
+
/* Check the status of the event point */
for (; events; events= events->get_next())
- set_on_state(events->get_shape());
+ {
+ gcalc_shape_info si= events->get_shape();
+ if (events->event == scev_thread ||
+ events->event == scev_end ||
+ (get_shape_kind(si) == Gcalc_function::shape_polygon))
+ set_b_state(si);
+ else if (get_shape_kind(si) == Gcalc_function::shape_line)
+ invert_i_state(si);
+ }
if (count())
return 1;
+ /* Set back states changed in the loop above. */
+ for (events= scan_it.get_events(); events; events= events->get_next())
+ {
+ gcalc_shape_info si= events->get_shape();
+ if (events->event == scev_thread ||
+ events->event == scev_end ||
+ (get_shape_kind(si) == Gcalc_function::shape_polygon))
+ clear_b_state(si);
+ else if (get_shape_kind(si) == Gcalc_function::shape_line)
+ invert_i_state(si);
+ }
+
if (scan_it.get_event_position() == scan_it.get_event_end())
continue;
/* Check the status after the event */
- restore_states();
eq_start= pit.point();
do
{
@@ -226,18 +325,28 @@ int Gcalc_function::find_function(Gcalc_scan_iterator &scan_it)
if (pit.point() != scan_it.get_event_end() &&
eq_start->cmp_dx_dy(pit.point()) == 0)
continue;
- save_states();
for (cur_eq= eq_start; cur_eq != pit.point();
cur_eq= cur_eq->get_next())
- set_on_state(cur_eq->get_shape());
+ {
+ gcalc_shape_info si= cur_eq->get_shape();
+ if (get_shape_kind(si) == Gcalc_function::shape_polygon)
+ set_b_state(si);
+ else
+ invert_i_state(si);
+ }
if (count())
return 1;
- restore_states();
+
for (cur_eq= eq_start; cur_eq != pit.point(); cur_eq= cur_eq->get_next())
{
gcalc_shape_info si= cur_eq->get_shape();
if ((get_shape_kind(si) == Gcalc_function::shape_polygon))
- invert_state(si);
+ {
+ clear_b_state(si);
+ invert_i_state(si);
+ }
+ else
+ invert_i_state(cur_eq->get_shape());
}
if (count())
return 1;
@@ -313,6 +422,15 @@ int Gcalc_operation_transporter::start_collection(int n_objects)
}
+int Gcalc_operation_transporter::empty_shape()
+{
+ if (m_fn->reserve_op_buffer(1))
+ return 1;
+ m_fn->add_operation(Gcalc_function::op_false, 0);
+ return 0;
+}
+
+
int Gcalc_result_receiver::start_shape(Gcalc_function::shape_type shape)
{
if (buffer.reserve(4*2, 512))
@@ -661,7 +779,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si)
if (ca_counter == 11522)
call_checkpoint(89);
#endif /*NO_TESTING*/
- m_fn->clear_state();
+ m_fn->clear_i_states();
/* Walk to the event, remembering what is needed. */
#ifndef NO_TESTING
if (si->get_event_position() == pi.point())
@@ -678,7 +796,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si)
prev_range= prev_state ? cur_t : 0;
}
if (m_fn->get_shape_kind(pi.get_shape()) == Gcalc_function::shape_polygon)
- m_fn->invert_state(pi.get_shape());
+ m_fn->invert_i_state(pi.get_shape());
}
events= si->get_events();
@@ -800,6 +918,7 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si)
eq_start= pi.point();
eq_thread= point_thread= *starting_t_hook;
+ m_fn->clear_b_states();
while (eq_start != si->get_event_end())
{
const Gcalc_scan_iterator::point *cur_eq;
@@ -812,17 +931,16 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si)
eq_start->cmp_dx_dy(pi.point()) == 0)
continue;
- m_fn->save_states();
for (cur_eq= eq_start; cur_eq != pi.point(); cur_eq= cur_eq->get_next())
- m_fn->set_on_state(cur_eq->get_shape());
+ m_fn->set_b_state(cur_eq->get_shape());
in_state= m_fn->count();
- m_fn->restore_states();
+ m_fn->clear_b_states();
for (cur_eq= eq_start; cur_eq != pi.point(); cur_eq= cur_eq->get_next())
{
gcalc_shape_info si= cur_eq->get_shape();
if ((m_fn->get_shape_kind(si) == Gcalc_function::shape_polygon))
- m_fn->invert_state(si);
+ m_fn->invert_i_state(si);
}
after_state= m_fn->count();
if (prev_state != after_state)
@@ -844,14 +962,15 @@ int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si)
if (!sav_prev_state && !m_poly_borders && !m_lines)
{
/* Check if we need to add the event point itself */
- m_fn->clear_state();
+ m_fn->clear_i_states();
+ /* b_states supposed to be clean already */
for (pi.restart(si); pi.point() != si->get_event_position(); ++pi)
{
if (m_fn->get_shape_kind(pi.get_shape()) == Gcalc_function::shape_polygon)
- m_fn->invert_state(pi.get_shape());
+ m_fn->invert_i_state(pi.get_shape());
}
for (events= si->get_events(); events; events= events->get_next())
- m_fn->set_on_state(events->get_shape());
+ m_fn->set_b_state(events->get_shape());
return m_fn->count() ? add_single_point(si) : 0;
}
diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h
index 39704dfeb56..5e98d46a90f 100644
--- a/sql/gcalc_tools.h
+++ b/sql/gcalc_tools.h
@@ -43,23 +43,35 @@ class Gcalc_function
private:
String shapes_buffer;
String function_buffer;
- const char *cur_func;
int *i_states;
- int *saved_i_states;
+ int *b_states;
uint32 cur_object_id;
uint n_shapes;
- int count_internal();
+ int count_internal(const char *cur_func, uint set_type,
+ const char **end);
public:
+ enum value
+ {
+ v_empty= 0x0000000,
+ v_find_t= 0x1000000,
+ v_find_f= 0x2000000,
+ v_t_found= 0x3000000,
+ v_f_found= 0x4000000,
+ v_mask= 0x7000000
+ };
enum op_type
{
- op_shape= 0,
- op_not= 0x80000000,
- op_union= 0x10000000,
- op_intersection= 0x20000000,
+ op_not= 0x80000000,
+ op_shape= 0x00000000,
+ op_union= 0x10000000,
+ op_intersection= 0x20000000,
op_symdifference= 0x30000000,
- op_difference= 0x40000000,
- op_backdifference= 0x50000000,
- op_any= 0x70000000
+ op_difference= 0x40000000,
+ op_repeat= 0x50000000,
+ op_border= 0x60000000,
+ op_internals= 0x70000000,
+ op_false= 0x08000000,
+ op_any= 0x78000000 /* The mask to get any of the operations */
};
enum shape_type
{
@@ -75,10 +87,11 @@ public:
Also adds the shape to the list of operands.
*/
int single_shape_op(shape_type shape_kind, gcalc_shape_info *si);
- void add_operation(op_type operation, uint32 n_operands);
+ void add_operation(uint operation, uint32 n_operands);
void add_not_operation(op_type operation, uint32 n_operands);
- uint32 get_next_operation_pos() { return function_buffer.length(); }
+ uint32 get_next_expression_pos() { return function_buffer.length(); }
void add_operands_to_op(uint32 operation_pos, uint32 n_operands);
+ int repeat_expression(uint32 exp_pos);
void set_cur_obj(uint32 cur_obj) { cur_object_id= cur_obj; }
int reserve_shape_buffer(uint n_shapes);
int reserve_op_buffer(uint n_ops);
@@ -90,20 +103,20 @@ public:
void set_states(int *shape_states) { i_states= shape_states; }
int alloc_states();
- void invert_state(gcalc_shape_info shape) { i_states[shape]^= 1; }
- void set_on_state(gcalc_shape_info shape) { i_states[shape]= 1; }
- int get_state(gcalc_shape_info shape) { return i_states[shape]; }
- void save_states();
- void restore_states();
+ void invert_i_state(gcalc_shape_info shape) { i_states[shape]^= 1; }
+ void set_b_state(gcalc_shape_info shape) { b_states[shape]= 1; }
+ void clear_b_state(gcalc_shape_info shape) { b_states[shape]= 0; }
+ int get_state(gcalc_shape_info shape)
+ { return i_states[shape] | b_states[shape]; }
+ int get_i_state(gcalc_shape_info shape) { return i_states[shape]; }
+ int get_b_state(gcalc_shape_info shape) { return b_states[shape]; }
int count()
- {
- cur_func= function_buffer.ptr();
- return count_internal();
- }
- void clear_state() { bzero(i_states, n_shapes * sizeof(int)); }
+ { return count_internal(function_buffer.ptr(), 0, 0); }
+ void clear_i_states();
+ void clear_b_states();
void reset();
- int find_function(Gcalc_scan_iterator &scan_it);
+ int check_function(Gcalc_scan_iterator &scan_it);
};
@@ -132,6 +145,7 @@ public:
int complete_ring();
int add_point(double x, double y);
int start_collection(int n_objects);
+ int empty_shape();
};
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 2a8f7eec52a..626f0c5d91e 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -5144,7 +5144,7 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("ENCRYPT") }, BUILDER(Create_func_encrypt)},
{ { C_STRING_WITH_LEN("ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
{ { C_STRING_WITH_LEN("ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
- { { C_STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_mbr_equals)},
+ { { C_STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_equals)},
{ { C_STRING_WITH_LEN("EXP") }, BUILDER(Create_func_exp)},
{ { C_STRING_WITH_LEN("EXPORT_SET") }, BUILDER(Create_func_export_set)},
{ { C_STRING_WITH_LEN("EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
@@ -5283,7 +5283,7 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("ST_DISTANCE") }, GEOM_BUILDER(Create_func_distance)},
{ { C_STRING_WITH_LEN("ST_ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
{ { C_STRING_WITH_LEN("ST_ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
- { { C_STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_mbr_equals)},
+ { { C_STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_equals)},
{ { C_STRING_WITH_LEN("ST_EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
{ { C_STRING_WITH_LEN("ST_GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("ST_GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
@@ -5323,7 +5323,7 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("ST_SYMDIFFERENCE") }, GEOM_BUILDER(Create_func_symdifference)},
{ { C_STRING_WITH_LEN("ST_TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
{ { C_STRING_WITH_LEN("ST_UNION") }, GEOM_BUILDER(Create_func_union)},
- { { C_STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_mbr_within)},
+ { { C_STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_within)},
{ { C_STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)},
{ { C_STRING_WITH_LEN("ST_Y") }, GEOM_BUILDER(Create_func_y)},
{ { C_STRING_WITH_LEN("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)},
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index e490643f88b..4db8ee02d7f 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -660,6 +660,7 @@ static double distance_points(const Gcalc_heap::Info *a,
Calculates the distance between objects.
*/
+#ifdef TMP_BLOCK
static int calc_distance(double *result, Gcalc_heap *collector, uint obj2_si,
Gcalc_function *func, Gcalc_scan_iterator *scan_it)
{
@@ -786,139 +787,11 @@ exit:
mem_error:
DBUG_RETURN(1);
}
+#endif /*TMP_BLOCK*/
#define GIS_ZERO 0.00000000001
-int Item_func_spatial_rel::func_touches()
-{
- bool above_cur_point;
- double x1, x2, y1, y2, ex, ey;
- double distance, area;
- int result= 0;
- int cur_func= 0;
-
- Gcalc_operation_transporter trn(&func, &collector);
-
- String *res1= args[0]->val_str(&tmp_value1);
- String *res2= args[1]->val_str(&tmp_value2);
- Geometry_buffer buffer1, buffer2;
- Geometry *g1, *g2;
- int obj2_si;
-
- DBUG_ENTER("Item_func_spatial_rel::func_touches");
- DBUG_ASSERT(fixed == 1);
-
- 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())))))
- goto mem_error;
-
- 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((ex * ex + ey * ey) < GIS_ZERO);
- }
-
- 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;
-
- collector.prepare_operation();
- scan_it.init(&collector);
-
- if (calc_distance(&distance, &collector, obj2_si, &func, &scan_it))
- goto mem_error;
- if (distance > GIS_ZERO)
- goto exit;
-
- scan_it.reset();
- scan_it.init(&collector);
-
- above_cur_point= false;
- distance= DBL_MAX;
-
- while (scan_it.more_trapezoids())
- {
- if (scan_it.step())
- goto mem_error;
-
- func.clear_state();
- for (Gcalc_trapezoid_iterator ti(&scan_it); ti.more(); ++ti)
- {
- gcalc_shape_info si= ti.lb()->get_shape();
- if ((func.get_shape_kind(si) == Gcalc_function::shape_polygon))
- {
- func.invert_state(si);
- cur_func= func.count();
- }
- if (cur_func)
- {
- area= scan_it.get_h() *
- ((scan_it.get_sp_x(ti.rb()) - scan_it.get_sp_x(ti.lb())) +
- (scan_it.get_sp_x(ti.rt()) - scan_it.get_sp_x(ti.lt())));
- if (area > GIS_ZERO)
- {
- result= 0;
- goto exit;
- }
- }
- }
- }
- result= 1;
-
-exit:
- collector.reset();
- func.reset();
- scan_it.reset();
- DBUG_RETURN(result);
-mem_error:
- null_value= 1;
- DBUG_RETURN(0);
-}
-
-
-int Item_func_spatial_rel::func_equals()
-{
- Gcalc_heap::Info *pi_s1, *pi_s2;
- Gcalc_heap::Info *cur_pi= collector.get_first();
- double d;
-
- if (!cur_pi)
- return 1;
-
- do {
- pi_s1= cur_pi;
- pi_s2= 0;
- while ((cur_pi= cur_pi->get_next()))
- {
- d= fabs(pi_s1->x - cur_pi->x) + fabs(pi_s1->y - cur_pi->y);
- if (d > GIS_ZERO)
- break;
- if (!pi_s2 && pi_s1->shape != cur_pi->shape)
- pi_s2= cur_pi;
- }
-
- if (!pi_s2)
- return 0;
- } while (cur_pi);
-
- return 1;
-}
-
-
longlong Item_func_spatial_rel::val_int()
{
DBUG_ENTER("Item_func_spatial_rel::val_int");
@@ -929,9 +802,7 @@ longlong Item_func_spatial_rel::val_int()
Geometry *g1, *g2;
int result= 0;
int mask= 0;
-
- if (spatial_rel == SP_TOUCHES_FUNC)
- DBUG_RETURN(func_touches());
+ uint shape_a, shape_b;
res1= args[0]->val_str(&tmp_value1);
res2= args[1]->val_str(&tmp_value2);
@@ -940,56 +811,103 @@ longlong Item_func_spatial_rel::val_int()
if (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())))))
+ goto exit;
+
switch (spatial_rel) {
case SP_CONTAINS_FUNC:
mask= 1;
- func.add_operation(Gcalc_function::op_backdifference, 2);
+ func.add_operation(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:
mask= 1;
func.add_operation(Gcalc_function::op_difference, 2);
+ null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn);
break;
case SP_EQUALS_FUNC:
+ mask= 1;
+ func.add_operation(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);
break;
case SP_INTERSECTS_FUNC:
func.add_operation(Gcalc_function::op_intersection, 2);
+ null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn);
break;
case SP_OVERLAPS_FUNC:
- func.add_operation(Gcalc_function::op_backdifference, 2);
- break;
case SP_CROSSES_FUNC:
func.add_operation(Gcalc_function::op_intersection, 2);
+ 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;
+ func.add_operation(Gcalc_function::v_find_t |
+ 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:
+ 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)))
+ break;
+ func.add_operation(Gcalc_function::op_internals, 1);
+ shape_b= func.get_next_expression_pos();
+ 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;
default:
DBUG_ASSERT(FALSE);
break;
}
-
- 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->store_shapes(&trn) || g2->store_shapes(&trn))))
+ if (null_value)
goto exit;
collector.prepare_operation();
scan_it.init(&collector);
+#ifdef TMP_BLOCK
if (spatial_rel == SP_EQUALS_FUNC)
{
result= (g1->get_class_info()->m_type_id == g1->get_class_info()->m_type_id) &&
func_equals();
goto exit;
}
+#endif /*TMP_BLOCK*/
if (func.alloc_states())
goto exit;
- result= func.find_function(scan_it) ^ mask;
+ result= func.check_function(scan_it) ^ mask;
exit:
collector.reset();
@@ -1307,7 +1225,7 @@ int Item_func_buffer::Transporter::start_line()
if (m_fn->reserve_op_buffer(2))
return 1;
- last_shape_pos= m_fn->get_next_operation_pos();
+ last_shape_pos= m_fn->get_next_expression_pos();
m_fn->add_operation(buffer_op, 0);
m_npoints= 0;
int_start_line();
@@ -1321,7 +1239,7 @@ int Item_func_buffer::Transporter::start_poly()
if (m_fn->reserve_op_buffer(2))
return 1;
- last_shape_pos= m_fn->get_next_operation_pos();
+ last_shape_pos= m_fn->get_next_expression_pos();
m_fn->add_operation(buffer_op, 0);
return Gcalc_operation_transporter::start_poly();
}
@@ -1827,19 +1745,20 @@ double Item_func_distance::val_real()
of objects
scev_thread | scev_two_threads | scev_single_point
*/
- func.clear_state();
+ 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_state(si);
+ 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_on_state(ev->get_shape());
+ func.set_b_state(ev->get_shape());
if (func.count())
{
/* Point of one object is inside the other - intersection found */
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index d5ed2c1f764..b4e495f39a8 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -251,9 +251,6 @@ public:
void fix_length_and_dec() { maybe_null= 1; }
bool is_null() { (void) val_int(); return null_value; }
-protected:
- int func_touches();
- int func_equals();
};
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 15dc42441a8..d18600dd7de 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -2519,6 +2519,12 @@ int Gis_geometry_collection::store_shapes(Gcalc_shape_transporter *trn) const
n_objects= uint4korr(data);
data+= 4;
+ if (!n_objects)
+ {
+ trn->empty_shape();
+ return 0;
+ }
+
if (trn->start_collection(n_objects))
return 1;