From fc9d34cabf06038f930db356d53ed76dab5fdf0d Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 8 Dec 2011 16:29:45 +0400 Subject: bug #901655 ST_BUFFER asserts with a coplicated shape. Coinciding nodes can appear as a result of DOUBLE inaccuracy. We should test that before we start the loop. Also the spatial relations can be calculated faster if we check MBR relations first. And we do have the shape's MBR-s now. per-file comments: sql/gcalc_slicescan.cc set_extent() method added. bug #901655 ST_BUFFER asserts with a coplicated shape. sql/gcalc_slicescan.h set_extent() method declared. bug #901655 ST_BUFFER asserts with a coplicated shape. sql/gcalc_tools.cc bug #901655 ST_BUFFER asserts with a coplicated shape. checks for equal nodes added. sql/item_geofunc.cc bug #901655 ST_BUFFER asserts with a coplicated shape. MBR for the shapes calculated, and MBR checks added before we start the heavy calculations. sql/spatial.h bug #901655 ST_BUFFER asserts with a coplicated shape. MBR::buffer() method implemented. --- sql/gcalc_slicescan.cc | 106 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 37 deletions(-) (limited to 'sql/gcalc_slicescan.cc') diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 7021902ffb7..3c02bf62e53 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -406,7 +406,7 @@ static int de_weak_check(long double a, long double b, long double ex) static int de_check(long double a, long double b) { - return de_weak_check(a, b, (long double) 1e-10); + return de_weak_check(a, b, (long double) 1e-9); } #endif /*GCALC_CHECK_WITH_FLOAT*/ @@ -792,10 +792,51 @@ static int cmp_intersections(const Gcalc_heap::Info *i1, /* Internal coordinates implementation end */ +#define GCALC_SCALE_1 1e18 + +static double find_scale(double extent) +{ + double scale= 1e-2; + while (scale < extent) + scale*= (double ) 10; + return GCALC_SCALE_1 / scale / 10; +} + + +void Gcalc_heap::set_extent(double xmin, double xmax, double ymin, double ymax) +{ + xmin= fabs(xmin); + xmax= fabs(xmax); + ymin= fabs(ymin); + ymax= fabs(ymax); + + if (xmax < xmin) + xmax= xmin; + if (ymax < ymin) + ymax= ymin; + + coord_extent= xmax > ymax ? xmax : ymax; + coord_extent= find_scale(coord_extent); +#ifdef GCALC_CHECK_WITH_FLOAT + gcalc_coord_extent= &coord_extent; +#endif /*GCALC_CHECK_WITH_FLOAT*/ +} + + +void Gcalc_heap::free_point_info(Gcalc_heap::Info *i, + Gcalc_dyn_list::Item **i_hook) +{ + if (m_hook == &i->next) + m_hook= i_hook; + *i_hook= i->next; + free_item(i); + m_n_points--; +} + + Gcalc_heap::Info *Gcalc_heap::new_point_info(double x, double y, gcalc_shape_info shape) { - double abs= fabs(x); Info *result= (Info *)new_item(); if (!result) return NULL; @@ -806,17 +847,8 @@ Gcalc_heap::Info *Gcalc_heap::new_point_info(double x, double y, result->shape= shape; result->top_node= 1; result->type= nt_shape_node; - if (m_n_points) - { - if (abs > coord_extent) - coord_extent= abs; - } - else - coord_extent= abs; - - abs= fabs(y); - if (abs > coord_extent) - coord_extent= abs; + gcalc_set_double(result->ix, x, coord_extent); + gcalc_set_double(result->iy, y, coord_extent); m_n_points++; return result; @@ -927,32 +959,12 @@ static int compare_point_info(const void *e0, const void *e1) } -#define GCALC_SCALE_1 1e18 - -static double find_scale(double extent) -{ - double scale= 1e-2; - while (scale < extent) - scale*= (double ) 10; - return GCALC_SCALE_1 / scale / 10; -} - - void Gcalc_heap::prepare_operation() { Info *cur; GCALC_DBUG_ASSERT(m_hook); - coord_extent= find_scale(coord_extent); -#ifdef GCALC_CHECK_WITH_FLOAT - gcalc_coord_extent= &coord_extent; -#endif /*GCALC_CHECK_WITH_FLOAT*/ *m_hook= NULL; m_hook= NULL; /* just to check it's not called twice */ - for (cur= get_first(); cur; cur= cur->get_next()) - { - gcalc_set_double(cur->ix, cur->x, coord_extent); - gcalc_set_double(cur->iy, cur->y, coord_extent); - } m_first= sort_list(compare_point_info, m_first, m_n_points); /* TODO - move this to the 'normal_scan' loop */ @@ -990,18 +1002,28 @@ int Gcalc_shape_transporter::int_add_point(gcalc_shape_info Info, double x, double y) { Gcalc_heap::Info *point; - GCALC_DBUG_ASSERT(!m_prev || m_prev->x != x || m_prev->y != y); + Gcalc_dyn_list::Item **hook; + + hook= m_heap->get_cur_hook(); if (!(point= m_heap->new_point_info(x, y, Info))) return 1; if (m_first) { + if (cmp_point_info(m_prev, point) == 0) + { + /* Coinciding points, do nothing */ + m_heap->free_point_info(point, hook); + return 0; + } + GCALC_DBUG_ASSERT(!m_prev || m_prev->x != x || m_prev->y != y); m_prev->left= point; point->right= m_prev; } else m_first= point; m_prev= point; + m_prev_hook= hook; return 0; } @@ -1029,10 +1051,20 @@ void Gcalc_shape_transporter::int_complete() return; } - GCALC_DBUG_ASSERT(m_prev->x != m_first->x || m_prev->y != m_first->y); /* polygon */ - m_first->right= m_prev; - m_prev->left= m_first; + if (cmp_point_info(m_first, m_prev) == 0) + { + /* Coinciding points, remove the last one from the list */ + m_prev->right->left= m_first; + m_first->right= m_prev->right; + m_heap->free_point_info(m_prev, m_prev_hook); + } + else + { + GCALC_DBUG_ASSERT(m_prev->x != m_first->x || m_prev->y != m_first->y); + m_first->right= m_prev; + m_prev->left= m_first; + } } -- cgit v1.2.1 From 56125a3bceb7a375610d4f4c04c9465fa324d516 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 16 Dec 2011 10:21:46 +0400 Subject: GIS issues fixed. Failures on SUN Solaris. Buggy compiler there required some extra initialization for variables. Then the 02 optimization leads to bugs when values set through the pointer are not always taken into account. Finally, the (long long) / (long) crashes there, the explicit typeconverstion added. Failing innodb_plunin.innodb_gis.test fixed. per-file comments: mysql-test/suite/innodb_plugin/t/innodb_gis.test GIS issues fixed. sql/gcalc_slicescan.cc GIS issues fixed. sql/gcalc_tools.cc GIS issues fixed. --- sql/gcalc_slicescan.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/gcalc_slicescan.cc') diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 3c02bf62e53..9e88f0a00ad 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -432,7 +432,7 @@ void gcalc_mul_coord(Gcalc_internal_coord *result, int result_len, gcalc_coord2 cur_b= n_b ? b[n_b] : FIRST_DIGIT(b[0]); gcalc_coord2 mul= cur_a * cur_b + carry + result[n_a + n_b + 1]; result[n_a + n_b + 1]= mul % GCALC_DIG_BASE; - carry= (gcalc_digit_t) (mul / GCALC_DIG_BASE); + carry= (gcalc_digit_t) (mul / (gcalc_coord2) GCALC_DIG_BASE); } while (n_b--); if (carry) { -- cgit v1.2.1