List:Commits« Previous MessageNext Message »
From:Alexey Botchkov Date:December 4 2009 2:38pm
Subject:bzr commit into mysql-5.1-bugteam branch (holyfoot:2664) Bug#45883
Bug#46372 Bug#46498
View as plain text  
#At file:///home/hf/work/mysql_common/gis-bugfix/ based on revid:holyfoot@stripped

 2664 Alexey Botchkov	2009-12-04
      Bug#46372      buffer of linestring returns multipolygon in certain cases
          there was a mistake in handling of 'holes' in the polygons.
          Fixed by adding the 'first_poly_node' pointer to the res_point
          structure to point to the first point of the surrounding polygon.
          Also a set of debugging functions was added. It doesn't affect the
          working fucntions, but greatly simplifies the debugging.
          This path fixes also bug#46498 and bug#45883 also.
      
      per-file comments:
        sql/gcalc_slicescan.cc
      Bug#46372      buffer of linestring returns multipolygon in certain cases
        sql/gcalc_slicescan.h
      Bug#46372      buffer of linestring returns multipolygon in certain cases
        sql/gcalc_tools.cc
      Bug#46372      buffer of linestring returns multipolygon in certain cases
        sql/gcalc_tools.h
      Bug#46372      buffer of linestring returns multipolygon in certain cases
        sql/item_geofunc.cc
      Bug#46372      buffer of linestring returns multipolygon in certain cases
        sql/spatial.cc
      Bug#46372      buffer of linestring returns multipolygon in certain cases

    modified:
      sql/gcalc_slicescan.cc
      sql/gcalc_slicescan.h
      sql/gcalc_tools.cc
      sql/gcalc_tools.h
      sql/item_geofunc.cc
      sql/spatial.cc
=== modified file 'sql/gcalc_slicescan.cc'
--- a/sql/gcalc_slicescan.cc	2009-11-24 16:35:34 +0000
+++ b/sql/gcalc_slicescan.cc	2009-12-04 14:30:55 +0000
@@ -66,12 +66,45 @@ void gcalc_dbug_env_struct::stop_recordi
   recfile= NULL;
 }
 
+
+void gcalc_dbug_env_struct::print(const char *ln)
+{
+  if (recfile)
+    fprintf(recfile, "%s", ln);
+}
+
+
 gcalc_dbug_env_struct::~gcalc_dbug_env_struct()
 {
   if (recfile)
     fclose(recfile);
 }
 
+
+void gcalc_dbug_do_print(const char* fmt, ...)
+{
+  va_list args;
+  char buff[1000];
+  va_start(args, fmt);
+  vsnprintf(buff, sizeof(buff), fmt, args);
+  va_end(args);
+  gcalc_dbug_cur_env->print(buff);
+}
+
+
+void gcalc_scan_iterator::point::dbug_print()
+{
+  const gcalc_scan_iterator::point *slice= this;
+  for (; slice; slice= slice->get_next())
+  {
+    gcalc_dbug_do_print("(%d %.15g ", slice->thread, slice->x);
+    gcalc_dbug_do_print(slice->horiz_dir ? "-" : "/");
+    gcalc_dbug_do_print(" %.15g) ", slice->dx_dy);
+  }
+  gcalc_dbug_do_print("\n");
+}
+
+
 static gcalc_dbug_env_struct gcalc_dbug_usual_env;
 gcalc_dbug_env_struct *gcalc_dbug_cur_env= &gcalc_dbug_usual_env;
 
@@ -219,6 +252,18 @@ void gcalc_heap::prepare_operation()
     trim_node(cur->left, cur);
     trim_node(cur->right, cur);
   }
+#ifdef GCALC_DBUG
+  {
+    info *cur= get_first();
+    GCALC_DBUG_PRINT(("shape\t  x\t  y\tleft\tright\tthis\n"));
+    for (; cur; cur= cur->get_next())
+    {
+      GCALC_DBUG_PRINT(("%d\t%.15g\t%.15g\t %d\t %d\t %d\n", cur->shape,
+                        cur->x, cur->y,(int)cur->left, (int)cur->right, (int) cur));
+    }
+    GCALC_DBUG_PRINT(("------------------\n"));
+  }
+#endif /*GCALC_DBUG*/
 }
 
 
@@ -299,7 +344,7 @@ static bool slice_first_equal_x(const gc
 				const gcalc_scan_iterator::point *p1)
 {
   if (p0->horiz_dir == p1->horiz_dir)
-    return p0->dx_dy < p1->dx_dy;
+    return p0->dx_dy <= p1->dx_dy;
   if (p0->horiz_dir)
     return p0->dx_dy < 0;
   return p1->dx_dy > 0;  /* p1->horiz_dir case */
@@ -494,6 +539,12 @@ int gcalc_scan_iterator::normal_scan()
     free_list(sp1);
   }
 
+  GCALC_DBUG_PRINT(("Y%.15g", m_y0));
+  GCALC_DBUG_SLICE(m_slice0);
+  GCALC_DBUG_PRINT(("Y%.15g", m_y1));
+  GCALC_DBUG_SLICE(m_slice1);
+  GCALC_DBUG_PRINT(("\n"));
+
   if (intersections_found)
     return handle_intersections();
 
@@ -589,6 +640,7 @@ int gcalc_scan_iterator::find_intersecti
   } while (intersections_found);
 
   *hook= NULL;
+  GCALC_DBUG_PRINT(("intersections found:%d\n", m_n_intersections));
   return 0;
 }
 
@@ -684,6 +736,11 @@ int gcalc_scan_iterator::intersection_sc
       free_list(m_slice1);
       m_slice1= m_sav_slice;
       free_list(m_intersections);
+      GCALC_DBUG_PRINT(("  is Y%.15g", m_y0));
+      GCALC_DBUG_SLICE(m_slice0);
+      GCALC_DBUG_PRINT(("  is Y%.15g", m_y1));
+      GCALC_DBUG_SLICE(m_slice1);
+      GCALC_DBUG_PRINT(("\n"));
       return 0;
     }
   }
@@ -715,6 +772,7 @@ redo_loop:
 	   there's two intersections with the same Y
 	   Move suitable one to the beginning of the list
 	*/
+        GCALC_DBUG_PRINT(("redo_loop needed\n"));
 	pop_suitable_intersection();
 	goto redo_loop;
       }
@@ -747,6 +805,11 @@ redo_loop:
     *psp1= NULL;
   }
 
+  GCALC_DBUG_PRINT(("  is Y%.15g", m_y0));
+  GCALC_DBUG_SLICE(m_slice0);
+  GCALC_DBUG_PRINT(("  is Y%.15g", m_y1));
+  GCALC_DBUG_SLICE(m_slice1);
+  GCALC_DBUG_PRINT(("\n"));
   return 0;
 }
 

=== modified file 'sql/gcalc_slicescan.h'
--- a/sql/gcalc_slicescan.h	2009-11-24 16:35:34 +0000
+++ b/sql/gcalc_slicescan.h	2009-12-04 14:30:55 +0000
@@ -1,7 +1,7 @@
 #ifndef gcalc_slicescan_h
 #define gcalc_slicescan_h
 
-/* #define GCALC_DBUG */
+/*#define GCALC_DBUG*/
 
 #ifdef GCALC_DBUG
 class gcalc_dbug_env_struct
@@ -14,6 +14,7 @@ public:
   virtual void start_line();
   virtual void add_point(double x, double y);
   virtual void complete();
+  virtual void print(const char *ln);
   
   void start_newfile(const char *filename);
   void start_append(const char *filename);
@@ -22,18 +23,24 @@ public:
 };
 
 extern gcalc_dbug_env_struct *gcalc_dbug_cur_env;
+void gcalc_dbug_do_print(const char* fmt, ...);
 #define GCALC_DBUG_START_RING gcalc_dbug_cur_env->start_ring()
 #define GCALC_DBUG_START_LINE gcalc_dbug_cur_env->start_line()
 #define GCALC_DBUG_ADD_POINT(X,Y) gcalc_dbug_cur_env->add_point(X,Y)
 #define GCALC_DBUG_COMPLETE gcalc_dbug_cur_env->complete()
+#define GCALC_DBUG_SLICE(SLICE) SLICE->dbug_print()
 #define GCALC_DBUG_STARTFILE(FILENAME) gcalc_dbug_cur_env->start_newfile(FILENAME)
 #define GCALC_DBUG_STOP gcalc_dbug_cur_env->stop_recording()
+#define GCALC_DBUG_PRINT(ARGLIST) gcalc_dbug_do_print ARGLIST
 #else
 #define GCALC_DBUG_START_RING
+#define GCALC_DBUG_START_LINE
 #define GCALC_DBUG_ADD_POINT(X,Y)
 #define GCALC_DBUG_COMPLETE
+#define GCALC_DBUG_SLICE(SLICE)
 #define GCALC_DBUG_STARTFILE(FILENAME)
 #define GCALC_DBUG_STOP
+#define GCALC_DBUG_PRINT(ARGLIST)
 #endif /*GCLAC_DBUG*/
 
 class gcalc_dyn_list
@@ -268,6 +275,9 @@ public:
       next_pi= from->next_pi;
       thread= from->thread;
     }
+#ifdef GCALC_DBUG
+    void dbug_print();
+#endif /*GCALC_DBUG*/
   };
 
   class intersection : public gcalc_dyn_list::item

=== modified file 'sql/gcalc_tools.cc'
--- a/sql/gcalc_tools.cc	2009-05-13 07:03:17 +0000
+++ b/sql/gcalc_tools.cc	2009-12-04 14:30:55 +0000
@@ -82,26 +82,29 @@ int gcalc_function::count_internal()
   result= count_internal();
 
   while (--n_ops)
+  {
+    int next_res= count_internal();
     switch (next_func)
     {
       case op_union:
-        result= result || count_internal();
+        result= result | next_res;
         break;
       case op_intersection:
-        result= result && count_internal();
+        result= result & next_res;
         break;
       case op_symdifference:
-        result= result ^ count_internal();
+        result= result ^ next_res;
         break;
       case op_difference:
-        result= result && !count_internal();
+        result= result & !next_res;
         break;
       case op_backdifference:
-        result= !result && count_internal();
+        result= !result & next_res;
         break;
       default:
         DBUG_ASSERT(FALSE);
     };
+  }
 
   return result ^ mask;
 }
@@ -161,48 +164,102 @@ int gcalc_result_receiver::start_shape(g
 {
   if (buffer.reserve(4*2, 512))
     return 1;
-  buffer.q_append((uint32) shape);
-  if (shape != gcalc_function::shape_point)
-  {
-    n_points_pos= buffer.length();
-    buffer.length(buffer.length() + 4);
-    n_points= 0;
-  }
+  cur_shape= shape;
+  shape_pos= buffer.length();
+  buffer.length(shape_pos + ((shape == gcalc_function::shape_point) ? 4:8));
+  n_points= 0;
 
-  if (!n_shapes++)
-    common_shapetype= shape;
-  else if (!collection_result && (shape != common_shapetype))
-  {
-    if (shape == gcalc_function::shape_hole)
-      ++n_holes;
-    else
-      collection_result= TRUE;
-  }
   return 0;
 }
 
 
 int gcalc_result_receiver::add_point(double x, double y)
 {
+  if (n_points && x == prev_x && y == prev_y)
+  {
+    GCALC_DBUG_PRINT(("Skip same point %.15g\t%.15g\n", x, y));
+    return 0;
+  }
+
+  GCALC_DBUG_PRINT(("Add result point %.15g\t%.15g\n", x, y));
+  if (!n_points++)
+  {
+    prev_x= first_x= x;
+    prev_y= first_y= y;
+    return 0;
+  }
+
   if (buffer.reserve(8*2, 512))
     return 1;
-  buffer.q_append(x);
-  buffer.q_append(y);
-  n_points++;
+  buffer.q_append(prev_x);
+  buffer.q_append(prev_y);
+  prev_x= x;
+  prev_y= y;
   return 0;
 }
 
 
 int gcalc_result_receiver::complete_shape()
 {
-  buffer.write_at_position(n_points_pos, n_points);
+  if (n_points == 0)
+  {
+    buffer.length(shape_pos);
+    return 0;
+  }
+  if (n_points == 1)
+  {
+    if (cur_shape != gcalc_function::shape_point)
+    {
+      cur_shape= gcalc_function::shape_point;
+      buffer.length(buffer.length()-4);
+    }
+  }
+  else
+  {
+    DBUG_ASSERT(cur_shape != gcalc_function::shape_point);
+    if ((cur_shape == gcalc_function::shape_polygon ||
+          cur_shape == gcalc_function::shape_hole) &&
+        prev_x == first_x && prev_y == first_y)
+    {
+      n_points--;
+      buffer.write_at_position(shape_pos+4, n_points);
+      goto do_complete;
+    }
+    buffer.write_at_position(shape_pos+4, n_points);
+  }
+
+  if (buffer.reserve(8*2, 512))
+    return 1;
+  buffer.q_append(prev_x);
+  buffer.q_append(prev_y);
+  
+do_complete:
+  GCALC_DBUG_PRINT(("Complete shape %d\n", n_points));
+
+  buffer.write_at_position(shape_pos, (uint32) cur_shape);
+
+  if (!n_shapes++)
+  {
+    DBUG_ASSERT(cur_shape != gcalc_function::shape_hole);
+    common_shapetype= cur_shape;
+  }
+  else if (cur_shape == gcalc_function::shape_hole)
+  {
+    ++n_holes;
+  }
+  else if (!collection_result && (cur_shape != common_shapetype))
+  {
+      collection_result= true;
+  }
   return 0;
 }
 
 
 int gcalc_result_receiver::single_point(double x, double y)
 {
-  return start_shape(gcalc_function::shape_point) || add_point(x, y);
+  return start_shape(gcalc_function::shape_point) ||
+         add_point(x, y) ||
+         complete_shape();
 }
 
 
@@ -230,7 +287,7 @@ int gcalc_result_receiver::get_result_ty
   switch (common_shapetype)
   {
     case gcalc_function::shape_polygon:
-      return (get_nshapes() == 1) ?
+      return (n_shapes - n_holes == 1) ?
               Geometry::wkb_polygon : Geometry::wkb_multipolygon;
     case gcalc_function::shape_point:
       return (n_shapes == 1) ? Geometry::wkb_point : Geometry::wkb_multipoint;
@@ -244,21 +301,26 @@ int gcalc_result_receiver::get_result_ty
 }
 
 
-int gcalc_result_receiver::move_hole(uint32 dest_position, uint32 source_position)
+int gcalc_result_receiver::move_hole(uint32 dest_position, uint32 source_position,
+                                     uint32 *new_dest_position)
 {
   char *ptr;
   int source_len;
   if (dest_position == source_position)
+  {
+    *new_dest_position= position();
     return 0;
+  }
 
-  if (buffer.reserve(source_position - dest_position))
+  source_len= buffer.length() - source_position;
+  if (buffer.reserve(source_len, MY_ALIGN(source_len, 512)))
     return 1;
+
   ptr= (char *) buffer.ptr();
-  source_len= buffer.length() - source_position;
-  memcpy(ptr + buffer.length(), ptr + source_position, source_len);
   memmove(ptr + dest_position + source_len, ptr + dest_position,
-          source_position - dest_position);
+          buffer.length() - dest_position);
   memcpy(ptr + dest_position, ptr + buffer.length(), source_len);
+  *new_dest_position= dest_position + source_len;
   return 0;
 }
 
@@ -300,6 +362,8 @@ inline int gcalc_operation_reducer::cont
   rp->intersection_point= false;
   rp->pi= p;
   t->rp= rp;
+  GCALC_DBUG_PRINT(("Cont_range %d\t%d\t%.15g\t%.15g\n", (int) t,
+                    (int) p->shape, p->x, p->y));
   return 0;
 }
 
@@ -320,6 +384,8 @@ inline int gcalc_operation_reducer::cont
   rp->pi= p;
   rp->y= y;
   t->rp= rp;
+  GCALC_DBUG_PRINT(("Cont_i_range %d\t%d\t%.15g\t%.15g\n", (int) t,
+                    (int) p->shape, p->x, p->y));
   return 0;
 }
 
@@ -334,6 +400,8 @@ inline int gcalc_operation_reducer::star
   rp->pi= p;
   t->result_range= 1;
   t->rp= rp;
+  GCALC_DBUG_PRINT(("Start_range %d\t%d\t%.15g\t%.15g\n", (int) t,
+                    (int) p->shape, p->x, p->y));
   return 0;
 }
 
@@ -351,6 +419,8 @@ inline int gcalc_operation_reducer::star
   rp->pi= p;
   t->result_range= 1;
   t->rp= rp;
+  GCALC_DBUG_PRINT(("Start_i_range %d\t%d\t%.15g\t%.15g\n", (int) t,
+                    (int) p->shape, p->x, p->y));
   return 0;
 }
 
@@ -366,6 +436,8 @@ inline int gcalc_operation_reducer::end_
   rp->pi= p;
   t->rp->up= rp;
   t->result_range= 0;
+  GCALC_DBUG_PRINT(("End_range %d\t%d\t%.15g\t%.15g\n", (int) t,
+                    (int) p->shape, p->x, p->y));
   return 0;
 }
 
@@ -384,6 +456,8 @@ inline int gcalc_operation_reducer::end_
   rp->y= y;
   t->rp->up= rp;
   t->result_range= 0;
+  GCALC_DBUG_PRINT(("End_i_range %d\t%d\t%.15g\t%.15g\n", (int) t,
+                    (int) p->shape, p->x, p->y));
   return 0;
 }
 
@@ -411,6 +485,9 @@ int gcalc_operation_reducer::start_coupl
     rp0->outer_poly= 0;
     t0->thread_start= rp0;
   }
+  GCALC_DBUG_PRINT(("Start_couple t0 %d\tt1 %d\tshape %d\t%.15g\t%.15g\t%d\n",
+                    (int) t0, (int) t1, (int) p->shape, p->x, p->y,
+                    (int) prev_range));
   return 0;
 }
 
@@ -444,6 +521,9 @@ int gcalc_operation_reducer::start_i_cou
     rp0->outer_poly= 0;
     t0->thread_start= rp0;
   }
+  GCALC_DBUG_PRINT(("Start_i_couple t0 %d\tt1 %d\tshape0 %d\tshape1 %d\t%.15g\t%.15g\t%d\n",
+                    (int) t0, (int) t1, (int) p0->shape, (int) p1->shape, x, y,
+                    (int) prev_range));
   return 0;
 }
 
@@ -464,6 +544,8 @@ int gcalc_operation_reducer::end_couple(
   rp0->intersection_point= rp1->intersection_point= false;
   rp0->pi= rp1->pi= p;
   t0->result_range= t1->result_range= 0;
+  GCALC_DBUG_PRINT(("End_couple t0 %d\tt1 %d\tshape %d\t%.15g\t%.15g\n",
+                    (int) t0, (int) t1, (int) p->shape, p->x, p->y));
   return 0;
 }
 
@@ -488,6 +570,8 @@ int gcalc_operation_reducer::end_i_coupl
   t0->result_range= t1->result_range= 0;
   t0->rp->up= rp0;
   t1->rp->up= rp1;
+  GCALC_DBUG_PRINT(("End_i_couple t0 %d\tt1 %d\tshape0 %d\tshape1 %d\t%.15g\t%.15g\n",
+                    (int) t0, (int) t1, (int) p0->shape, (int) p1->shape, x, y));
   return 0;
 }
 
@@ -501,6 +585,8 @@ int gcalc_operation_reducer::add_single_
   rp->pi= p;
   rp->x= p->x;
   rp->y= p->y;
+  GCALC_DBUG_PRINT(("Single point shape %d\t%.15g\t%.15g\n",
+                    (int) p->shape, p->x, p->y));
   return 0;
 }
 
@@ -515,6 +601,8 @@ int gcalc_operation_reducer::add_i_singl
   rp->x= x;
   rp->pi= p;
   rp->y= y;
+  GCALC_DBUG_PRINT(("i_Single point shape %d\t%.15g\t%.15g\n",
+                    (int) p->shape, x, y));
   return 0;
 }
 
@@ -833,25 +921,31 @@ inline int gcalc_operation_reducer::get_
 }
 
 
-inline int gcalc_operation_reducer::get_result_thread(res_point *cur,
-						   gcalc_result_receiver *storage,
-						   int move_upward)
+int gcalc_operation_reducer::get_result_thread(res_point *cur,
+                                               gcalc_result_receiver *storage,
+                                               int move_upward)
 {
   res_point *next;
   bool glue_step= false;
+  res_point *first_poly_node= cur;
+  double x, y;
+  GCALC_DBUG_PRINT(("Result thread \n"));
   while (cur)
   {
     if (!glue_step)
     {
       if (cur->intersection_point)
       {
-	if (storage->add_point(float_to_coord(cur->x),
-			       float_to_coord(cur->y)))
-	  return 1;
+        x= float_to_coord(cur->x);
+        y= float_to_coord(cur->y);
       }
       else
-	if (storage->add_point(cur->pi->x, cur->pi->y))
-	  return 1;
+      {
+	x= cur->pi->x;
+        y= cur->pi->y;
+      }
+      if (storage->add_point(x, y))
+        return 1;
     }
     
     next= move_upward ? cur->up : cur->down;
@@ -865,6 +959,8 @@ inline int gcalc_operation_reducer::get_
     }
     else
       glue_step= false;
+
+    cur->first_poly_node= first_poly_node;
     free_result(cur);
     cur= next;
   }
@@ -872,18 +968,19 @@ inline int gcalc_operation_reducer::get_
 }
 
 
-inline int gcalc_operation_reducer::get_polygon_result(res_point *cur,
-						    gcalc_result_receiver *storage)
+int gcalc_operation_reducer::get_polygon_result(res_point *cur,
+                                                gcalc_result_receiver *storage)
 {
   res_point *glue= cur->glue;
   glue->up->down= NULL;
   free_result(glue);
-  return get_result_thread(cur, storage, 1);
+  return get_result_thread(cur, storage, 1) ||
+         storage->complete_shape();
 }
 
 
-inline int gcalc_operation_reducer::get_line_result(res_point *cur,
-						 gcalc_result_receiver *storage)
+int gcalc_operation_reducer::get_line_result(res_point *cur,
+                                             gcalc_result_receiver *storage)
 {
   res_point *next;
   int move_upward= 1;
@@ -904,17 +1001,20 @@ inline int gcalc_operation_reducer::get_
     }
   }
 
-  return get_result_thread(cur, storage, move_upward);
+  return get_result_thread(cur, storage, move_upward) ||
+         storage->complete_shape();
 }
 
 
 int gcalc_operation_reducer::get_result(gcalc_result_receiver *storage)
 {
+  GCALC_DBUG_PRINT(("get_result\n"));
   *m_res_hook= NULL;
   while (m_result)
   {
     if (!m_result->up)
     {
+      GCALC_DBUG_PRINT(("singlet\n"));
       if (get_single_result(m_result, storage))
 	return 1;
       continue;
@@ -922,19 +1022,24 @@ int gcalc_operation_reducer::get_result(
     gcalc_function::shape_type shape= m_fn->get_shape_kind(m_result->pi->shape);
     if (shape == gcalc_function::shape_polygon)
     {
+      GCALC_DBUG_PRINT(("Polygon result \n"));
       if (m_result->outer_poly)
       {
-        uint32 insert_position, hole_position;
-        insert_position= m_result->outer_poly->poly_position;
+        uint32 *insert_position, hole_position;
+        GCALC_DBUG_PRINT(("\tOuter poly \n"));
+        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))
+            storage->move_hole(*insert_position, hole_position,
+                               insert_position))
           return 1;
       }
       else
       {
         uint32 *poly_position= &m_result->poly_position;
+        GCALC_DBUG_PRINT(("\tNo outer poly \n"));
         storage->start_shape(gcalc_function::shape_polygon);
         if (get_polygon_result(m_result, storage))
           return 1;
@@ -943,12 +1048,11 @@ int gcalc_operation_reducer::get_result(
     }
     else
     {
+      GCALC_DBUG_PRINT(("Line result \n"));
       storage->start_shape(shape);
       if (get_line_result(m_result, storage))
 	return 1;
     }
-    if (storage->complete_shape())
-      return 1;
   }
   
   m_res_hook= (gcalc_dyn_list::item **)&m_result;

=== modified file 'sql/gcalc_tools.h'
--- a/sql/gcalc_tools.h	2009-04-13 08:03:25 +0000
+++ b/sql/gcalc_tools.h	2009-12-04 14:30:55 +0000
@@ -71,12 +71,15 @@ public:
 class gcalc_result_receiver
 {
   String buffer;
-  uint32 n_points_pos;
   uint32 n_points;
   gcalc_function::shape_type common_shapetype;
   bool collection_result;
   uint32 n_shapes;
   uint32 n_holes;
+
+  gcalc_function::shape_type cur_shape;
+  uint32 shape_pos;
+  double first_x, first_y, prev_x, prev_y;
 public:
   gcalc_result_receiver();
   int start_shape(gcalc_function::shape_type shape);
@@ -92,7 +95,8 @@ public:
   int get_nholes() { return n_holes; }
   int get_result_typeid();
   uint32 position() { return buffer.length(); }
-  int move_hole(uint32 dest_position, uint32 source_position);
+  int move_hole(uint32 dest_position, uint32 source_position,
+                uint32 *new_dest_position);
 };
 
 
@@ -122,13 +126,17 @@ public:
   public:
     bool intersection_point;
     double x,y;
-    const gcalc_heap::info *pi;
     res_point *up;
     res_point *down;
     res_point *glue;
     union
     {
-      const res_point *outer_poly;
+      const gcalc_heap::info *pi;
+      res_point *first_poly_node;
+    };
+    union
+    {
+      res_point *outer_poly;
       uint32 poly_position;
     };
     gcalc_dyn_list::item **prev_hook;
@@ -140,7 +148,7 @@ public:
   public:
     res_point *rp;
     int result_range;
-    const res_point *thread_start;
+    res_point *thread_start;
     active_thread *get_next() { return (active_thread *)next; }
   };
 
@@ -207,7 +215,7 @@ private:
   int get_single_result(res_point *res, gcalc_result_receiver *storage);
   int get_result_thread(res_point *cur, gcalc_result_receiver *storage,
 			int move_upward);
-  int get_polygon_result(res_point *cur,gcalc_result_receiver *storage);
+  int get_polygon_result(res_point *cur, gcalc_result_receiver *storage);
   int get_line_result(res_point *cur, gcalc_result_receiver *storage);
 
   void free_result(res_point *res);

=== modified file 'sql/item_geofunc.cc'
--- a/sql/item_geofunc.cc	2009-11-24 16:35:34 +0000
+++ b/sql/item_geofunc.cc	2009-12-04 14:30:55 +0000
@@ -737,6 +737,8 @@ String *Item_func_spatial_operation::val
     goto exit;
 
   
+  GCALC_DBUG_STARTFILE("/home/hf/gcalc_log");
+
   collector.prepare_operation();
   scan_it.init(&collector);
   if (func.alloc_states())
@@ -759,6 +761,7 @@ String *Item_func_spatial_operation::val
     goto exit;
 
 exit:
+  GCALC_DBUG_STOP;
   collector.reset();
   func.reset();
   scan_it.reset();

=== modified file 'sql/spatial.cc'
--- a/sql/spatial.cc	2009-11-18 13:40:52 +0000
+++ b/sql/spatial.cc	2009-12-04 14:30:55 +0000
@@ -1757,6 +1757,8 @@ uint Gis_multi_polygon::init_from_opresu
   const char *opres_orig= opres;
   uint p_len;
   uint poly_shapes;
+  uint n_poly= 0;
+  uint32 np_pos= bin->length();
 
   if (bin->reserve(4, 512))
     return 0;
@@ -1772,7 +1774,9 @@ uint Gis_multi_polygon::init_from_opresu
       return 0;
     n_shapes-= poly_shapes;
     opres+= p_len;
+    n_poly++;
   }
+  bin->write_at_position(np_pos, n_poly);
   return opres - opres_orig;
 }
 


Attachment: [text/bzr-bundle] bzr/holyfoot@mysql.com-20091204143055-0s3xwff43g3oiuuy.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (holyfoot:2664) Bug#45883Bug#46372 Bug#46498Alexey Botchkov5 Dec