summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Botchkov <holyfoot@askmonty.org>2011-07-05 19:42:35 +0500
committerAlexey Botchkov <holyfoot@askmonty.org>2011-07-05 19:42:35 +0500
commitf3b850a7b52b5947eb694b5a1f73d0425de5bb0e (patch)
tree8a211b1bb2d3b9502b2bb05309285832c6a9d8a8
parent7f55ea121191131723c99889943f8a278c5a7b4b (diff)
downloadmariadb-git-f3b850a7b52b5947eb694b5a1f73d0425de5bb0e.tar.gz
bug #804305 Crash in wkb_get_double with ST_INTERSECTION.
That crash happened with the complicated topology of the result. If we found a hole in a polygon whose outside border was already found, we need to paste the hole right after it and respectively shift polygons after it. Also we need to update poly_position fields in these polygons. That last thing wasn't properly done that led to the crash. To fix that we keep the list of the found polygons and update the poly_positions that are bigger or equal to where we placed the next hole. per-file comments: mysql-test/r/gis-precise.result bug #804305 Crash in wkb_get_double with ST_INTERSECTION. test result updated. mysql-test/t/gis-precise.test bug #804305 Crash in wkb_get_double with ST_INTERSECTION. test result added. sql/gcalc_tools.cc bug #804305 Crash in wkb_get_double with ST_INTERSECTION. keep the list of the found polygons and update their poly_position fields respectively. sql/gcalc_tools.h bug #804305 Crash in wkb_get_double with ST_INTERSECTION. Gcalc_result_receiver::move_hole interface changed.
-rw-r--r--mysql-test/r/gis-precise.result14
-rw-r--r--mysql-test/t/gis-precise.test9
-rw-r--r--sql/gcalc_tools.cc31
-rw-r--r--sql/gcalc_tools.h11
4 files changed, 53 insertions, 12 deletions
diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result
index 4f07333e6a3..75028e484dd 100644
--- a/mysql-test/r/gis-precise.result
+++ b/mysql-test/r/gis-precise.result
@@ -218,3 +218,17 @@ Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'),
SELECT ST_INTERSECTION(NULL, NULL);
ST_INTERSECTION(NULL, NULL)
NULL
+SELECT ASTEXT(ST_INTERSECTION(
+MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((2 2,2 8,8 8,8 2,2 2),(4 4,4 6,6 6,6 4,4 4)),
+ ((0 5,3 5,3 0,0 0,0 1,2 1,2 2,0 2,0 5), (1 3,2 3,2 4,1 4,1 3)),
+ ((2 2,5 2,4 4,2 8,2 2)))'),
+MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((3 5,2 4,2 5,3 5)),
+ ((2 2,9 2,0 2,2 6,2 2)),
+ ((2 2,2 8,8 8,8 2,2 2), (4 4,4 6,6 6,6 4,4 4)),
+ ((9 9,6 8,7 0,9 9)))')));
+ASTEXT(ST_INTERSECTION(
+MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((2 2,2 8,8 8,8 2,2 2),(4 4,4 6,6 6,6 4,4 4)),
+ ((0 5,3 5,3 0,0 0,0 1,2 1,2 2,0 2,0 5), (1 3,2 3,2 4,1 4,1 3)),
+ ((2 2,5 2,4 4,2 8,2 2)))'),
+MULTIPOLY
+MULTIPOLYGON(((2 2,3 2,2 2)),((5 2,0 2,5 2)),((2 2,0 2,1.5 5,2 5,2 2),(1 3,1 4,2 4,2 3,1 3)),((2 2,2 8,8 8,8 2,5 2,2 2),(6 4,4 4,4 6,6 6,6 4)))
diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test
index 72ba6b748be..87b56dc0040 100644
--- a/mysql-test/t/gis-precise.test
+++ b/mysql-test/t/gis-precise.test
@@ -121,3 +121,12 @@ SELECT Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7
#bug 801212 Assertion with ST_INTERSECTION on NULL values
SELECT ST_INTERSECTION(NULL, NULL);
+#bug 804305 Crash in wkb_get_double with ST_INTERSECTION
+SELECT ASTEXT(ST_INTERSECTION(
+ MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((2 2,2 8,8 8,8 2,2 2),(4 4,4 6,6 6,6 4,4 4)),
+ ((0 5,3 5,3 0,0 0,0 1,2 1,2 2,0 2,0 5), (1 3,2 3,2 4,1 4,1 3)),
+ ((2 2,5 2,4 4,2 8,2 2)))'),
+ MULTIPOLYGONFROMTEXT('MULTIPOLYGON(((3 5,2 4,2 5,3 5)),
+ ((2 2,9 2,0 2,2 6,2 2)),
+ ((2 2,2 8,8 8,8 2,2 2), (4 4,4 6,6 6,6 4,4 4)),
+ ((9 9,6 8,7 0,9 9)))')));
diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc
index 0e2970116ce..11d452cd8cf 100644
--- a/sql/gcalc_tools.cc
+++ b/sql/gcalc_tools.cc
@@ -419,17 +419,16 @@ int Gcalc_result_receiver::get_result_typeid()
int Gcalc_result_receiver::move_hole(uint32 dest_position, uint32 source_position,
- uint32 *new_dest_position)
+ uint32 *position_shift)
{
char *ptr;
int source_len;
+
+ *position_shift= source_len= buffer.length() - source_position;
+
if (dest_position == source_position)
- {
- *new_dest_position= position();
return 0;
- }
- source_len= buffer.length() - source_position;
if (buffer.reserve(source_len, MY_ALIGN(source_len, 512)))
return 1;
@@ -437,7 +436,6 @@ int Gcalc_result_receiver::move_hole(uint32 dest_position, uint32 source_positio
memmove(ptr + dest_position + source_len, ptr + dest_position,
buffer.length() - dest_position);
memcpy(ptr + dest_position, ptr + buffer.length(), source_len);
- *new_dest_position= dest_position + source_len;
return 0;
}
@@ -1098,6 +1096,8 @@ int Gcalc_operation_reducer::get_line_result(res_point *cur,
int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage)
{
+ poly_instance *polygons= NULL;
+
*m_res_hook= NULL;
while (m_result)
{
@@ -1112,19 +1112,28 @@ int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage)
{
if (m_result->outer_poly)
{
- uint32 *insert_position, hole_position;
- insert_position= &m_result->outer_poly->first_poly_node->poly_position;
- DBUG_ASSERT(*insert_position);
+ uint32 insert_position, hole_position, position_shift;
+ poly_instance *cur_poly;
+ insert_position= m_result->outer_poly->first_poly_node->poly_position;
+ DBUG_ASSERT(insert_position);
hole_position= storage->position();
storage->start_shape(Gcalc_function::shape_hole);
if (get_polygon_result(m_result, storage) ||
- storage->move_hole(*insert_position, hole_position,
- insert_position))
+ storage->move_hole(insert_position, hole_position,
+ &position_shift))
return 1;
+ for (cur_poly= polygons;
+ cur_poly && *cur_poly->after_poly_position >= insert_position;
+ cur_poly= cur_poly->get_next())
+ *cur_poly->after_poly_position+= position_shift;
}
else
{
uint32 *poly_position= &m_result->poly_position;
+ poly_instance *p= new_poly();
+ p->after_poly_position= poly_position;
+ p->next= polygons;
+ polygons= p;
storage->start_shape(Gcalc_function::shape_polygon);
if (get_polygon_result(m_result, storage))
return 1;
diff --git a/sql/gcalc_tools.h b/sql/gcalc_tools.h
index 7df236618fb..32835d68666 100644
--- a/sql/gcalc_tools.h
+++ b/sql/gcalc_tools.h
@@ -170,7 +170,7 @@ public:
int get_result_typeid();
uint32 position() { return buffer.length(); }
int move_hole(uint32 dest_position, uint32 source_position,
- uint32 *new_dest_position);
+ uint32 *position_shift);
};
@@ -233,6 +233,13 @@ public:
active_thread *get_next() { return (active_thread *)next; }
};
+ class poly_instance : public Gcalc_dyn_list::Item
+ {
+ public:
+ uint32 *after_poly_position;
+ poly_instance *get_next() { return (poly_instance *)next; }
+ };
+
protected:
Gcalc_function *m_fn;
Gcalc_dyn_list::Item **m_res_hook;
@@ -253,6 +260,8 @@ protected:
active_thread *new_active_thread() { return (active_thread *)new_item(); }
+ poly_instance *new_poly() { return (poly_instance *) new_item(); }
+
private:
int continue_range(active_thread *t, const Gcalc_heap::Info *p);
int continue_i_range(active_thread *t, const Gcalc_heap::Info *p,