summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Botchkov <holyfoot@askmonty.org>2011-07-04 16:03:36 +0500
committerAlexey Botchkov <holyfoot@askmonty.org>2011-07-04 16:03:36 +0500
commit0e6c889c83bcf6c37526e3a3fee192bb59cab92e (patch)
treedf83f696c25331e8fe04874a9a22ebe3483a96fd
parenta9a6597d598c735ba6b8a136864b888d8d626b70 (diff)
downloadmariadb-git-0e6c889c83bcf6c37526e3a3fee192bb59cab92e.tar.gz
bug #801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT
Collections were treated mistakenly, so the counter for the final UNION operation received the wrong value. As a fix we implement Item_func_buffer::Transporter::start_collection() method, where we set the proper operation and the operand counter. start_poly() and start_line() were also modified to function correctly for the polygon as a part of a collection. per-file comments: mysql-test/r/gis-precise.result bug #801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT test result updated. mysql-test/t/gis-precise.test bug #801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT test case added. sql/item_geofunc.cc bug #801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT start_collection() implemented. sql/item_geofunc.h bug #801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT Item_func_buffer::Transporter::start_collection() defined.
-rw-r--r--mysql-test/r/gis-precise.result3
-rw-r--r--mysql-test/t/gis-precise.test3
-rw-r--r--sql/item_geofunc.cc60
-rw-r--r--sql/item_geofunc.h15
4 files changed, 66 insertions, 15 deletions
diff --git a/mysql-test/r/gis-precise.result b/mysql-test/r/gis-precise.result
index 48c00c4a468..e4cc9028236 100644
--- a/mysql-test/r/gis-precise.result
+++ b/mysql-test/r/gis-precise.result
@@ -212,3 +212,6 @@ GEOMETRYCOLLECTION(POLYGON((0 0,1 9,8 2,0 0),(2 2,2 7,3 2,2 2)),LINESTRING(0 0,5
SELECT astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0));
astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0))
LINESTRING(0 0,1 1)
+SELECT Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5);
+Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5)
+78.68426
diff --git a/mysql-test/t/gis-precise.test b/mysql-test/t/gis-precise.test
index e75316a0805..e267bcf57c1 100644
--- a/mysql-test/t/gis-precise.test
+++ b/mysql-test/t/gis-precise.test
@@ -114,3 +114,6 @@ SELECT astext(ST_UNION (
#bug 801189 ST_BUFFER asserts if radius = 0
SELECT astext(ST_BUFFER(LineStringFromText('LINESTRING(0 0,1 1)'),0));
+
+#buf 801199 Infinite recursion in Gcalc_function::count_internal with ST_BUFFER over MULTIPOINT
+SELECT Round(ST_Area(ST_BUFFER(MultipointFromText('MULTIPOINT(7 7,3 7,7 2,7 4 ,7 7)'), 3)), 5);
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index f65df790dfb..8cae6dd6564 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -1284,6 +1284,18 @@ int Item_func_buffer::Transporter::add_point_buffer(double x, double y)
int Item_func_buffer::Transporter::start_line()
{
+ if (buffer_op == Gcalc_function::op_difference)
+ {
+ skip_line= TRUE;
+ return 0;
+ }
+
+ m_nshapes= 0;
+
+ if (m_fn->reserve_op_buffer(2))
+ return 1;
+ last_shape_pos= m_fn->get_next_operation_pos();
+ m_fn->add_operation(buffer_op, 0);
m_npoints= 0;
int_start_line();
return 0;
@@ -1292,11 +1304,25 @@ int Item_func_buffer::Transporter::start_line()
int Item_func_buffer::Transporter::start_poly()
{
- ++m_nshapes;
+ m_nshapes= 1;
+
+ if (m_fn->reserve_op_buffer(2))
+ return 1;
+ last_shape_pos= m_fn->get_next_operation_pos();
+ m_fn->add_operation(buffer_op, 0);
return Gcalc_operation_transporter::start_poly();
}
+int Item_func_buffer::Transporter::complete_poly()
+{
+ if (Gcalc_operation_transporter::complete_poly())
+ return 1;
+ m_fn->add_operands_to_op(last_shape_pos, m_nshapes);
+ return 0;
+}
+
+
int Item_func_buffer::Transporter::start_ring()
{
m_npoints= 0;
@@ -1304,8 +1330,20 @@ int Item_func_buffer::Transporter::start_ring()
}
+int Item_func_buffer::Transporter::start_collection(int n_objects)
+{
+ if (m_fn->reserve_op_buffer(1))
+ return 1;
+ m_fn->add_operation(Gcalc_function::op_union, n_objects);
+ return 0;
+}
+
+
int Item_func_buffer::Transporter::add_point(double x, double y)
{
+ if (skip_line)
+ return 0;
+
if (m_npoints && x == x2 && y == y2)
return 0;
@@ -1374,9 +1412,14 @@ int Item_func_buffer::Transporter::complete()
int Item_func_buffer::Transporter::complete_line()
{
- if (complete())
- return 1;
- int_complete_line();
+ if (!skip_line)
+ {
+ if (complete())
+ return 1;
+ int_complete_line();
+ m_fn->add_operands_to_op(last_shape_pos, m_nshapes);
+ }
+ skip_line= FALSE;
return 0;
}
@@ -1396,7 +1439,6 @@ String *Item_func_buffer::val_str(String *str_value)
double dist= args[1]->val_real();
Geometry_buffer buffer;
Geometry *g;
- uint32 union_pos;
uint32 srid= 0;
String *str_result= NULL;
Transporter trn(&func, &collector, dist);
@@ -1418,17 +1460,9 @@ String *Item_func_buffer::val_str(String *str_value)
goto mem_error;
}
- if (func.reserve_op_buffer(2))
- goto mem_error;
- /* will specify operands later */
- union_pos= func.get_next_operation_pos();
- func.add_operation((dist > 0.0) ? Gcalc_function::op_union :
- Gcalc_function::op_difference, 0);
-
if (g->store_shapes(&trn))
goto mem_error;
- func.add_operands_to_op(union_pos, trn.m_nshapes);
collector.prepare_operation();
if (func.alloc_states())
goto mem_error;
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index 1838a3783e8..d5ed2c1f764 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -26,6 +26,7 @@
#endif
#include "gcalc_slicescan.h"
+#include "gcalc_tools.h"
class Item_geometry_func: public Item_str_func
{
@@ -298,18 +299,28 @@ protected:
int add_last_edge_buffer();
int add_point_buffer(double x, double y);
int complete();
- public:
int m_nshapes;
+ Gcalc_function::op_type buffer_op;
+ int last_shape_pos;
+ bool skip_line;
+
+ public:
Transporter(Gcalc_function *fn, Gcalc_heap *heap, double d) :
- Gcalc_operation_transporter(fn, heap), m_npoints(0), m_d(d), m_nshapes(0)
+ Gcalc_operation_transporter(fn, heap), m_npoints(0), m_d(d),
+ m_nshapes(0), buffer_op((d > 0.0) ? Gcalc_function::op_union :
+ Gcalc_function::op_difference),
+ skip_line(FALSE)
{}
int single_point(double x, double y);
int start_line();
int complete_line();
int start_poly();
+ int complete_poly();
int start_ring();
int complete_ring();
int add_point(double x, double y);
+
+ int start_collection(int n_objects);
};
Gcalc_heap collector;
Gcalc_function func;