[Commits] Rev 3604: ST_Relate and ST_ConvexHull implementations added. in file:///home/hf/wmar/5.3-gis/

holyfoot at askmonty.org holyfoot at askmonty.org
Fri Nov 23 15:56:51 EET 2012


At file:///home/hf/wmar/5.3-gis/

------------------------------------------------------------
revno: 3604
revision-id: holyfoot at askmonty.org-20121123134857-779f6r64mbl29f4f
parent: holyfoot at askmonty.org-20121122062302-xxa1uxurik07unjd
committer: Alexey Botchkov <holyfoot at askmonty.org>
branch nick: 5.3-gis
timestamp: Fri 2012-11-23 17:48:57 +0400
message:
  ST_Relate and ST_ConvexHull implementations added.
-------------- next part --------------
=== modified file 'mysql-test/r/gis-precise.result'
--- a/mysql-test/r/gis-precise.result	2012-11-22 06:23:02 +0000
+++ b/mysql-test/r/gis-precise.result	2012-11-23 13:48:57 +0000
@@ -215,6 +215,24 @@ POLYGON((10 0,7 3,0 14,10 16,15 15,14 7,
 select astext(st_convexhull(GeomFromText('POLYGON((10 0, 7 3, 15 6, 0 14, 10 16, 15 15, 12 10, 14 7, 10 0))')));
 astext(st_convexhull(GeomFromText('POLYGON((10 0, 7 3, 15 6, 0 14, 10 16, 15 15, 12 10, 14 7, 10 0))')))
 POLYGON((10 0,7 3,0 14,10 16,15 15,15 6,10 0))
+select st_relate(Geomfromtext('POLYGON((0 0, 0 1, 1 0, 0 0))'), GEOMfromtext('POLYGON((0 0, 1 1, 0 1, 0 0))'), 'T*******T');
+st_relate(Geomfromtext('POLYGON((0 0, 0 1, 1 0, 0 0))'), GEOMfromtext('POLYGON((0 0, 1 1, 0 1, 0 0))'), 'T*******T')
+1
+select st_relate(Geomfromtext('POLYGON((0 0, 0 10, 10 0, 0 0))'), GEOMfromtext('POLYGON((1 1, 2 2, 1 2, 1 1))'), '****T***T');
+st_relate(Geomfromtext('POLYGON((0 0, 0 10, 10 0, 0 0))'), GEOMfromtext('POLYGON((1 1, 2 2, 1 2, 1 1))'), '****T***T')
+1
+select st_relate(Geomfromtext('POLYGON((0 0, 0 10, 10 0, 0 0))'), GEOMfromtext('POLYGON((1 1, 2 2, 1 2, 1 1))'), 'T*******T');
+st_relate(Geomfromtext('POLYGON((0 0, 0 10, 10 0, 0 0))'), GEOMfromtext('POLYGON((1 1, 2 2, 1 2, 1 1))'), 'T*******T')
+0
+select astext(st_boundary(Geomfromtext('POINT(0 0)')));
+astext(st_boundary(Geomfromtext('POINT(0 0)')))
+GEOMETRYCOLLECTION EMPTY
+select astext(st_boundary(Geomfromtext(' LINESTRING(0 0,0 10,10 0)')));
+astext(st_boundary(Geomfromtext(' LINESTRING(0 0,0 10,10 0)')))
+MULTIPOINT(0 0,10 0)
+select astext(st_boundary(Geomfromtext('POLYGON((0 0, 0 10, 10 0, 0 0))')));
+astext(st_boundary(Geomfromtext('POLYGON((0 0, 0 10, 10 0, 0 0))')))
+LINESTRING(0 0,0 10,10 0,0 0)
 SELECT astext(ST_UNION (
 PolyFromText('POLYGON(( 2 2 ,3 2,2 7,2 2),( 0 0,8 2,1 9,0 0))'),
 ExteriorRing( Envelope( MultiLineStringFromText('MULTILINESTRING((3 4,5 3),(3 0,0 5))')))));

=== modified file 'mysql-test/r/gis.result'
--- a/mysql-test/r/gis.result	2012-08-31 14:50:45 +0000
+++ b/mysql-test/r/gis.result	2012-11-23 13:48:57 +0000
@@ -1282,6 +1282,11 @@ WHERE name = 'Route 5' 
 AND aliases = 'Main Street';
 IsEmpty(centerline)
 0
+SELECT IsSimple(shore) 
+FROM lakes 
+WHERE name = 'Blue Lake';
+IsSimple(shore)
+1
 # Conformance Item T14 
 SELECT AsText(Envelope(boundary)) 
 FROM named_places 
@@ -1439,6 +1444,13 @@ WHERE forests.name = 'Green Forest' 
 AND named_places.name = 'Ashton';
 ST_Contains(forests.boundary, named_places.boundary)
 0
+# Conformance Item T45 
+SELECT ST_Relate(forests.boundary, named_places.boundary, 'TTTTTTTTT') 
+FROM forests, named_places 
+WHERE forests.name = 'Green Forest' 
+AND named_places.name = 'Ashton';
+ST_Relate(forests.boundary, named_places.boundary, 'TTTTTTTTT')
+1
 # Conformance Item T46 
 SELECT ST_Distance(position, boundary) 
 FROM bridges, named_places 
@@ -1446,6 +1458,13 @@ WHERE bridges.name = 'Cam Bridge' 
 AND named_places.name = 'Ashton';
 ST_Distance(position, boundary)
 12
+# Conformance Item T47 
+SELECT AsText(ST_Intersection(centerline, shore)) 
+FROM streams, lakes 
+WHERE streams.name = 'Cam Stream' 
+AND lakes.name = 'Blue Lake';
+AsText(ST_Intersection(centerline, shore))
+POINT(52 18)
 # Conformance Item T48 
 SELECT AsText(ST_Difference(named_places.boundary, forests.boundary)) 
 FROM named_places, forests 
@@ -1472,6 +1491,12 @@ FROM buildings, bridges 
 WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1;
 count(*)
 1
+# Conformance Item T52 
+SELECT AsText(ConvexHull(shore)) 
+FROM lakes 
+WHERE lakes.name = 'Blue Lake';
+AsText(ConvexHull(shore))
+POLYGON((48 6,52 18,66 23,73 9,48 6))
 DROP DATABASE gis_ogs;
 #
 # BUG #1043845 st_distance() results are incorrect depending on variable order

=== modified file 'mysql-test/t/gis-precise.test'
--- a/mysql-test/t/gis-precise.test	2012-11-22 06:23:02 +0000
+++ b/mysql-test/t/gis-precise.test	2012-11-23 13:48:57 +0000
@@ -115,6 +115,16 @@ select astext(st_convexhull(GeomFromText
 select astext(st_convexhull(GeomFromText('POLYGON((10 0, 7 3, 10 6, 0 14, 10 16, 15 15, 12 10, 14 7, 10 0))')));
 select astext(st_convexhull(GeomFromText('POLYGON((10 0, 7 3, 15 6, 0 14, 10 16, 15 15, 12 10, 14 7, 10 0))')));
 
+# Relate test
+select st_relate(Geomfromtext('POLYGON((0 0, 0 1, 1 0, 0 0))'), GEOMfromtext('POLYGON((0 0, 1 1, 0 1, 0 0))'), 'T*******T');
+select st_relate(Geomfromtext('POLYGON((0 0, 0 10, 10 0, 0 0))'), GEOMfromtext('POLYGON((1 1, 2 2, 1 2, 1 1))'), '****T***T');
+select st_relate(Geomfromtext('POLYGON((0 0, 0 10, 10 0, 0 0))'), GEOMfromtext('POLYGON((1 1, 2 2, 1 2, 1 1))'), 'T*******T');
+
+# Boundary test
+select astext(st_boundary(Geomfromtext('POINT(0 0)')));
+select astext(st_boundary(Geomfromtext(' LINESTRING(0 0,0 10,10 0)')));
+select astext(st_boundary(Geomfromtext('POLYGON((0 0, 0 10, 10 0, 0 0))')));
+
 # bug #801243 Assertion `(0)' failed in Gis_geometry_collection::init_from_opresult on ST_UNION
 
 SELECT astext(ST_UNION (

=== modified file 'mysql-test/t/gis.test'
--- a/mysql-test/t/gis.test	2012-08-31 14:50:45 +0000
+++ b/mysql-test/t/gis.test	2012-11-23 13:48:57 +0000
@@ -1100,12 +1100,10 @@ FROM road_segments 
 WHERE name = 'Route 5' 
 AND aliases = 'Main Street'; 
 
-# FIXME: get wrong result:0, expected 1.
 #--echo # Conformance Item T12 
-# TODO: ST_IsSimple() alias
-#SELECT IsSimple(shore) 
-#FROM lakes 
-#WHERE name = 'Blue Lake'; 
+SELECT IsSimple(shore) 
+FROM lakes 
+WHERE name = 'Blue Lake'; 
 
 # TODO: WL#2377
 #--echo # Conformance Item T13 
@@ -1306,11 +1304,11 @@ WHERE forests.name = 'Green Forest' 
 AND named_places.name = 'Ashton'; 
 
 # TODO: WL#2377
-#--echo # Conformance Item T45 
-#SELECT Relate(forests.boundary, named_places.boundary, 'TTTTTTTTT') 
-#FROM forests, named_places 
-#WHERE forests.name = 'Green Forest' 
-#AND named_places.name = 'Ashton'; 
+--echo # Conformance Item T45 
+SELECT ST_Relate(forests.boundary, named_places.boundary, 'TTTTTTTTT') 
+FROM forests, named_places 
+WHERE forests.name = 'Green Forest' 
+AND named_places.name = 'Ashton'; 
 
 --echo # Conformance Item T46 
 SELECT ST_Distance(position, boundary) 
@@ -1319,11 +1317,11 @@ WHERE bridges.name = 'Cam Bridge' 
 AND named_places.name = 'Ashton'; 
 
 # FIXME: wrong result: NULL, expected 12
-#--echo # Conformance Item T47 
-#SELECT AsText(ST_Intersection(centerline, shore)) 
-#FROM streams, lakes 
-#WHERE streams.name = 'Cam Stream' 
-#AND lakes.name = 'Blue Lake'; 
+--echo # Conformance Item T47 
+SELECT AsText(ST_Intersection(centerline, shore)) 
+FROM streams, lakes 
+WHERE streams.name = 'Cam Stream' 
+AND lakes.name = 'Blue Lake'; 
 
 --echo # Conformance Item T48 
 SELECT AsText(ST_Difference(named_places.boundary, forests.boundary)) 
@@ -1349,10 +1347,10 @@ FROM buildings, bridges 
 WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1; 
 
 # TODO: WL#2377
-#--echo # Conformance Item T52 
-#SELECT AsText(ConvexHull(shore)) 
-#FROM lakes 
-#WHERE lakes.name = 'Blue Lake'; 
+--echo # Conformance Item T52 
+SELECT AsText(ConvexHull(shore)) 
+FROM lakes 
+WHERE lakes.name = 'Blue Lake'; 
 
 DROP DATABASE gis_ogs;
 

=== modified file 'sql/item_create.cc'
--- a/sql/item_create.cc	2012-11-22 06:23:02 +0000
+++ b/sql/item_create.cc	2012-11-23 13:48:57 +0000
@@ -947,7 +947,20 @@ class Create_func_envelope : public Crea
   Create_func_envelope() {}
   virtual ~Create_func_envelope() {}
 };
-#endif
+
+
+class Create_func_boundary : public Create_func_arg1
+{
+public:
+  virtual Item *create_1_arg(THD *thd, Item *arg1);
+
+  static Create_func_boundary s_singleton;
+
+protected:
+  Create_func_boundary() {}
+  virtual ~Create_func_boundary() {}
+};
+#endif /*HAVE_SPATIAL*/
 
 
 #ifdef HAVE_SPATIAL
@@ -1292,6 +1305,19 @@ class Create_func_interiorringn : public
 
 
 #ifdef HAVE_SPATIAL
+class Create_func_relate : public Create_func_arg3
+{
+public:
+  virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+
+  static Create_func_relate s_singleton;
+
+protected:
+  Create_func_relate() {}
+  virtual ~Create_func_relate() {}
+};
+
+
 class Create_func_mbr_intersects : public Create_func_arg2
 {
   public:
@@ -3494,7 +3520,16 @@ Create_func_envelope::create_1_arg(THD *
 {
   return new (thd->mem_root) Item_func_envelope(arg1);
 }
-#endif
+
+
+Create_func_boundary Create_func_boundary::s_singleton;
+
+Item*
+Create_func_boundary::create_1_arg(THD *thd, Item *arg1)
+{
+  return new (thd->mem_root) Item_func_boundary(arg1);
+}
+#endif /*HAVE_SPATIAL*/
 
 
 #ifdef HAVE_SPATIAL
@@ -3903,6 +3938,15 @@ Create_func_interiorringn::create_2_arg(
 
 
 #ifdef HAVE_SPATIAL
+Create_func_relate Create_func_relate::s_singleton;
+
+Item*
+Create_func_relate::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *matrix)
+{
+  return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2, matrix);
+}
+
+
 Create_func_mbr_intersects Create_func_mbr_intersects::s_singleton;
 
 Item*
@@ -5148,6 +5192,7 @@ static Native_func_registry func_array[]
   { { C_STRING_WITH_LEN("CONNECTION_ID") }, BUILDER(Create_func_connection_id)},
   { { C_STRING_WITH_LEN("CONV") }, BUILDER(Create_func_conv)},
   { { C_STRING_WITH_LEN("CONVERT_TZ") }, BUILDER(Create_func_convert_tz)},
+  { { C_STRING_WITH_LEN("CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)},
   { { C_STRING_WITH_LEN("COS") }, BUILDER(Create_func_cos)},
   { { C_STRING_WITH_LEN("COT") }, BUILDER(Create_func_cot)},
   { { C_STRING_WITH_LEN("CRC32") }, BUILDER(Create_func_crc32)},
@@ -5298,6 +5343,7 @@ static Native_func_registry func_array[]
   { { C_STRING_WITH_LEN("ST_ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)},
   { { C_STRING_WITH_LEN("ST_ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)},
   { { C_STRING_WITH_LEN("ST_ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)},
+  { { C_STRING_WITH_LEN("ST_BOUNDARY") }, GEOM_BUILDER(Create_func_boundary)},
   { { C_STRING_WITH_LEN("ST_BUFFER") }, GEOM_BUILDER(Create_func_buffer)},
   { { C_STRING_WITH_LEN("ST_CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
   { { C_STRING_WITH_LEN("ST_CONTAINS") }, GEOM_BUILDER(Create_func_contains)},
@@ -5344,6 +5390,7 @@ static Native_func_registry func_array[]
   { { C_STRING_WITH_LEN("ST_POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
   { { C_STRING_WITH_LEN("ST_POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
   { { C_STRING_WITH_LEN("ST_POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+  { { C_STRING_WITH_LEN("ST_RELATE") }, GEOM_BUILDER(Create_func_relate)},
   { { C_STRING_WITH_LEN("ST_SRID") }, GEOM_BUILDER(Create_func_srid)},
   { { C_STRING_WITH_LEN("ST_STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
   { { C_STRING_WITH_LEN("ST_SYMDIFFERENCE") }, GEOM_BUILDER(Create_func_symdifference)},

=== modified file 'sql/item_func.h'
--- a/sql/item_func.h	2012-11-01 19:36:31 +0000
+++ b/sql/item_func.h	2012-11-23 13:48:57 +0000
@@ -52,7 +52,7 @@ class Item_func :public Item_result_fiel
                   SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC,
                   SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC,
                   SP_STARTPOINT,SP_ENDPOINT,SP_EXTERIORRING,
-                  SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN,
+                  SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN, SP_RELATE_FUNC,
                   NOT_FUNC, NOT_ALL_FUNC,
                   NOW_FUNC, TRIG_COND_FUNC,
                   SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC,

=== modified file 'sql/item_geofunc.cc'
--- a/sql/item_geofunc.cc	2012-11-22 06:23:02 +0000
+++ b/sql/item_geofunc.cc	2012-11-23 13:48:57 +0000
@@ -216,6 +216,130 @@ String *Item_func_envelope::val_str(Stri
 }
 
 
+int Item_func_boundary::Transporter::single_point(double x, double y)
+{
+  return 0;
+}
+
+
+int Item_func_boundary::Transporter::start_line()
+{
+  n_points= 0;
+  current_type= Gcalc_function::shape_line;
+  return 0;
+}
+
+
+int Item_func_boundary::Transporter::complete_line()
+{
+  current_type= (Gcalc_function::shape_type) 0;
+  if (n_points > 1)
+    return m_receiver->single_point(last_x, last_y);
+  return 0;
+}
+
+
+int Item_func_boundary::Transporter::start_poly()
+{
+  current_type= Gcalc_function::shape_polygon;
+  return 0;
+}
+
+
+int Item_func_boundary::Transporter::complete_poly()
+{
+  current_type= (Gcalc_function::shape_type) 0;
+  return 0;
+}
+
+
+int Item_func_boundary::Transporter::start_ring()
+{
+  n_points= 0;
+  return m_receiver->start_shape(Gcalc_function::shape_line);
+}
+
+
+int Item_func_boundary::Transporter::complete_ring()
+{
+  if (n_points > 1)
+  {
+     m_receiver->add_point(last_x, last_y);
+  }
+  m_receiver->complete_shape();
+  return 0;
+}
+
+
+int Item_func_boundary::Transporter::add_point(double x, double y)
+{
+  ++n_points;
+  if (current_type== Gcalc_function::shape_polygon)
+  {
+    /* Polygon's ring case */
+    if (n_points == 1)
+    {
+      last_x= x;
+      last_y= y;
+    }
+    return m_receiver->add_point(x, y);
+  }
+  
+  if (current_type== Gcalc_function::shape_line)
+  {
+    /* Line's case */
+    last_x= x;
+    last_y= y;
+    if (n_points == 1)
+      return m_receiver->single_point(x, y);
+  }
+  return 0;
+}
+
+
+int Item_func_boundary::Transporter::start_collection(int n_objects)
+{
+  return 0;
+}
+
+
+String *Item_func_boundary::val_str(String *str_value)
+{
+  DBUG_ENTER("Item_func_boundary::val_str");
+  DBUG_ASSERT(fixed == 1);
+  String arg_val;
+  String *swkb= args[0]->val_str(&arg_val);
+  Geometry_buffer buffer;
+  Geometry *g;
+  uint32 srid= 0;
+  Transporter trn(&res_receiver);
+  
+  if ((null_value=
+       args[0]->null_value ||
+       !(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
+    DBUG_RETURN(0);
+  
+  if (g->store_shapes(&trn))
+    goto mem_error;
+
+  str_value->set_charset(&my_charset_bin);
+  if (str_value->reserve(SRID_SIZE, 512))
+    goto mem_error;
+  str_value->length(0);
+  str_value->q_append(srid);
+
+  if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
+    goto mem_error;
+
+  res_receiver.reset();
+  DBUG_RETURN(str_value);
+
+mem_error:
+  null_value= 1;
+  DBUG_RETURN(0);
+}
+
+
 Field::geometry_type Item_func_centroid::get_geometry_type() const
 {
   return Field::GEOM_POINT;
@@ -249,7 +373,7 @@ String *Item_func_centroid::val_str(Stri
 int Item_func_convexhull::add_node_to_line(ch_node **p_cur, int dir,
                                            const Gcalc_heap::Info *pi)
 {
-  ch_node *new_node= NULL;
+  ch_node *new_node;
   ch_node *cur= *p_cur;
 
   while (cur->prev)
@@ -260,12 +384,11 @@ int Item_func_convexhull::add_node_to_li
       break;
     /* The last node in the line should be */
     /* replaced with the curren one.       */
-    if (new_node)
-      res_heap.free_item(new_node);
     new_node= cur;
     cur= cur->prev;
+    res_heap.free_item(new_node);
   }
-  if (!new_node && !(new_node= new_ch_node()))
+  if (!(new_node= new_ch_node()))
     return 1;
   cur->next= new_node;
   new_node->prev= cur;
@@ -324,6 +447,7 @@ String *Item_func_convexhull::val_str(St
 
   left_cur= left_first= new_ch_node();
   right_cur= right_first= new_ch_node();
+  right_first->prev= left_first->prev= 0;
   right_first->pi= left_first->pi= scan_it.get_events()->pi;
 
   while (scan_it.more_points())
@@ -367,7 +491,6 @@ String *Item_func_convexhull::val_str(St
   }
 
   left_cur->next= 0;
-  right_first->prev= 0;
   if (res_receiver.start_shape(Gcalc_function::shape_polygon))
     goto mem_error;
 
@@ -749,10 +872,13 @@ longlong Item_func_spatial_mbr_rel::val_
 
 Item_func_spatial_rel::Item_func_spatial_rel(Item *a,Item *b,
                                              enum Functype sp_rel) :
-    Item_bool_func2(a,b), collector()
-{
-  spatial_rel = sp_rel;
-}
+    Item_int_func(a,b), spatial_rel(sp_rel)
+{}
+
+
+Item_func_spatial_rel::Item_func_spatial_rel(Item *a,Item *b, Item *mask) :
+    Item_int_func(a,b,mask), spatial_rel(SP_RELATE_FUNC)
+{}
 
 
 Item_func_spatial_rel::~Item_func_spatial_rel()
@@ -779,6 +905,8 @@ const char *Item_func_spatial_rel::func_
       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"; 
@@ -817,6 +945,84 @@ static double distance_points(const Gcal
 }
 
 
+static Gcalc_function::op_type op_matrix(int n)
+{
+  switch (n)
+  {
+    case 0:
+      return Gcalc_function::op_border;
+    case 1:
+      return Gcalc_function::op_internals;
+    case 2:
+      return (Gcalc_function::op_type)
+        ((int) Gcalc_function::op_not | (int) Gcalc_function::op_union);
+  };
+  GCALC_DBUG_ASSERT(FALSE);
+  return Gcalc_function::op_any;
+}
+
+
+static int setup_relate_func(Geometry *g1, Geometry *g2,
+    Gcalc_operation_transporter *trn, Gcalc_function *func,
+    const char *mask)
+{
+  int do_store_shapes=1;
+  uint shape_a, shape_b;
+  uint n_operands= 0;
+  int last_shape_pos;
+
+  last_shape_pos= func->get_next_expression_pos();
+  func->add_operation(Gcalc_function::op_intersection, 0);
+  for (int nc=0; nc<9; nc++)
+  {
+    uint cur_op;
+
+    cur_op= Gcalc_function::op_intersection;
+    switch (mask[nc])
+    {
+      case '*':
+        continue;
+      case 'T':
+      case '0':
+      case '1':
+      case '2':
+        cur_op|= Gcalc_function::v_find_t;
+        break;
+      case 'F':
+        cur_op|= Gcalc_function::v_find_f;
+        break;
+    };
+    ++n_operands;
+    if (func->reserve_op_buffer(1))
+      return 1;
+    func->add_operation(cur_op, 2);
+
+    func->add_operation(op_matrix(nc/3), 1);
+    if (do_store_shapes)
+    {
+      shape_a= func->get_next_expression_pos();
+      if (g1->store_shapes(trn))
+        return 1;
+    }
+    else
+      func->repeat_expression(shape_a);
+    func->add_operation(op_matrix(nc%3), 1);
+    if (do_store_shapes)
+    {
+      shape_b= func->get_next_expression_pos();
+      if (g2->store_shapes(trn))
+        return 1;
+      do_store_shapes= 0;
+    }
+    else
+      func->repeat_expression(shape_b);
+  }
+  
+  func->add_operands_to_op(last_shape_pos, n_operands);
+  return 0;
+}
+
+
 #define GIS_ZERO 0.00000000001
 
 longlong Item_func_spatial_rel::val_int()
@@ -825,6 +1031,7 @@ longlong Item_func_spatial_rel::val_int(
   DBUG_ASSERT(fixed == 1);
   String *res1;
   String *res2;
+  String *res3;
   Geometry_buffer buffer1, buffer2;
   Geometry *g1, *g2;
   int result= 0;
@@ -893,6 +1100,8 @@ longlong Item_func_spatial_rel::val_int(
     case SP_OVERLAPS_FUNC:
     case SP_CROSSES_FUNC:
       func.add_operation(Gcalc_function::op_intersection, 2);
+      if (func.reserve_op_buffer(1))
+        break;
       func.add_operation(Gcalc_function::v_find_t |
                          Gcalc_function::op_intersection, 2);
       shape_a= func.get_next_expression_pos();
@@ -901,6 +1110,8 @@ longlong Item_func_spatial_rel::val_int(
       shape_b= func.get_next_expression_pos();
       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::v_find_t |
@@ -913,6 +1124,8 @@ longlong Item_func_spatial_rel::val_int(
       func.repeat_expression(shape_a);
       break;
     case SP_TOUCHES_FUNC:
+      if (func.reserve_op_buffer(2))
+        break;
       func.add_operation(Gcalc_function::op_intersection, 2);
       func.add_operation(Gcalc_function::v_find_f |
                          Gcalc_function::op_not |
@@ -925,6 +1138,8 @@ longlong Item_func_spatial_rel::val_int(
       shape_b= func.get_next_expression_pos();
       if ((null_value= g2->store_shapes(&trn)))
         break;
+      if (func.reserve_op_buffer(5))
+        break;
       func.add_operation(Gcalc_function::v_find_t |
                          Gcalc_function::op_intersection, 2);
       func.add_operation(Gcalc_function::op_border, 1);
@@ -932,6 +1147,13 @@ longlong Item_func_spatial_rel::val_int(
       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;

=== modified file 'sql/item_geofunc.h'
--- a/sql/item_geofunc.h	2012-11-22 06:23:02 +0000
+++ b/sql/item_geofunc.h	2012-11-23 13:48:57 +0000
@@ -139,6 +139,36 @@ class Item_func_envelope: public Item_ge
   Field::geometry_type get_geometry_type() const;
 };
 
+class Item_func_boundary: public Item_geometry_func
+{
+  class Transporter : public Gcalc_shape_transporter
+  {
+    Gcalc_result_receiver *m_receiver;
+    uint n_points;
+    Gcalc_function::shape_type current_type;
+    double last_x, last_y;
+  public:
+    Transporter(Gcalc_result_receiver *receiver) :
+      Gcalc_shape_transporter(NULL), m_receiver(receiver)
+    {}
+    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_result_receiver res_receiver;
+public:
+  Item_func_boundary(Item *a): Item_geometry_func(a) {}
+  const char *func_name() const { return "st_boundary"; }
+  String *val_str(String *);
+};
+
 class Item_func_point: public Item_geometry_func
 {
 public:
@@ -257,15 +287,16 @@ class Item_func_spatial_mbr_rel: public 
 };
 
 
-class Item_func_spatial_rel: public Item_bool_func2
+class Item_func_spatial_rel: public Item_int_func
 {
   enum Functype spatial_rel;
   Gcalc_heap collector;
   Gcalc_scan_iterator scan_it;
   Gcalc_function func;
-  String tmp_value1,tmp_value2;
+  String tmp_value1, tmp_value2, tmp_matrix;
 public:
   Item_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel);
+  Item_func_spatial_rel(Item *a, Item *b, Item *matrix);
   virtual ~Item_func_spatial_rel();
   longlong val_int();
   enum Functype functype() const 
@@ -281,6 +312,9 @@ class Item_func_spatial_rel: public Item
 
   void fix_length_and_dec() { maybe_null= 1; }
   bool is_null() { (void) val_int(); return null_value; }
+  bool is_bool_func() { return 1; }
+  uint decimal_precision() const { return 1; }
+  optimize_type select_optimize() const { return OPTIMIZE_OP; }
 };
 
 

=== modified file 'sql/spatial.cc'
--- a/sql/spatial.cc	2012-11-09 08:11:20 +0000
+++ b/sql/spatial.cc	2012-11-23 13:48:57 +0000
@@ -2220,7 +2220,12 @@ uint Gis_geometry_collection::init_from_
     n_objects++;
   }
   bin->write_at_position(no_pos, n_objects);
-  return (uint) (opres - opres_orig);
+
+  /* Originally it was just 'return (uint) (opres - opres_orig);'  */
+  /* But in the case of GEOMETRYCOLLECTION EMPTY we'd return 0     */
+  /* which is the sign of an error. And the GEOMETRY_COLLECTION    */
+  /* is never hosted inside another geometry object.               */
+  return n_objects ? (uint) (opres - opres_orig) : 1;
 }
 
 



More information about the commits mailing list