1 /*
2    Copyright (c) 2002, 2013, Oracle and/or its affiliates.
3    Copyright (c) 2011, 2021, MariaDB Corporation.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; version 2 of the License.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
17 
18 #include "mariadb.h"
19 #include "sql_priv.h"
20 #include "spatial.h"
21 #include "gstream.h"                            // Gis_read_stream
22 #include "sql_string.h"                         // String
23 
24 /* This is from item_func.h. Didn't want to #include the whole file. */
25 double my_double_round(double value, longlong dec, bool dec_unsigned,
26                        bool truncate);
27 
28 #ifdef HAVE_SPATIAL
29 
30 /*
31   exponential notation :
32   1   sign
33   1   number before the decimal point
34   1   decimal point
35   14  number of significant digits (see String::qs_append(double))
36   1   'e' sign
37   1   exponent sign
38   3   exponent digits
39   ==
40   22
41 
42   "f" notation :
43   1   optional 0
44   1   sign
45   14  number significant digits (see String::qs_append(double) )
46   1   decimal point
47   ==
48   17
49 */
50 
51 #define MAX_DIGITS_IN_DOUBLE MY_GCVT_MAX_FIELD_WIDTH
52 
within(const MBR * mbr)53 int MBR::within(const MBR *mbr)
54 {
55   /*
56     We have to take into account the 'dimension' of
57     the MBR, where the dimension of a single point is 0,
58     the dimesion of an vertical or horizontal line is 1,
59     and finally the dimension of the solid rectangle is 2.
60   */
61 
62   int dim1= dimension();
63   int dim2= mbr->dimension();
64 
65   DBUG_ASSERT(dim1 >= 0 && dim1 <= 2 && dim2 >= 0 && dim2 <= 2);
66 
67   /*
68     Either/both of the two operands can degrade to a point or a
69     horizontal/vertical line segment, and we have to treat such cases
70     separately.
71    */
72   switch (dim1)
73   {
74   case 0:
75     DBUG_ASSERT(xmin == xmax && ymin == ymax);
76     switch (dim2)
77     {
78     case 0:
79       DBUG_ASSERT(mbr->xmin == mbr->xmax && mbr->ymin == mbr->ymax);
80       return equals(mbr);
81       break;
82     case 1:
83       DBUG_ASSERT((mbr->xmin == mbr->xmax && mbr->ymin != mbr->ymax) ||
84                   (mbr->ymin == mbr->ymax && mbr->xmin != mbr->xmax));
85       return ((xmin > mbr->xmin && xmin < mbr->xmax && ymin == mbr->ymin) ||
86               (ymin > mbr->ymin && ymin < mbr->ymax && xmin == mbr->xmin));
87       break;
88     case 2:
89       DBUG_ASSERT(mbr->xmin != mbr->xmax && mbr->ymin != mbr->ymax);
90       return (xmin > mbr->xmin && xmax < mbr->xmax &&
91               ymin > mbr->ymin && ymax < mbr->ymax);
92       break;
93     }
94     break;
95   case 1:
96     DBUG_ASSERT((xmin == xmax && ymin != ymax) ||
97                 (ymin == ymax && xmin != xmax));
98     switch (dim2)
99     {
100     case 0:
101       DBUG_ASSERT(mbr->xmin == mbr->xmax && mbr->ymin == mbr->ymax);
102       return 0;
103       break;
104     case 1:
105       DBUG_ASSERT((mbr->xmin == mbr->xmax && mbr->ymin != mbr->ymax) ||
106                   (mbr->ymin == mbr->ymax && mbr->xmin != mbr->xmax));
107       return ((xmin == xmax && mbr->xmin == mbr->xmax && mbr->xmin == xmin &&
108                mbr->ymin <= ymin && mbr->ymax >= ymax) ||
109               (ymin == ymax && mbr->ymin == mbr->ymax && mbr->ymin == ymin &&
110                mbr->xmin <= xmin && mbr->xmax >= xmax));
111       break;
112     case 2:
113       DBUG_ASSERT(mbr->xmin != mbr->xmax && mbr->ymin != mbr->ymax);
114       return ((xmin == xmax && xmin > mbr->xmin && xmax < mbr->xmax &&
115                ymin >= mbr->ymin && ymax <= mbr->ymax) ||
116               (ymin == ymax && ymin > mbr->ymin && ymax < mbr->ymax &&
117                xmin >= mbr->xmin && xmax <= mbr->xmax));
118       break;
119     }
120     break;
121   case 2:
122     DBUG_ASSERT(xmin != xmax && ymin != ymax);
123     switch (dim2)
124     {
125     case 0:
126     case 1:
127       return 0;
128       break;
129     case 2:
130       DBUG_ASSERT(mbr->xmin != mbr->xmax && mbr->ymin != mbr->ymax);
131       return ((mbr->xmin <= xmin) && (mbr->ymin <= ymin) &&
132               (mbr->xmax >= xmax) && (mbr->ymax >= ymax));
133       break;
134 
135     }
136     break;
137   }
138 
139   // Never reached.
140   DBUG_ASSERT(false);
141   return 0;
142 }
143 
144 
145 /***************************** Gis_class_info *******************************/
146 
147 String Geometry::bad_geometry_data("Bad object", &my_charset_bin);
148 
149 Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_last+1]=
150 {
151   NULL, NULL, NULL, NULL, NULL, NULL, NULL
152 };
153 
154 static Geometry::Class_info **ci_collection_end=
155                                 Geometry::ci_collection+Geometry::wkb_last + 1;
156 
Class_info(const char * name,const char * geojson_name,int type_id,create_geom_t create_func)157 Geometry::Class_info::Class_info(const char *name, const char *geojson_name,
158                                  int type_id, create_geom_t create_func):
159   m_type_id(type_id), m_create_func(create_func)
160 {
161   m_name.str= (char *) name;
162   m_name.length= strlen(name);
163   m_geojson_name.str= (char *) geojson_name;
164   m_geojson_name.length= strlen(geojson_name);
165 
166   ci_collection[type_id]= this;
167 }
168 
create_point(char * buffer)169 static Geometry *create_point(char *buffer)
170 {
171   return new (buffer) Gis_point;
172 }
173 
create_linestring(char * buffer)174 static Geometry *create_linestring(char *buffer)
175 {
176   return new (buffer) Gis_line_string;
177 }
178 
create_polygon(char * buffer)179 static Geometry *create_polygon(char *buffer)
180 {
181   return new (buffer) Gis_polygon;
182 }
183 
create_multipoint(char * buffer)184 static Geometry *create_multipoint(char *buffer)
185 {
186   return new (buffer) Gis_multi_point;
187 }
188 
create_multipolygon(char * buffer)189 static Geometry *create_multipolygon(char *buffer)
190 {
191   return new (buffer) Gis_multi_polygon;
192 }
193 
create_multilinestring(char * buffer)194 static Geometry *create_multilinestring(char *buffer)
195 {
196   return new (buffer) Gis_multi_line_string;
197 }
198 
create_geometrycollection(char * buffer)199 static Geometry *create_geometrycollection(char *buffer)
200 {
201   return new (buffer) Gis_geometry_collection;
202 }
203 
204 
205 
206 static Geometry::Class_info point_class("POINT", "Point",
207 					Geometry::wkb_point, create_point);
208 
209 static Geometry::Class_info linestring_class("LINESTRING", "LineString",
210 					     Geometry::wkb_linestring,
211 					     create_linestring);
212 static Geometry::Class_info polygon_class("POLYGON", "Polygon",
213 					      Geometry::wkb_polygon,
214 					      create_polygon);
215 static Geometry::Class_info multipoint_class("MULTIPOINT", "MultiPoint",
216 						 Geometry::wkb_multipoint,
217 						 create_multipoint);
218 static Geometry::Class_info
219 multilinestring_class("MULTILINESTRING", "MultiLineString",
220 		      Geometry::wkb_multilinestring, create_multilinestring);
221 static Geometry::Class_info multipolygon_class("MULTIPOLYGON", "MultiPolygon",
222 						   Geometry::wkb_multipolygon,
223 						   create_multipolygon);
224 static Geometry::Class_info
225 geometrycollection_class("GEOMETRYCOLLECTION", "GeometryCollection",
226                          Geometry::wkb_geometrycollection,
227 			 create_geometrycollection);
228 
get_point(double * x,double * y,const char * data)229 static void get_point(double *x, double *y, const char *data)
230 {
231   float8get(*x, data);
232   float8get(*y, data + SIZEOF_STORED_DOUBLE);
233 }
234 
235 /***************************** Geometry *******************************/
236 
find_class(const char * name,size_t len)237 Geometry::Class_info *Geometry::find_class(const char *name, size_t len)
238 {
239   for (Class_info **cur_rt= ci_collection;
240        cur_rt < ci_collection_end; cur_rt++)
241   {
242     if (*cur_rt &&
243 	((*cur_rt)->m_name.length == len) &&
244 	(my_charset_latin1.strnncoll((*cur_rt)->m_name.str, len,
245 		                     name, len) == 0))
246       return *cur_rt;
247   }
248   return 0;
249 }
250 
251 
create_by_typeid(Geometry_buffer * buffer,int type_id)252 Geometry *Geometry::create_by_typeid(Geometry_buffer *buffer, int type_id)
253 {
254   Class_info *ci;
255   if (!(ci= find_class(type_id)))
256     return NULL;
257   return (*ci->m_create_func)(buffer->data);
258 }
259 
260 
construct(Geometry_buffer * buffer,const char * data,uint32 data_len)261 Geometry *Geometry::construct(Geometry_buffer *buffer,
262                               const char *data, uint32 data_len)
263 {
264   uint32 geom_type;
265   Geometry *result;
266 
267   if (data_len < SRID_SIZE + WKB_HEADER_SIZE)   // < 4 + (1 + 4)
268     return NULL;
269   /* + 1 to skip the byte order (stored in position SRID_SIZE). */
270   geom_type= uint4korr(data + SRID_SIZE + 1);
271   if (!(result= create_by_typeid(buffer, (int) geom_type)))
272     return NULL;
273   result->m_data= data+ SRID_SIZE + WKB_HEADER_SIZE;
274   result->m_data_end= data + data_len;
275   return result;
276 }
277 
278 
get_key_image_itMBR(LEX_CSTRING & src,uchar * buff,uint length)279 uint Geometry::get_key_image_itMBR(LEX_CSTRING &src, uchar *buff, uint length)
280 {
281   const char *dummy;
282   MBR mbr;
283   Geometry_buffer buffer;
284   Geometry *gobj;
285   const uint image_length= SIZEOF_STORED_DOUBLE*4;
286 
287   if (src.length < SRID_SIZE)
288   {
289     bzero(buff, image_length);
290     return image_length;
291   }
292   gobj= Geometry::construct(&buffer, (char*) src.str, (uint32) src.length);
293   if (!gobj || gobj->get_mbr(&mbr, &dummy))
294     bzero(buff, image_length);
295   else
296   {
297     float8store(buff,    mbr.xmin);
298     float8store(buff+8,  mbr.xmax);
299     float8store(buff+16, mbr.ymin);
300     float8store(buff+24, mbr.ymax);
301   }
302   return image_length;
303 }
304 
305 
create_from_wkt(Geometry_buffer * buffer,Gis_read_stream * trs,String * wkt,bool init_stream)306 Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer,
307 				    Gis_read_stream *trs, String *wkt,
308 				    bool init_stream)
309 {
310   LEX_STRING name;
311   Class_info *ci;
312   char next_sym;
313 
314   if (trs->get_next_word(&name))
315   {
316     trs->set_error_msg("Geometry name expected");
317     return NULL;
318   }
319   if (!(ci= find_class(name.str, name.length)) ||
320       wkt->reserve(1 + 4, 512))
321     return NULL;
322   Geometry *result= (*ci->m_create_func)(buffer->data);
323   wkt->q_append((char) wkb_ndr);
324   wkt->q_append((uint32) result->get_class_info()->m_type_id);
325   if (!(next_sym= trs->next_symbol()))
326     return NULL;
327   if (!(next_sym= trs->next_symbol()))
328     return NULL;
329   if ((next_sym == '(' && trs->check_next_symbol('(')) ||
330       result->init_from_wkt(trs, wkt) ||
331       (next_sym == '(' && trs->check_next_symbol(')')))
332     return NULL;
333   if (init_stream)
334   {
335     result->set_data_ptr(wkt->ptr(), wkt->length());
336     result->shift_wkb_header();
337   }
338   return result;
339 }
340 
341 
as_wkt(String * wkt,const char ** end)342 int Geometry::as_wkt(String *wkt, const char **end)
343 {
344   uint32 len= (uint) get_class_info()->m_name.length;
345   if (wkt->reserve(len + 2, 512))
346     return 1;
347   wkt->qs_append(get_class_info()->m_name.str, len);
348   if (get_class_info() != &geometrycollection_class)
349     wkt->qs_append('(');
350   if (get_data_as_wkt(wkt, end))
351     return 1;
352   if (get_class_info() != &geometrycollection_class)
353     wkt->qs_append(')');
354   return 0;
355 }
356 
357 
358 static const uchar type_keyname[]= "type";
359 static const uint type_keyname_len= 4;
360 static const uchar coord_keyname[]= "coordinates";
361 static const uint coord_keyname_len= 11;
362 static const uchar geometries_keyname[]= "geometries";
363 static const uint geometries_keyname_len= 10;
364 static const uchar features_keyname[]= "features";
365 static const uint features_keyname_len= 8;
366 static const uchar geometry_keyname[]= "geometry";
367 static const uint geometry_keyname_len= 8;
368 
369 static const uint max_keyname_len= 11; /*'coordinates' keyname is the longest.*/
370 
371 static const uchar feature_type[]= "feature";
372 static const int feature_type_len= 7;
373 static const uchar feature_coll_type[]= "featurecollection";
374 static const int feature_coll_type_len= 17;
375 static const uchar bbox_keyname[]= "bbox";
376 static const int bbox_keyname_len= 4;
377 
378 
as_json(String * wkt,uint max_dec_digits,const char ** end)379 int Geometry::as_json(String *wkt, uint max_dec_digits, const char **end)
380 {
381   uint32 len= (uint) get_class_info()->m_geojson_name.length;
382   if (wkt->reserve(4 + type_keyname_len + 2 + len + 2 + 2 +
383                    coord_keyname_len + 4, 512))
384     return 1;
385   wkt->qs_append("\"", 1);
386   wkt->qs_append((const char *) type_keyname, type_keyname_len);
387   wkt->qs_append("\": \"", 4);
388   wkt->qs_append(get_class_info()->m_geojson_name.str, len);
389   wkt->qs_append("\", \"", 4);
390   if (get_class_info() == &geometrycollection_class)
391     wkt->qs_append((const char *) geometries_keyname, geometries_keyname_len);
392   else
393     wkt->qs_append((const char *) coord_keyname, coord_keyname_len);
394 
395   wkt->qs_append("\": ", 3);
396   if (get_data_as_json(wkt, max_dec_digits, end))
397     return 1;
398 
399   return 0;
400 }
401 
402 
bbox_as_json(String * wkt)403 int Geometry::bbox_as_json(String *wkt)
404 {
405   MBR mbr;
406   const char *end;
407   if (wkt->reserve(5 + bbox_keyname_len + (FLOATING_POINT_DECIMALS+2)*4, 512))
408     return 1;
409   wkt->qs_append("\"", 1);
410   wkt->qs_append((const char *) bbox_keyname, bbox_keyname_len);
411   wkt->qs_append("\": [", 4);
412 
413   if (get_mbr(&mbr, &end))
414     return 1;
415 
416   wkt->qs_append(mbr.xmin);
417   wkt->qs_append(", ", 2);
418   wkt->qs_append(mbr.ymin);
419   wkt->qs_append(", ", 2);
420   wkt->qs_append(mbr.xmax);
421   wkt->qs_append(", ", 2);
422   wkt->qs_append(mbr.ymax);
423   wkt->qs_append("]", 1);
424 
425   return 0;
426 }
427 
428 
wkb_get_double(const char * ptr,Geometry::wkbByteOrder bo)429 static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo)
430 {
431   double res;
432   if (bo != Geometry::wkb_xdr)
433   {
434     float8get(res, ptr);
435   }
436   else
437   {
438     char inv_array[8];
439     inv_array[0]= ptr[7];
440     inv_array[1]= ptr[6];
441     inv_array[2]= ptr[5];
442     inv_array[3]= ptr[4];
443     inv_array[4]= ptr[3];
444     inv_array[5]= ptr[2];
445     inv_array[6]= ptr[1];
446     inv_array[7]= ptr[0];
447     float8get(res, inv_array);
448   }
449   return res;
450 }
451 
452 
wkb_get_uint(const char * ptr,Geometry::wkbByteOrder bo)453 static uint32 wkb_get_uint(const char *ptr, Geometry::wkbByteOrder bo)
454 {
455   if (bo != Geometry::wkb_xdr)
456     return uint4korr(ptr);
457   /* else */
458   {
459     char inv_array[4];
460     inv_array[0]= ptr[3];
461     inv_array[1]= ptr[2];
462     inv_array[2]= ptr[1];
463     inv_array[3]= ptr[0];
464     return uint4korr(inv_array);
465   }
466 }
467 
468 
create_from_wkb(Geometry_buffer * buffer,const char * wkb,uint32 len,String * res)469 Geometry *Geometry::create_from_wkb(Geometry_buffer *buffer,
470                                     const char *wkb, uint32 len, String *res)
471 {
472   uint32 geom_type;
473   Geometry *geom;
474 
475   if (len < WKB_HEADER_SIZE)
476     return NULL;
477   geom_type= wkb_get_uint(wkb+1, (wkbByteOrder)wkb[0]);
478   if (!(geom= create_by_typeid(buffer, (int) geom_type)) ||
479       res->reserve(WKB_HEADER_SIZE, 512))
480     return NULL;
481 
482   res->q_append((char) wkb_ndr);
483   res->q_append(geom_type);
484 
485   return geom->init_from_wkb(wkb + WKB_HEADER_SIZE, len - WKB_HEADER_SIZE,
486                              (wkbByteOrder) wkb[0], res) ? geom : NULL;
487 }
488 
489 
create_from_json(Geometry_buffer * buffer,json_engine_t * je,bool er_on_3D,String * res)490 Geometry *Geometry::create_from_json(Geometry_buffer *buffer,
491                       json_engine_t *je, bool er_on_3D, String *res)
492 {
493   Class_info *ci= NULL;
494   const uchar *coord_start= NULL, *geom_start= NULL,
495               *features_start= NULL, *geometry_start= NULL;
496   Geometry *result;
497   uchar key_buf[max_keyname_len];
498   uint key_len;
499   int fcoll_type_found= 0, feature_type_found= 0;
500 
501 
502   if (json_read_value(je))
503     goto err_return;
504 
505   if (je->value_type != JSON_VALUE_OBJECT)
506   {
507     je->s.error= GEOJ_INCORRECT_GEOJSON;
508     goto err_return;
509   }
510 
511   while (json_scan_next(je) == 0 && je->state != JST_OBJ_END)
512   {
513     DBUG_ASSERT(je->state == JST_KEY);
514 
515     key_len=0;
516     while (json_read_keyname_chr(je) == 0)
517     {
518       if (je->s.c_next > 127 || key_len >= max_keyname_len)
519       {
520         /* Symbol out of range, or keyname too long. No need to compare.. */
521         key_len=0;
522         break;
523       }
524       key_buf[key_len++]= (uchar)je->s.c_next | 0x20; /* make it lowercase. */
525     }
526 
527     if (unlikely(je->s.error))
528       goto err_return;
529 
530     if (key_len == type_keyname_len &&
531         memcmp(key_buf, type_keyname, type_keyname_len) == 0)
532     {
533       /*
534          Found the "type" key. Let's check it's a string and remember
535          the feature's type.
536       */
537       if (json_read_value(je))
538         goto err_return;
539 
540       if (je->value_type == JSON_VALUE_STRING)
541       {
542         if ((ci= find_class((const char *) je->value, je->value_len)))
543         {
544           if ((coord_start=
545                 (ci == &geometrycollection_class) ? geom_start : coord_start))
546             goto create_geom;
547         }
548         else if (je->value_len == feature_coll_type_len &&
549             my_charset_latin1.strnncoll(je->value, je->value_len,
550 		                        feature_coll_type, feature_coll_type_len) == 0)
551         {
552           /*
553             'FeatureCollection' type found. Handle the 'Featurecollection'/'features'
554             GeoJSON construction.
555           */
556           if (features_start)
557             goto handle_feature_collection;
558           fcoll_type_found= 1;
559         }
560         else if (je->value_len == feature_type_len &&
561                  my_charset_latin1.strnncoll(je->value, je->value_len,
562 		                             feature_type, feature_type_len) == 0)
563         {
564           if (geometry_start)
565             goto handle_geometry_key;
566           feature_type_found= 1;
567         }
568         else /* can't understand the type. */
569           break;
570       }
571       else /* The "type" value can only be string. */
572         break;
573     }
574     else if (key_len == coord_keyname_len &&
575              memcmp(key_buf, coord_keyname, coord_keyname_len) == 0)
576     {
577       /*
578         Found the "coordinates" key. Let's check it's an array
579         and remember where it starts.
580       */
581       if (json_read_value(je))
582         goto err_return;
583 
584       if (je->value_type == JSON_VALUE_ARRAY)
585       {
586         coord_start= je->value_begin;
587         if (ci && ci != &geometrycollection_class)
588           goto create_geom;
589         if (json_skip_level(je))
590           goto err_return;
591       }
592     }
593     else if (key_len == geometries_keyname_len &&
594              memcmp(key_buf, geometries_keyname, geometries_keyname_len) == 0)
595     {
596       /*
597         Found the "geometries" key. Let's check it's an array
598         and remember where it starts.
599       */
600       if (json_read_value(je))
601         goto err_return;
602 
603       if (je->value_type == JSON_VALUE_ARRAY)
604       {
605         geom_start= je->value_begin;
606         if (ci == &geometrycollection_class)
607         {
608           coord_start= geom_start;
609           goto create_geom;
610         }
611       }
612     }
613     else if (key_len == features_keyname_len &&
614              memcmp(key_buf, features_keyname, features_keyname_len) == 0)
615     {
616       /*
617         'features' key found. Handle the 'Featurecollection'/'features'
618         GeoJSON construction.
619       */
620       if (json_read_value(je))
621         goto err_return;
622       if (je->value_type == JSON_VALUE_ARRAY)
623       {
624         features_start= je->value_begin;
625         if (fcoll_type_found)
626           goto handle_feature_collection;
627       }
628     }
629     else if (key_len == geometry_keyname_len &&
630              memcmp(key_buf, geometry_keyname, geometry_keyname_len) == 0)
631     {
632       if (json_read_value(je))
633         goto err_return;
634       if (je->value_type == JSON_VALUE_OBJECT)
635       {
636         geometry_start= je->value_begin;
637         if (feature_type_found)
638           goto handle_geometry_key;
639       }
640       goto err_return;
641     }
642     else
643     {
644       if (json_skip_key(je))
645         goto err_return;
646     }
647   }
648 
649   if (je->s.error == 0)
650   {
651     /*
652       We didn't find all the required keys. That are "type" and "coordinates"
653       or "geometries" for GeometryCollection.
654     */
655     je->s.error= GEOJ_INCORRECT_GEOJSON;
656   }
657   goto err_return;
658 
659 handle_feature_collection:
660   ci= &geometrycollection_class;
661   coord_start= features_start;
662 
663 create_geom:
664 
665   json_scan_start(je, je->s.cs, coord_start, je->s.str_end);
666 
667   if (res->reserve(1 + 4, 512))
668     goto err_return;
669 
670   result= (*ci->m_create_func)(buffer->data);
671   res->q_append((char) wkb_ndr);
672   res->q_append((uint32) result->get_class_info()->m_type_id);
673   if (result->init_from_json(je, er_on_3D, res))
674     goto err_return;
675 
676   return result;
677 
678 handle_geometry_key:
679   json_scan_start(je, je->s.cs, geometry_start, je->s.str_end);
680   return create_from_json(buffer, je, er_on_3D, res);
681 
682 err_return:
683   return NULL;
684 }
685 
686 
create_from_opresult(Geometry_buffer * g_buf,String * res,Gcalc_result_receiver & rr)687 Geometry *Geometry::create_from_opresult(Geometry_buffer *g_buf,
688                                    String *res, Gcalc_result_receiver &rr)
689 {
690   uint32 geom_type= rr.get_result_typeid();
691   Geometry *obj= create_by_typeid(g_buf, geom_type);
692 
693   if (!obj || res->reserve(WKB_HEADER_SIZE, 512))
694     return NULL;
695 
696   res->q_append((char) wkb_ndr);
697   res->q_append(geom_type);
698   return obj->init_from_opresult(res, rr.result(), rr.length()) ? obj : NULL;
699 }
700 
701 
envelope(String * result) const702 bool Geometry::envelope(String *result) const
703 {
704   MBR mbr;
705   const char *end;
706 
707   if (get_mbr(&mbr, &end))
708     return 1;
709 
710   if (!mbr.valid())
711   {
712     /* Empty geometry */
713     if (result->reserve(1 + 4*2))
714       return 1;
715     result->q_append((char) wkb_ndr);
716     result->q_append((uint32) wkb_geometrycollection);
717     result->q_append((uint32) 0);
718     return 0;
719   }
720   if (result->reserve(1 + 4 * 3 + SIZEOF_STORED_DOUBLE * 10))
721     return 1;
722 
723   result->q_append((char) wkb_ndr);
724   result->q_append((uint32) wkb_polygon);
725   result->q_append((uint32) 1);
726   result->q_append((uint32) 5);
727   result->q_append(mbr.xmin);
728   result->q_append(mbr.ymin);
729   result->q_append(mbr.xmax);
730   result->q_append(mbr.ymin);
731   result->q_append(mbr.xmax);
732   result->q_append(mbr.ymax);
733   result->q_append(mbr.xmin);
734   result->q_append(mbr.ymax);
735   result->q_append(mbr.xmin);
736   result->q_append(mbr.ymin);
737 
738   return 0;
739 }
740 
741 
742 /*
743   Create a point from data.
744 
745   SYNPOSIS
746     create_point()
747     result		Put result here
748     data		Data for point is here.
749 
750   RETURN
751     0	ok
752     1	Can't reallocate 'result'
753 */
754 
create_point(String * result,const char * data) const755 bool Geometry::create_point(String *result, const char *data) const
756 {
757   if (no_data(data, POINT_DATA_SIZE) ||
758       result->reserve(1 + 4 + POINT_DATA_SIZE))
759     return 1;
760   result->q_append((char) wkb_ndr);
761   result->q_append((uint32) wkb_point);
762   /* Copy two double in same format */
763   result->q_append(data, POINT_DATA_SIZE);
764   return 0;
765 }
766 
767 /*
768   Create a point from coordinates.
769 
770   SYNPOSIS
771     create_point()
772     result		Put result here
773     x			x coordinate for point
774     y			y coordinate for point
775 
776   RETURN
777     0	ok
778     1	Can't reallocate 'result'
779 */
780 
create_point(String * result,double x,double y)781 bool Geometry::create_point(String *result, double x, double y)
782 {
783   if (result->reserve(1 + 4 + POINT_DATA_SIZE))
784     return 1;
785 
786   result->q_append((char) wkb_ndr);
787   result->q_append((uint32) wkb_point);
788   result->q_append(x);
789   result->q_append(y);
790   return 0;
791 }
792 
793 /*
794   Append N points from packed format to text
795 
796   SYNOPSIS
797     append_points()
798     txt			Append points here
799     n_points		Number of points
800     data		Packed data
801     offset		Offset between points
802 
803   RETURN
804     # end of data
805 */
806 
append_points(String * txt,uint32 n_points,const char * data,uint32 offset) const807 const char *Geometry::append_points(String *txt, uint32 n_points,
808 				    const char *data, uint32 offset) const
809 {
810   while (n_points--)
811   {
812     double x,y;
813     data+= offset;
814     get_point(&x, &y, data);
815     data+= POINT_DATA_SIZE;
816     txt->qs_append(x);
817     txt->qs_append(' ');
818     txt->qs_append(y);
819     txt->qs_append(',');
820   }
821   return data;
822 }
823 
824 
append_json_point(String * txt,uint max_dec,const char * data)825 static void append_json_point(String *txt, uint max_dec, const char *data)
826 {
827   double x,y;
828   get_point(&x, &y, data);
829   if (max_dec < FLOATING_POINT_DECIMALS)
830   {
831     x= my_double_round(x, max_dec, FALSE, FALSE);
832     y= my_double_round(y, max_dec, FALSE, FALSE);
833   }
834   txt->qs_append('[');
835   txt->qs_append(x);
836   txt->qs_append(", ", 2);
837   txt->qs_append(y);
838   txt->qs_append(']');
839 }
840 
841 
842 /*
843   Append N points from packed format to json
844 
845   SYNOPSIS
846     append_json_points()
847     txt			Append points here
848     n_points		Number of points
849     data		Packed data
850     offset		Offset between points
851 
852   RETURN
853     # end of data
854 */
855 
append_json_points(String * txt,uint max_dec,uint32 n_points,const char * data,uint32 offset)856 static const char *append_json_points(String *txt, uint max_dec,
857     uint32 n_points, const char *data, uint32 offset)
858 {
859   txt->qs_append('[');
860   while (n_points--)
861   {
862     data+= offset;
863     append_json_point(txt, max_dec, data);
864     data+= POINT_DATA_SIZE;
865     txt->qs_append(", ", 2);
866   }
867   txt->length(txt->length() - 2);// Remove ending ', '
868   txt->qs_append(']');
869   return data;
870 }
871 /*
872   Get most bounding rectangle (mbr) for X points
873 
874   SYNOPSIS
875     get_mbr_for_points()
876     mbr			MBR (store rectangle here)
877     points		Number of points
878     data		Packed data
879     offset		Offset between points
880 
881   RETURN
882     0	Wrong data
883     #	end of data
884 */
885 
get_mbr_for_points(MBR * mbr,const char * data,uint offset) const886 const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data,
887 					 uint offset) const
888 {
889   uint32 points;
890   /* read number of points */
891   if (no_data(data, 4))
892     return 0;
893   points= uint4korr(data);
894   data+= 4;
895 
896   if (not_enough_points(data, points, offset))
897     return 0;
898 
899   /* Calculate MBR for points */
900   while (points--)
901   {
902     data+= offset;
903     mbr->add_xy(data, data + SIZEOF_STORED_DOUBLE);
904     data+= POINT_DATA_SIZE;
905   }
906   return data;
907 }
908 
909 
910 /***************************** Point *******************************/
911 
get_data_size() const912 uint32 Gis_point::get_data_size() const
913 {
914   return POINT_DATA_SIZE;
915 }
916 
917 
init_from_wkt(Gis_read_stream * trs,String * wkb)918 bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
919 {
920   double x, y;
921   if (trs->get_next_number(&x) || trs->get_next_number(&y) ||
922       wkb->reserve(POINT_DATA_SIZE, 512))
923     return 1;
924   wkb->q_append(x);
925   wkb->q_append(y);
926   return 0;
927 }
928 
929 
init_from_wkb(const char * wkb,uint len,wkbByteOrder bo,String * res)930 uint Gis_point::init_from_wkb(const char *wkb, uint len,
931                               wkbByteOrder bo, String *res)
932 {
933   double x, y;
934   if (len < POINT_DATA_SIZE || res->reserve(POINT_DATA_SIZE))
935     return 0;
936   x= wkb_get_double(wkb, bo);
937   y= wkb_get_double(wkb + SIZEOF_STORED_DOUBLE, bo);
938   res->q_append(x);
939   res->q_append(y);
940   return POINT_DATA_SIZE;
941 }
942 
943 
read_point_from_json(json_engine_t * je,bool er_on_3D,double * x,double * y)944 static int read_point_from_json(json_engine_t *je, bool er_on_3D,
945                                 double *x, double *y)
946 {
947   int n_coord= 0, err;
948   double tmp, *d;
949   char *endptr;
950 
951   while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
952   {
953     DBUG_ASSERT(je->state == JST_VALUE);
954     if (json_read_value(je))
955       return 1;
956 
957     if (je->value_type != JSON_VALUE_NUMBER)
958       goto bad_coordinates;
959 
960     d= (n_coord == 0) ? x : ((n_coord == 1) ? y : &tmp);
961     *d= je->s.cs->strntod((char *) je->value, je->value_len, &endptr, &err);
962     if (err)
963       goto bad_coordinates;
964     n_coord++;
965   }
966 
967   if (n_coord <= 2 || !er_on_3D)
968     return 0;
969   je->s.error= Geometry::GEOJ_DIMENSION_NOT_SUPPORTED;
970   return 1;
971 bad_coordinates:
972   je->s.error= Geometry::GEOJ_INCORRECT_GEOJSON;
973   return 1;
974 }
975 
976 
init_from_json(json_engine_t * je,bool er_on_3D,String * wkb)977 bool Gis_point::init_from_json(json_engine_t *je, bool er_on_3D, String *wkb)
978 {
979   double x, y;
980   if (json_read_value(je))
981     return TRUE;
982 
983   if (je->value_type != JSON_VALUE_ARRAY)
984   {
985     je->s.error= GEOJ_INCORRECT_GEOJSON;
986     return TRUE;
987   }
988 
989   if (read_point_from_json(je, er_on_3D, &x, &y) ||
990       wkb->reserve(POINT_DATA_SIZE))
991     return TRUE;
992 
993   wkb->q_append(x);
994   wkb->q_append(y);
995   return FALSE;
996 }
997 
998 
get_data_as_wkt(String * txt,const char ** end) const999 bool Gis_point::get_data_as_wkt(String *txt, const char **end) const
1000 {
1001   double x, y;
1002   if (get_xy(&x, &y))
1003     return 1;
1004   if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 1))
1005     return 1;
1006   txt->qs_append(x);
1007   txt->qs_append(' ');
1008   txt->qs_append(y);
1009   *end= m_data+ POINT_DATA_SIZE;
1010   return 0;
1011 }
1012 
1013 
get_data_as_json(String * txt,uint max_dec_digits,const char ** end) const1014 bool Gis_point::get_data_as_json(String *txt, uint max_dec_digits,
1015                                  const char **end) const
1016 {
1017   if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 4))
1018     return 1;
1019   append_json_point(txt, max_dec_digits, m_data);
1020   *end= m_data+ POINT_DATA_SIZE;
1021   return 0;
1022 }
1023 
1024 
get_mbr(MBR * mbr,const char ** end) const1025 bool Gis_point::get_mbr(MBR *mbr, const char **end) const
1026 {
1027   double x, y;
1028   if (get_xy(&x, &y))
1029     return 1;
1030   mbr->add_xy(x, y);
1031   *end= m_data+ POINT_DATA_SIZE;
1032   return 0;
1033 }
1034 
1035 
area(double * ar,const char ** end) const1036 int Gis_point::area(double *ar, const char **end) const
1037 {
1038   *ar= 0;
1039   *end= m_data+ POINT_DATA_SIZE;
1040   return 0;
1041 }
1042 
1043 
geom_length(double * len,const char ** end) const1044 int Gis_point::geom_length(double *len, const char **end) const
1045 {
1046   *len= 0;
1047   *end= m_data+ POINT_DATA_SIZE;
1048   return 0;
1049 }
1050 
1051 
store_shapes(Gcalc_shape_transporter * trn) const1052 int Gis_point::store_shapes(Gcalc_shape_transporter *trn) const
1053 {
1054   double x, y;
1055 
1056   return get_xy(&x, &y) || trn->single_point(x, y);
1057 }
1058 
1059 
get_class_info() const1060 const Geometry::Class_info *Gis_point::get_class_info() const
1061 {
1062   return &point_class;
1063 }
1064 
1065 
1066 /**
1067   Function to calculate haversine.
1068   Taking as arguments Point and Multipoint geometries.
1069   Multipoint geometry has to be single point only.
1070   It is up to caller to ensure valid input.
1071 
1072   @param    g      pointer to the Geometry
1073   @param    r      sphere radius
1074   @param    error  pointer describing the error in case of the boundary conditions
1075 
1076   @return distance in case without error, it is caclulcated distance (non-negative),
1077                    in case error exist, negative value.
1078 */
calculate_haversine(const Geometry * g,const double sphere_radius,int * error)1079 double Gis_point::calculate_haversine(const Geometry *g,
1080                                       const double sphere_radius,
1081                                       int *error)
1082 {
1083   DBUG_ASSERT(sphere_radius > 0);
1084   double x1r, x2r, y1r, y2r;
1085 
1086   // This check is done only for optimization purposes where we know it will
1087   // be one and only one point in Multipoint
1088   if (g->get_class_info()->m_type_id == Geometry::wkb_multipoint)
1089   {
1090     const char point_size= 4 + WKB_HEADER_SIZE + POINT_DATA_SIZE+1; //1 for the type
1091     char point_temp[point_size];
1092     memset(point_temp+4, Geometry::wkb_point, 1);
1093     memcpy(point_temp+5, static_cast<const Gis_multi_point *>(g)->get_data_ptr()+5, 4);
1094     memcpy(point_temp+4+WKB_HEADER_SIZE, g->get_data_ptr()+4+WKB_HEADER_SIZE,
1095            POINT_DATA_SIZE);
1096     point_temp[point_size-1]= '\0';
1097     Geometry_buffer gbuff;
1098     Geometry *gg= Geometry::construct(&gbuff, point_temp, point_size-1);
1099     DBUG_ASSERT(gg);
1100     if (static_cast<Gis_point *>(gg)->get_xy_radian(&x2r, &y2r))
1101     {
1102       DBUG_ASSERT(0);
1103       return -1;
1104     }
1105   }
1106   else
1107   {
1108     if (static_cast<const Gis_point *>(g)->get_xy_radian(&x2r, &y2r))
1109     {
1110       DBUG_ASSERT(0);
1111       return -1;
1112     }
1113   }
1114   if (this->get_xy_radian(&x1r, &y1r))
1115   {
1116     DBUG_ASSERT(0);
1117     return -1;
1118   }
1119   // Check boundary conditions: longitude[-180,180]
1120   if (!((x2r >= -M_PI && x2r <= M_PI) && (x1r >= -M_PI && x1r <= M_PI)))
1121   {
1122     *error=1;
1123     return -1;
1124   }
1125   // Check boundary conditions: latitude[-90,90]
1126   if (!((y2r >= -M_PI/2 && y2r <= M_PI/2) && (y1r >= -M_PI/2 && y1r <= M_PI/2)))
1127   {
1128     *error=-1;
1129     return -1;
1130   }
1131   double dlat= sin((y2r - y1r)/2)*sin((y2r - y1r)/2);
1132   double dlong= sin((x2r - x1r)/2)*sin((x2r - x1r)/2);
1133   return 2*sphere_radius*asin((sqrt(dlat + cos(y1r)*cos(y2r)*dlong)));
1134 }
1135 
1136 
1137 /**
1138   Function that calculate spherical distance of Point from Multipoint geometries.
1139   In case there is single point in Multipoint geometries calculate_haversine()
1140   can handle such case. Otherwise, new geometry (Point) has to be constructed.
1141 
1142   @param    g pointer to the Geometry
1143   @param    r sphere radius
1144   @param    result pointer to the result
1145   @param    err    pointer to the error obtained from calculate_haversin()
1146 
1147   @return state
1148   @retval TRUE  failed
1149   @retval FALSE success
1150 */
spherical_distance_multipoints(Geometry * g,const double r,double * result,int * err)1151 int Gis_point::spherical_distance_multipoints(Geometry *g, const double r,
1152                                               double *result, int *err)
1153 {
1154   uint32 num_of_points2;
1155     // To find the minimum radius it cannot be greater than Earth radius
1156   double res= 6370986.0;
1157   double temp_res= 0.0;
1158   const uint32 len= 4 + WKB_HEADER_SIZE + POINT_DATA_SIZE + 1;
1159   char s[len];
1160   g->num_geometries(&num_of_points2);
1161   DBUG_ASSERT(num_of_points2 >= 1);
1162   if (num_of_points2 == 1)
1163   {
1164     *result= this->calculate_haversine(g, r, err);
1165     return 0;
1166   }
1167   for (uint32 i=1; i <= num_of_points2; i++)
1168   {
1169     Geometry_buffer buff_temp;
1170     Geometry *temp;
1171 
1172     // First 4 bytes are handled already, make sure to create a Point
1173     memset(s + 4, Geometry::wkb_point, 1);
1174     memcpy(s + 5, g->get_data_ptr() + 5, 4);
1175     memcpy(s + 4 + WKB_HEADER_SIZE, g->get_data_ptr() + 4 + WKB_HEADER_SIZE*i +\
1176                                     POINT_DATA_SIZE*(i-1), POINT_DATA_SIZE);
1177     s[len-1]= '\0';
1178     temp= Geometry::construct(&buff_temp, s, len);
1179     DBUG_ASSERT(temp);
1180     temp_res= this->calculate_haversine(temp, r, err);
1181     if (res > temp_res)
1182       res= temp_res;
1183   }
1184   *result= res;
1185   return 0;
1186 }
1187 /***************************** LineString *******************************/
1188 
get_data_size() const1189 uint32 Gis_line_string::get_data_size() const
1190 {
1191   uint32 n_points;
1192   if (no_data(m_data, 4))
1193     return GET_SIZE_ERROR;
1194 
1195   n_points= uint4korr(m_data);
1196 
1197   if (not_enough_points(m_data + 4, n_points))
1198     return GET_SIZE_ERROR;
1199 
1200   return 4 + n_points * POINT_DATA_SIZE;
1201 }
1202 
1203 
init_from_wkt(Gis_read_stream * trs,String * wkb)1204 bool Gis_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
1205 {
1206   uint32 n_points= 0;
1207   uint32 np_pos= wkb->length();
1208   Gis_point p;
1209 
1210   if (wkb->reserve(4, 512))
1211     return 1;
1212   wkb->length(wkb->length()+4);			// Reserve space for points
1213 
1214   for (;;)
1215   {
1216     if (p.init_from_wkt(trs, wkb))
1217       return 1;
1218     n_points++;
1219     if (trs->skip_char(','))			// Didn't find ','
1220       break;
1221   }
1222   if (n_points < 1)
1223   {
1224     trs->set_error_msg("Too few points in LINESTRING");
1225     return 1;
1226   }
1227   wkb->write_at_position(np_pos, n_points);
1228   return 0;
1229 }
1230 
1231 
init_from_wkb(const char * wkb,uint len,wkbByteOrder bo,String * res)1232 uint Gis_line_string::init_from_wkb(const char *wkb, uint len,
1233                                     wkbByteOrder bo, String *res)
1234 {
1235   uint32 n_points, proper_length;
1236   const char *wkb_end;
1237   Gis_point p;
1238 
1239   if (len < 4 || (n_points= wkb_get_uint(wkb, bo)) < 1 ||
1240       ((len - 4) / POINT_DATA_SIZE) < n_points)
1241     return 0;
1242   proper_length= 4 + n_points * POINT_DATA_SIZE;
1243 
1244   if (len < proper_length || res->reserve(proper_length))
1245     return 0;
1246 
1247   res->q_append(n_points);
1248   wkb_end= wkb + proper_length;
1249   for (wkb+= 4; wkb<wkb_end; wkb+= POINT_DATA_SIZE)
1250   {
1251     if (!p.init_from_wkb(wkb, POINT_DATA_SIZE, bo, res))
1252       return 0;
1253   }
1254 
1255   return proper_length;
1256 }
1257 
1258 
init_from_json(json_engine_t * je,bool er_on_3D,String * wkb)1259 bool Gis_line_string::init_from_json(json_engine_t *je, bool er_on_3D,
1260                                      String *wkb)
1261 {
1262   uint32 n_points= 0;
1263   uint32 np_pos= wkb->length();
1264   Gis_point p;
1265 
1266   if (json_read_value(je))
1267     return TRUE;
1268 
1269   if (je->value_type != JSON_VALUE_ARRAY)
1270   {
1271     je->s.error= GEOJ_INCORRECT_GEOJSON;
1272     return TRUE;
1273   }
1274 
1275   if (wkb->reserve(4, 512))
1276     return TRUE;
1277   wkb->length(wkb->length()+4);	// Reserve space for n_points
1278 
1279   while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
1280   {
1281     DBUG_ASSERT(je->state == JST_VALUE);
1282 
1283     if (p.init_from_json(je, er_on_3D, wkb))
1284       return TRUE;
1285     n_points++;
1286   }
1287   if (n_points < 1)
1288   {
1289     je->s.error= Geometry::GEOJ_TOO_FEW_POINTS;
1290     return TRUE;
1291   }
1292   wkb->write_at_position(np_pos, n_points);
1293   return FALSE;
1294 }
1295 
1296 
get_data_as_wkt(String * txt,const char ** end) const1297 bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const
1298 {
1299   uint32 n_points;
1300   const char *data= m_data;
1301 
1302   if (no_data(data, 4))
1303     return 1;
1304   n_points= uint4korr(data);
1305   data += 4;
1306 
1307   if (n_points < 1 ||
1308       not_enough_points(data, n_points) ||
1309       txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
1310     return 1;
1311 
1312   while (n_points--)
1313   {
1314     double x, y;
1315     get_point(&x, &y, data);
1316     data+= POINT_DATA_SIZE;
1317     txt->qs_append(x);
1318     txt->qs_append(' ');
1319     txt->qs_append(y);
1320     txt->qs_append(',');
1321   }
1322   txt->length(txt->length() - 1);		// Remove end ','
1323   *end= data;
1324   return 0;
1325 }
1326 
1327 
get_data_as_json(String * txt,uint max_dec_digits,const char ** end) const1328 bool Gis_line_string::get_data_as_json(String *txt, uint max_dec_digits,
1329                                        const char **end) const
1330 {
1331   uint32 n_points;
1332   const char *data= m_data;
1333 
1334   if (no_data(data, 4))
1335     return 1;
1336   n_points= uint4korr(data);
1337   data += 4;
1338 
1339   if (n_points < 1 ||
1340       not_enough_points(data, n_points) ||
1341       txt->reserve((MAX_DIGITS_IN_DOUBLE*2 + 6) * n_points + 2))
1342     return 1;
1343 
1344   *end= append_json_points(txt, max_dec_digits, n_points, data, 0);
1345 
1346   return 0;
1347 }
1348 
1349 
get_mbr(MBR * mbr,const char ** end) const1350 bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const
1351 {
1352   return (*end=get_mbr_for_points(mbr, m_data, 0)) == 0;
1353 }
1354 
1355 
geom_length(double * len,const char ** end) const1356 int Gis_line_string::geom_length(double *len, const char **end) const
1357 {
1358   uint32 n_points;
1359   double prev_x, prev_y;
1360   const char *data= m_data;
1361 
1362   *len= 0;					// In case of errors
1363   if (no_data(data, 4))
1364     return 1;
1365   n_points= uint4korr(data);
1366   data+= 4;
1367   if (n_points < 1 || not_enough_points(data, n_points))
1368     return 1;
1369 
1370   get_point(&prev_x, &prev_y, data);
1371   data+= POINT_DATA_SIZE;
1372   while (--n_points)
1373   {
1374     double x, y;
1375     get_point(&x, &y, data);
1376     data+= POINT_DATA_SIZE;
1377     *len+= sqrt(pow(prev_x-x,2)+pow(prev_y-y,2));
1378     prev_x= x;
1379     prev_y= y;
1380   }
1381   *end= data;
1382   return 0;
1383 }
1384 
1385 
area(double * ar,const char ** end) const1386 int Gis_line_string::area(double *ar, const char **end) const
1387 {
1388   uint32 n_points;
1389   *ar= 0.0;
1390 
1391   /* read number of points */
1392   if (no_data(m_data, 4))
1393     return 1;
1394   n_points= uint4korr(m_data);
1395   *end= m_data + 4 + POINT_DATA_SIZE * n_points;
1396   return 0;
1397 }
1398 
1399 
is_closed(int * closed) const1400 int Gis_line_string::is_closed(int *closed) const
1401 {
1402   uint32 n_points;
1403   double x1, y1, x2, y2;
1404   const char *data= m_data;
1405 
1406   if (no_data(data, 4))
1407     return 1;
1408   n_points= uint4korr(data);
1409   if (n_points == 1)
1410   {
1411     *closed=1;
1412     return 0;
1413   }
1414   data+= 4;
1415   if (n_points == 0 || not_enough_points(data, n_points))
1416     return 1;
1417 
1418   /* Get first point */
1419   get_point(&x1, &y1, data);
1420 
1421   /* get last point */
1422   data+= POINT_DATA_SIZE + (n_points-2)*POINT_DATA_SIZE;
1423   get_point(&x2, &y2, data);
1424 
1425   *closed= (x1==x2) && (y1==y2);
1426   return 0;
1427 }
1428 
1429 
num_points(uint32 * n_points) const1430 int Gis_line_string::num_points(uint32 *n_points) const
1431 {
1432   *n_points= uint4korr(m_data);
1433   return 0;
1434 }
1435 
1436 
start_point(String * result) const1437 int Gis_line_string::start_point(String *result) const
1438 {
1439   /* +4 is for skipping over number of points */
1440   return create_point(result, m_data + 4);
1441 }
1442 
1443 
end_point(String * result) const1444 int Gis_line_string::end_point(String *result) const
1445 {
1446   uint32 n_points;
1447   if (no_data(m_data, 4))
1448     return 1;
1449   n_points= uint4korr(m_data);
1450   if (n_points == 0 || not_enough_points(m_data+4, n_points))
1451     return 1;
1452   return create_point(result, m_data + 4 + (n_points - 1) * POINT_DATA_SIZE);
1453 }
1454 
1455 
point_n(uint32 num,String * result) const1456 int Gis_line_string::point_n(uint32 num, String *result) const
1457 {
1458   uint32 n_points;
1459   if (no_data(m_data, 4))
1460     return 1;
1461   num--;
1462   n_points= uint4korr(m_data);
1463   if (num >= n_points || not_enough_points(m_data+4, n_points))
1464     return 1;
1465 
1466   return create_point(result, m_data + 4 + num*POINT_DATA_SIZE);
1467 }
1468 
1469 
store_shapes(Gcalc_shape_transporter * trn) const1470 int Gis_line_string::store_shapes(Gcalc_shape_transporter *trn) const
1471 {
1472   uint32 n_points;
1473   double x, y;
1474   double UNINIT_VAR(prev_x), UNINIT_VAR(prev_y);
1475   int first_point= 1;
1476   const char *data= m_data;
1477 
1478   if (no_data(m_data, 4))
1479     return 1;
1480   n_points= uint4korr(data);
1481   data+= 4;
1482   if (n_points < 1 || not_enough_points(data, n_points))
1483     return 1;
1484 
1485   trn->start_line();
1486 
1487   while (n_points--)
1488   {
1489     get_point(&x, &y, data);
1490     data+= POINT_DATA_SIZE;
1491     if (!first_point && x == prev_x && y == prev_y)
1492       continue;
1493     if (trn->add_point(x, y))
1494       return 1;
1495     first_point= 0;
1496     prev_x= x;
1497     prev_y= y;
1498   }
1499 
1500   return trn->complete_line();
1501 }
1502 
get_class_info() const1503 const Geometry::Class_info *Gis_line_string::get_class_info() const
1504 {
1505   return &linestring_class;
1506 }
1507 
1508 
1509 /***************************** Polygon *******************************/
1510 
get_data_size() const1511 uint32 Gis_polygon::get_data_size() const
1512 {
1513   uint32 n_linear_rings;
1514   uint32 n_points;
1515   const char *data= m_data;
1516 
1517   if (no_data(data, 4))
1518     return GET_SIZE_ERROR;
1519   n_linear_rings= uint4korr(data);
1520   data+= 4;
1521 
1522   while (n_linear_rings--)
1523   {
1524     if (no_data(data, 4) ||
1525         not_enough_points(data+4, n_points= uint4korr(data)))
1526       return GET_SIZE_ERROR;
1527     data+= 4 + n_points*POINT_DATA_SIZE;
1528   }
1529   if (no_data(data, 0))
1530     return GET_SIZE_ERROR;
1531   return (uint32) (data - m_data);
1532 }
1533 
1534 
init_from_wkt(Gis_read_stream * trs,String * wkb)1535 bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
1536 {
1537   uint32 n_linear_rings= 0;
1538   uint32 lr_pos= wkb->length();
1539   int closed;
1540 
1541   if (wkb->reserve(4, 512))
1542     return 1;
1543   wkb->length(wkb->length()+4);	// Reserve space for n_rings
1544   for (;;)
1545   {
1546     Gis_line_string ls;
1547     uint32 ls_pos=wkb->length();
1548     if (trs->check_next_symbol('(') ||
1549 	ls.init_from_wkt(trs, wkb) ||
1550 	trs->check_next_symbol(')'))
1551       return 1;
1552 
1553     ls.set_data_ptr(wkb->ptr() + ls_pos, wkb->length() - ls_pos);
1554     if (ls.is_closed(&closed) || !closed)
1555     {
1556       trs->set_error_msg("POLYGON's linear ring isn't closed");
1557       return 1;
1558     }
1559     n_linear_rings++;
1560     if (trs->skip_char(','))			// Didn't find ','
1561       break;
1562   }
1563   wkb->write_at_position(lr_pos, n_linear_rings);
1564   return 0;
1565 }
1566 
1567 
init_from_opresult(String * bin,const char * opres,uint res_len)1568 uint Gis_polygon::init_from_opresult(String *bin,
1569                                      const char *opres, uint res_len)
1570 {
1571   const char *opres_orig= opres;
1572   uint32 position= bin->length();
1573   uint32 poly_shapes= 0;
1574 
1575   if (bin->reserve(4, 512))
1576     return 0;
1577   bin->q_append(poly_shapes);
1578 
1579   while (opres_orig + res_len > opres)
1580   {
1581     uint32 n_points, proper_length;
1582     const char *op_end, *p1_position;
1583     Gis_point p;
1584     Gcalc_function::shape_type st;
1585 
1586     st= (Gcalc_function::shape_type) uint4korr(opres);
1587     if (poly_shapes && st != Gcalc_function::shape_hole)
1588       break;
1589     poly_shapes++;
1590     n_points= uint4korr(opres + 4) + 1; /* skip shape type id */
1591     proper_length= 4 + n_points * POINT_DATA_SIZE;
1592 
1593     if (bin->reserve(proper_length, 512))
1594       return 0;
1595 
1596     bin->q_append(n_points);
1597     op_end= opres + 8 + (n_points-1) * 8 * 2;
1598     p1_position= (opres+= 8);
1599     for (; opres<op_end; opres+= POINT_DATA_SIZE)
1600     {
1601       if (!p.init_from_wkb(opres, POINT_DATA_SIZE, wkb_ndr, bin))
1602         return 0;
1603     }
1604     if (!p.init_from_wkb(p1_position, POINT_DATA_SIZE, wkb_ndr, bin))
1605       return 0;
1606   }
1607 
1608   bin->write_at_position(position, poly_shapes);
1609 
1610   return (uint) (opres - opres_orig);
1611 }
1612 
1613 
init_from_wkb(const char * wkb,uint len,wkbByteOrder bo,String * res)1614 uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
1615                                 String *res)
1616 {
1617   uint32 n_linear_rings;
1618   const char *wkb_orig= wkb;
1619 
1620   if (len < 4)
1621     return 0;
1622 
1623   if (!(n_linear_rings= wkb_get_uint(wkb, bo)))
1624     return 0;
1625 
1626   if (res->reserve(4, 512))
1627     return 0;
1628   wkb+= 4;
1629   len-= 4;
1630   res->q_append(n_linear_rings);
1631 
1632   while (n_linear_rings--)
1633   {
1634     Gis_line_string ls;
1635     uint32 ls_pos= res->length();
1636     int ls_len;
1637     int closed;
1638 
1639     if (!(ls_len= ls.init_from_wkb(wkb, len, bo, res)))
1640       return 0;
1641 
1642     ls.set_data_ptr(res->ptr() + ls_pos, res->length() - ls_pos);
1643 
1644     if (ls.is_closed(&closed) || !closed)
1645       return 0;
1646     wkb+= ls_len;
1647   }
1648 
1649   return (uint) (wkb - wkb_orig);
1650 }
1651 
1652 
init_from_json(json_engine_t * je,bool er_on_3D,String * wkb)1653 bool Gis_polygon::init_from_json(json_engine_t *je, bool er_on_3D, String *wkb)
1654 {
1655   uint32 n_linear_rings= 0;
1656   uint32 lr_pos= wkb->length();
1657   int closed;
1658 
1659   if (json_read_value(je))
1660     return TRUE;
1661 
1662   if (je->value_type != JSON_VALUE_ARRAY)
1663   {
1664     je->s.error= GEOJ_INCORRECT_GEOJSON;
1665     return TRUE;
1666   }
1667 
1668   if (wkb->reserve(4, 512))
1669     return TRUE;
1670   wkb->length(wkb->length()+4);	// Reserve space for n_rings
1671 
1672   while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
1673   {
1674     Gis_line_string ls;
1675     DBUG_ASSERT(je->state == JST_VALUE);
1676 
1677     uint32 ls_pos=wkb->length();
1678     if (ls.init_from_json(je, er_on_3D, wkb))
1679       return TRUE;
1680     ls.set_data_ptr(wkb->ptr() + ls_pos, wkb->length() - ls_pos);
1681     if (ls.is_closed(&closed) || !closed)
1682     {
1683       je->s.error= GEOJ_POLYGON_NOT_CLOSED;
1684       return TRUE;
1685     }
1686     n_linear_rings++;
1687   }
1688 
1689   if (je->s.error)
1690     return TRUE;
1691 
1692   if (n_linear_rings == 0)
1693   {
1694     je->s.error= Geometry::GEOJ_EMPTY_COORDINATES;
1695     return TRUE;
1696   }
1697   wkb->write_at_position(lr_pos, n_linear_rings);
1698   return FALSE;
1699 }
1700 
1701 
get_data_as_wkt(String * txt,const char ** end) const1702 bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const
1703 {
1704   uint32 n_linear_rings;
1705   const char *data= m_data;
1706 
1707   if (no_data(data, 4))
1708     return 1;
1709 
1710   n_linear_rings= uint4korr(data);
1711   data+= 4;
1712 
1713   while (n_linear_rings--)
1714   {
1715     uint32 n_points;
1716     if (no_data(data, 4))
1717       return 1;
1718     n_points= uint4korr(data);
1719     data+= 4;
1720     if (not_enough_points(data, n_points) ||
1721 	txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
1722       return 1;
1723     txt->qs_append('(');
1724     data= append_points(txt, n_points, data, 0);
1725     (*txt) [txt->length() - 1]= ')';		// Replace end ','
1726     txt->qs_append(',');
1727   }
1728   txt->length(txt->length() - 1);		// Remove end ','
1729   *end= data;
1730   return 0;
1731 }
1732 
1733 
get_data_as_json(String * txt,uint max_dec_digits,const char ** end) const1734 bool Gis_polygon::get_data_as_json(String *txt, uint max_dec_digits,
1735                                    const char **end) const
1736 {
1737   uint32 n_linear_rings;
1738   const char *data= m_data;
1739 
1740   if (no_data(data, 4) || txt->reserve(1, 512))
1741     return 1;
1742 
1743   n_linear_rings= uint4korr(data);
1744   data+= 4;
1745 
1746   txt->qs_append('[');
1747   while (n_linear_rings--)
1748   {
1749     uint32 n_points;
1750     if (no_data(data, 4))
1751       return 1;
1752     n_points= uint4korr(data);
1753     data+= 4;
1754     if (not_enough_points(data, n_points) ||
1755 	txt->reserve(4 + (MAX_DIGITS_IN_DOUBLE * 2 + 6) * n_points))
1756       return 1;
1757     data= append_json_points(txt, max_dec_digits, n_points, data, 0);
1758     txt->qs_append(", ", 2);
1759   }
1760   txt->length(txt->length() - 2);// Remove ending ', '
1761   txt->qs_append(']');
1762   *end= data;
1763   return 0;
1764 }
1765 
1766 
get_mbr(MBR * mbr,const char ** end) const1767 bool Gis_polygon::get_mbr(MBR *mbr, const char **end) const
1768 {
1769   uint32 n_linear_rings;
1770   const char *data= m_data;
1771 
1772   if (no_data(data, 4))
1773     return 1;
1774   n_linear_rings= uint4korr(data);
1775   data+= 4;
1776 
1777   while (n_linear_rings--)
1778   {
1779     if (!(data= get_mbr_for_points(mbr, data, 0)))
1780       return 1;
1781   }
1782   *end= data;
1783   return 0;
1784 }
1785 
1786 
area(double * ar,const char ** end_of_data) const1787 int Gis_polygon::area(double *ar, const char **end_of_data) const
1788 {
1789   uint32 n_linear_rings;
1790   double result= -1.0;
1791   const char *data= m_data;
1792 
1793   if (no_data(data, 4))
1794     return 1;
1795   n_linear_rings= uint4korr(data);
1796   data+= 4;
1797 
1798   while (n_linear_rings--)
1799   {
1800     double prev_x, prev_y;
1801     double lr_area= 0;
1802     uint32 n_points;
1803 
1804     if (no_data(data, 4))
1805       return 1;
1806     n_points= uint4korr(data);
1807     if (n_points == 0 ||
1808         not_enough_points(data, n_points))
1809       return 1;
1810     get_point(&prev_x, &prev_y, data+4);
1811     data+= (4+POINT_DATA_SIZE);
1812 
1813     while (--n_points)				// One point is already read
1814     {
1815       double x, y;
1816       get_point(&x, &y, data);
1817       data+= POINT_DATA_SIZE;
1818       lr_area+= (prev_x + x)* (prev_y - y);
1819       prev_x= x;
1820       prev_y= y;
1821     }
1822     lr_area= fabs(lr_area)/2;
1823     if (result == -1.0)
1824       result= lr_area;
1825     else
1826       result-= lr_area;
1827   }
1828   *ar= fabs(result);
1829   *end_of_data= data;
1830   return 0;
1831 }
1832 
1833 
exterior_ring(String * result) const1834 int Gis_polygon::exterior_ring(String *result) const
1835 {
1836   uint32 n_points, length;
1837   const char *data= m_data + 4; // skip n_linerings
1838 
1839   if (no_data(data, 4))
1840     return 1;
1841   n_points= uint4korr(data);
1842   data+= 4;
1843   length= n_points * POINT_DATA_SIZE;
1844   if (not_enough_points(data, n_points) || result->reserve(1+4+4+ length))
1845     return 1;
1846 
1847   result->q_append((char) wkb_ndr);
1848   result->q_append((uint32) wkb_linestring);
1849   result->q_append(n_points);
1850   result->q_append(data, n_points * POINT_DATA_SIZE);
1851   return 0;
1852 }
1853 
1854 
num_interior_ring(uint32 * n_int_rings) const1855 int Gis_polygon::num_interior_ring(uint32 *n_int_rings) const
1856 {
1857   if (no_data(m_data, 4))
1858     return 1;
1859   *n_int_rings= uint4korr(m_data)-1;
1860   return 0;
1861 }
1862 
1863 
interior_ring_n(uint32 num,String * result) const1864 int Gis_polygon::interior_ring_n(uint32 num, String *result) const
1865 {
1866   const char *data= m_data;
1867   uint32 n_linear_rings;
1868   uint32 n_points;
1869   uint32 points_size;
1870 
1871   if (no_data(data, 4))
1872     return 1;
1873   n_linear_rings= uint4korr(data);
1874   data+= 4;
1875 
1876   if (num >= n_linear_rings || num < 1)
1877     return 1;
1878 
1879   while (num--)
1880   {
1881     if (no_data(data, 4))
1882       return 1;
1883     data+= 4 + uint4korr(data) * POINT_DATA_SIZE;
1884   }
1885   if (no_data(data, 4))
1886     return 1;
1887   n_points= uint4korr(data);
1888   points_size= n_points * POINT_DATA_SIZE;
1889   data+= 4;
1890   if (not_enough_points(data, n_points) || result->reserve(1+4+4+ points_size))
1891     return 1;
1892 
1893   result->q_append((char) wkb_ndr);
1894   result->q_append((uint32) wkb_linestring);
1895   result->q_append(n_points);
1896   result->q_append(data, points_size);
1897 
1898   return 0;
1899 }
1900 
1901 
centroid_xy(double * x,double * y) const1902 int Gis_polygon::centroid_xy(double *x, double *y) const
1903 {
1904   uint32 n_linear_rings;
1905   double UNINIT_VAR(res_area);
1906   double UNINIT_VAR(res_cx), UNINIT_VAR(res_cy);
1907   const char *data= m_data;
1908   bool first_loop= 1;
1909 
1910   if (no_data(data, 4) ||
1911       (n_linear_rings= uint4korr(data)) == 0)
1912     return 1;
1913   data+= 4;
1914 
1915   while (n_linear_rings--)
1916   {
1917     uint32 n_points, org_n_points;
1918     double prev_x, prev_y;
1919     double cur_area= 0;
1920     double cur_cx= 0, cur_cy= 0;
1921     double sum_cx= 0, sum_cy= 0;
1922 
1923     if (no_data(data, 4))
1924       return 1;
1925     org_n_points= n_points= uint4korr(data);
1926     data+= 4;
1927     if (n_points == 0 || not_enough_points(data, n_points))
1928       return 1;
1929     get_point(&prev_x, &prev_y, data);
1930     data+= POINT_DATA_SIZE;
1931 
1932     while (--n_points)				// One point is already read
1933     {
1934       double tmp_x, tmp_y;
1935       double loc_area;
1936       get_point(&tmp_x, &tmp_y, data);
1937       data+= POINT_DATA_SIZE;
1938       loc_area= prev_x * tmp_y - tmp_x * prev_y;
1939       cur_area+= loc_area;
1940       cur_cx+= tmp_x;
1941       cur_cy+= tmp_y;
1942       sum_cx+= (prev_x + tmp_x) * loc_area;
1943       sum_cy+= (prev_y + tmp_y) * loc_area;
1944 
1945       prev_x= tmp_x;
1946       prev_y= tmp_y;
1947     }
1948 
1949     if (fabs(cur_area) > 1e-10)
1950     {
1951       cur_cx= sum_cx / cur_area / 3.0;
1952       cur_cy= sum_cy / cur_area / 3.0;
1953     }
1954     else
1955     {
1956       cur_cx= cur_cx / (org_n_points - 1);
1957       cur_cy= cur_cy / (org_n_points - 1);
1958     }
1959 
1960     cur_area= fabs(cur_area);
1961 
1962     if (!first_loop)
1963     {
1964       double d_area= fabs(res_area - cur_area);
1965       res_cx= (res_area * res_cx - cur_area * cur_cx) / d_area;
1966       res_cy= (res_area * res_cy - cur_area * cur_cy) / d_area;
1967     }
1968     else
1969     {
1970       first_loop= 0;
1971       res_area= cur_area;
1972       res_cx= cur_cx;
1973       res_cy= cur_cy;
1974     }
1975   }
1976 
1977   *x= res_cx;
1978   *y= res_cy;
1979   return 0;
1980 }
1981 
1982 
centroid(String * result) const1983 int Gis_polygon::centroid(String *result) const
1984 {
1985   double x, y;
1986   if (centroid_xy(&x, &y))
1987     return 1;
1988   return create_point(result, x, y);
1989 }
1990 
1991 
store_shapes(Gcalc_shape_transporter * trn) const1992 int Gis_polygon::store_shapes(Gcalc_shape_transporter *trn) const
1993 {
1994   uint32 n_linear_rings;
1995   const char *data= m_data;
1996   double first_x, first_y;
1997   double prev_x, prev_y;
1998   int was_equal_first= 0;
1999 
2000   if (trn->start_poly())
2001     return 1;
2002 
2003   if (no_data(data, 4))
2004     return 1;
2005   n_linear_rings= uint4korr(data);
2006   data+= 4;
2007 
2008   while (n_linear_rings--)
2009   {
2010     uint32 n_points;
2011 
2012     if (no_data(data, 4))
2013       return 1;
2014     n_points= uint4korr(data);
2015     data+= 4;
2016     if (!n_points || not_enough_points(data, n_points))
2017       return 1;
2018 
2019     trn->start_ring();
2020     get_point(&first_x, &first_y, data);
2021     data+= POINT_DATA_SIZE;
2022 
2023     prev_x= first_x;
2024     prev_y= first_y;
2025     if (trn->add_point(first_x, first_y))
2026       return 1;
2027 
2028     if (--n_points == 0)
2029       goto single_point_ring;
2030 
2031     while (--n_points)
2032     {
2033       double x, y;
2034       get_point(&x, &y, data);
2035       data+= POINT_DATA_SIZE;
2036       if (x == prev_x && y == prev_y)
2037         continue;
2038       prev_x= x;
2039       prev_y= y;
2040       if (was_equal_first)
2041       {
2042         if (trn->add_point(first_x, first_y))
2043           return 1;
2044         was_equal_first= 0;
2045       }
2046       if (x == first_x && y == first_y)
2047       {
2048         was_equal_first= 1;
2049         continue;
2050       }
2051       if (trn->add_point(x, y))
2052         return 1;
2053     }
2054     data+= POINT_DATA_SIZE;
2055 
2056 single_point_ring:
2057     trn->complete_ring();
2058   }
2059 
2060   trn->complete_poly();
2061   return 0;
2062 }
2063 
2064 
get_class_info() const2065 const Geometry::Class_info *Gis_polygon::get_class_info() const
2066 {
2067   return &polygon_class;
2068 }
2069 
2070 
2071 /***************************** MultiPoint *******************************/
2072 
get_data_size() const2073 uint32 Gis_multi_point::get_data_size() const
2074 {
2075   uint32 n_points;
2076 
2077   if (no_data(m_data, 4) ||
2078       not_enough_points(m_data+4, (n_points= uint4korr(m_data)),
2079         WKB_HEADER_SIZE))
2080      return GET_SIZE_ERROR;
2081   return  4 + n_points * (POINT_DATA_SIZE + WKB_HEADER_SIZE);
2082 }
2083 
2084 
init_from_wkt(Gis_read_stream * trs,String * wkb)2085 bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
2086 {
2087   uint32 n_points= 0;
2088   uint32 np_pos= wkb->length();
2089   Gis_point p;
2090 
2091   if (wkb->reserve(4, 512))
2092     return 1;
2093   wkb->length(wkb->length()+4);			// Reserve space for points
2094 
2095   for (;;)
2096   {
2097     if (wkb->reserve(1 + 4, 512))
2098       return 1;
2099     wkb->q_append((char) wkb_ndr);
2100     wkb->q_append((uint32) wkb_point);
2101     if (p.init_from_wkt(trs, wkb))
2102       return 1;
2103     n_points++;
2104     if (trs->skip_char(','))			// Didn't find ','
2105       break;
2106   }
2107   wkb->write_at_position(np_pos, n_points);	// Store number of found points
2108   return 0;
2109 }
2110 
2111 
init_from_opresult(String * bin,const char * opres,uint res_len)2112 uint Gis_multi_point::init_from_opresult(String *bin,
2113                                          const char *opres, uint res_len)
2114 {
2115   uint bin_size, n_points;
2116   Gis_point p;
2117   const char *opres_end;
2118 
2119   n_points= res_len/(4+8*2);
2120   bin_size= n_points * (WKB_HEADER_SIZE + POINT_DATA_SIZE) + 4;
2121 
2122   if (bin->reserve(bin_size, 512))
2123     return 0;
2124 
2125   bin->q_append(n_points);
2126   opres_end= opres + res_len;
2127   for (; opres < opres_end; opres+= (4 + 8*2))
2128   {
2129     bin->q_append((char)wkb_ndr);
2130     bin->q_append((uint32)wkb_point);
2131     if (!p.init_from_wkb(opres + 4, POINT_DATA_SIZE, wkb_ndr, bin))
2132       return 0;
2133   }
2134   return res_len;
2135 }
2136 
2137 
init_from_wkb(const char * wkb,uint len,wkbByteOrder bo,String * res)2138 uint Gis_multi_point::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
2139                                     String *res)
2140 {
2141   uint32 n_points;
2142   uint proper_size;
2143   Gis_point p;
2144   const char *wkb_end;
2145 
2146   if (len < 4 ||
2147       (n_points= wkb_get_uint(wkb, bo)) > max_n_points)
2148     return 0;
2149   proper_size= 4 + n_points * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
2150 
2151   if (len < proper_size || res->reserve(proper_size))
2152     return 0;
2153 
2154   res->q_append(n_points);
2155   wkb_end= wkb + proper_size;
2156   for (wkb+=4; wkb < wkb_end; wkb+= (WKB_HEADER_SIZE + POINT_DATA_SIZE))
2157   {
2158     res->q_append((char)wkb_ndr);
2159     res->q_append((uint32)wkb_point);
2160     if (!p.init_from_wkb(wkb + WKB_HEADER_SIZE,
2161                          POINT_DATA_SIZE, (wkbByteOrder) wkb[0], res))
2162       return 0;
2163   }
2164   return proper_size;
2165 }
2166 
2167 
init_from_json(json_engine_t * je,bool er_on_3D,String * wkb)2168 bool Gis_multi_point::init_from_json(json_engine_t *je, bool er_on_3D,
2169                                      String *wkb)
2170 {
2171   uint32 n_points= 0;
2172   uint32 np_pos= wkb->length();
2173   Gis_point p;
2174 
2175   if (json_read_value(je))
2176     return TRUE;
2177 
2178   if (je->value_type != JSON_VALUE_ARRAY)
2179   {
2180     je->s.error= GEOJ_INCORRECT_GEOJSON;
2181     return TRUE;
2182   }
2183 
2184   if (wkb->reserve(4, 512))
2185     return TRUE;
2186   wkb->length(wkb->length()+4);	// Reserve space for n_points
2187 
2188   while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
2189   {
2190     DBUG_ASSERT(je->state == JST_VALUE);
2191 
2192     if (wkb->reserve(1 + 4, 512))
2193       return TRUE;
2194     wkb->q_append((char) wkb_ndr);
2195     wkb->q_append((uint32) wkb_point);
2196 
2197     if (p.init_from_json(je, er_on_3D, wkb))
2198       return TRUE;
2199     n_points++;
2200   }
2201 
2202   if (je->s.error)
2203     return TRUE;
2204 
2205   if (n_points == 0)
2206   {
2207     je->s.error= Geometry::GEOJ_EMPTY_COORDINATES;
2208     return TRUE;
2209   }
2210 
2211   wkb->write_at_position(np_pos, n_points);
2212   return FALSE;
2213 }
2214 
2215 
get_data_as_wkt(String * txt,const char ** end) const2216 bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const
2217 {
2218   uint32 n_points;
2219   if (no_data(m_data, 4))
2220     return 1;
2221 
2222   n_points= uint4korr(m_data);
2223   if (n_points > max_n_points ||
2224       not_enough_points(m_data+4, n_points, WKB_HEADER_SIZE) ||
2225       txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
2226     return 1;
2227   *end= append_points(txt, n_points, m_data+4, WKB_HEADER_SIZE);
2228   txt->length(txt->length()-1);			// Remove end ','
2229   return 0;
2230 }
2231 
2232 
get_data_as_json(String * txt,uint max_dec_digits,const char ** end) const2233 bool Gis_multi_point::get_data_as_json(String *txt, uint max_dec_digits,
2234                                        const char **end) const
2235 {
2236   uint32 n_points;
2237   if (no_data(m_data, 4))
2238     return 1;
2239 
2240   n_points= uint4korr(m_data);
2241   if (n_points > max_n_points ||
2242       not_enough_points(m_data+4, n_points, WKB_HEADER_SIZE) ||
2243       txt->reserve((MAX_DIGITS_IN_DOUBLE * 2 + 6) * n_points + 2))
2244     return 1;
2245   *end= append_json_points(txt, max_dec_digits, n_points, m_data+4,
2246                            WKB_HEADER_SIZE);
2247   return 0;
2248 }
2249 
2250 
get_mbr(MBR * mbr,const char ** end) const2251 bool Gis_multi_point::get_mbr(MBR *mbr, const char **end) const
2252 {
2253   return (*end= get_mbr_for_points(mbr, m_data, WKB_HEADER_SIZE)) == 0;
2254 }
2255 
2256 
num_geometries(uint32 * num) const2257 int Gis_multi_point::num_geometries(uint32 *num) const
2258 {
2259   *num= uint4korr(m_data);
2260   return 0;
2261 }
2262 
2263 
geometry_n(uint32 num,String * result) const2264 int Gis_multi_point::geometry_n(uint32 num, String *result) const
2265 {
2266   const char *data= m_data;
2267   uint32 n_points;
2268 
2269   if (no_data(data, 4))
2270     return 1;
2271   n_points= uint4korr(data);
2272   data+= 4+ (num - 1) * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
2273 
2274   if (num > n_points || num < 1 ||
2275       no_data(data, WKB_HEADER_SIZE + POINT_DATA_SIZE) ||
2276       result->reserve(WKB_HEADER_SIZE + POINT_DATA_SIZE))
2277     return 1;
2278 
2279   result->q_append(data, WKB_HEADER_SIZE + POINT_DATA_SIZE);
2280   return 0;
2281 }
2282 
2283 
store_shapes(Gcalc_shape_transporter * trn) const2284 int Gis_multi_point::store_shapes(Gcalc_shape_transporter *trn) const
2285 {
2286   uint32 n_points;
2287   Gis_point pt;
2288   const char *data= m_data;
2289 
2290   if (no_data(data, 4))
2291     return 1;
2292   n_points= uint4korr(data);
2293   data+= 4;
2294 
2295   if (trn->start_collection(n_points))
2296     return 1;
2297 
2298   while (n_points--)
2299   {
2300     if (no_data(data, WKB_HEADER_SIZE))
2301       return 1;
2302     data+= WKB_HEADER_SIZE;
2303     pt.set_data_ptr(data, (uint32) (m_data_end - data));
2304     if (pt.store_shapes(trn))
2305       return 1;
2306     data+= pt.get_data_size();
2307   }
2308   return 0;
2309 }
2310 
2311 
get_class_info() const2312 const Geometry::Class_info *Gis_multi_point::get_class_info() const
2313 {
2314   return &multipoint_class;
2315 }
2316 
2317 
2318 /**
2319   Function that calculate spherical distance of Multipoints geometries.
2320   In case there is single point in Multipoint geometries calculate_haversine()
2321   can handle such case. Otherwise, new geometry (Point) has to be constructed.
2322 
2323   @param    g pointer to the Geometry
2324   @param    r sphere radius
2325   @param    result pointer to the result
2326   @param    err    pointer to the error obtained from calculate_haversin()
2327 
2328   @return state
2329   @retval TRUE  failed
2330   @retval FALSE success
2331 */
spherical_distance_multipoints(Geometry * g,const double r,double * result,int * err)2332 int Gis_multi_point::spherical_distance_multipoints(Geometry *g, const double r,
2333                                                     double *result, int *err)
2334 {
2335   const uint32 len= 4 + WKB_HEADER_SIZE + POINT_DATA_SIZE + 1;
2336   // Check how many points are stored in Multipoints
2337   uint32 num_of_points1, num_of_points2;
2338   // To find the minimum radius it cannot be greater than Earth radius
2339   double res= 6370986.0;
2340 
2341   /* From Item_func_sphere_distance::spherical_distance_points,
2342      we are sure that there will be multiple points and we have to construct
2343      Point geometry and return the smallest result.
2344   */
2345   num_geometries(&num_of_points1);
2346   DBUG_ASSERT(num_of_points1 >= 1);
2347   g->num_geometries(&num_of_points2);
2348   DBUG_ASSERT(num_of_points2 >= 1);
2349 
2350   for (uint32 i=1; i <= num_of_points1; i++)
2351   {
2352     Geometry_buffer buff_temp;
2353     Geometry *temp;
2354     double temp_res= 0.0;
2355     char s[len];
2356     // First 4 bytes are handled already, make sure to create a Point
2357     memset(s + 4, Geometry::wkb_point, 1);
2358     memcpy(s + 5, this->get_data_ptr() + 5, 4);
2359     memcpy(s + 4 + WKB_HEADER_SIZE, this->get_data_ptr() + 4 + WKB_HEADER_SIZE*i +\
2360                                     POINT_DATA_SIZE*(i-1), POINT_DATA_SIZE);
2361     s[len-1]= '\0';
2362     temp= Geometry::construct(&buff_temp, s, len);
2363     DBUG_ASSERT(temp);
2364     // Optimization for single Multipoint
2365     if (num_of_points2 == 1)
2366     {
2367       *result= static_cast<Gis_point *>(temp)->calculate_haversine(g, r, err);
2368       return 0;
2369     }
2370     for (uint32 j=1; j<= num_of_points2; j++)
2371     {
2372       Geometry_buffer buff_temp2;
2373       Geometry *temp2;
2374       char s2[len];
2375       // First 4 bytes are handled already, make sure to create a Point
2376       memset(s2 + 4, Geometry::wkb_point, 1);
2377       memcpy(s2 + 5, g->get_data_ptr() + 5, 4);
2378       memcpy(s2 + 4 + WKB_HEADER_SIZE, g->get_data_ptr() + 4 + WKB_HEADER_SIZE*j +\
2379                                        POINT_DATA_SIZE*(j-1), POINT_DATA_SIZE);
2380       s2[len-1]= '\0';
2381       temp2= Geometry::construct(&buff_temp2, s2, len);
2382       DBUG_ASSERT(temp2);
2383       temp_res= static_cast<Gis_point *>(temp)->calculate_haversine(temp2, r, err);
2384       if (res > temp_res)
2385         res= temp_res;
2386     }
2387   }
2388   *result= res;
2389   return 0;
2390 }
2391 
2392 
2393 /***************************** MultiLineString *******************************/
2394 
get_data_size() const2395 uint32 Gis_multi_line_string::get_data_size() const
2396 {
2397   uint32 n_line_strings;
2398   uint32 n_points;
2399   const char *data= m_data;
2400 
2401   if (no_data(data, 4))
2402     return GET_SIZE_ERROR;
2403   n_line_strings= uint4korr(data);
2404   data+= 4;
2405 
2406   while (n_line_strings--)
2407   {
2408     if (no_data(data, WKB_HEADER_SIZE + 4) ||
2409         not_enough_points(data + WKB_HEADER_SIZE+4,
2410                           (n_points= uint4korr(data + WKB_HEADER_SIZE))))
2411       return GET_SIZE_ERROR;
2412     data+= (WKB_HEADER_SIZE + 4 + n_points*POINT_DATA_SIZE);
2413   }
2414   if (no_data(data, 0))
2415     return GET_SIZE_ERROR;
2416   return (uint32) (data - m_data);
2417 }
2418 
2419 
init_from_wkt(Gis_read_stream * trs,String * wkb)2420 bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
2421 {
2422   uint32 n_line_strings= 0;
2423   uint32 ls_pos= wkb->length();
2424 
2425   if (wkb->reserve(4, 512))
2426     return 1;
2427   wkb->length(wkb->length()+4);			// Reserve space for points
2428 
2429   for (;;)
2430   {
2431     Gis_line_string ls;
2432 
2433     if (wkb->reserve(1 + 4, 512))
2434       return 1;
2435     wkb->q_append((char) wkb_ndr); wkb->q_append((uint32) wkb_linestring);
2436 
2437     if (trs->check_next_symbol('(') ||
2438 	ls.init_from_wkt(trs, wkb) ||
2439 	trs->check_next_symbol(')'))
2440       return 1;
2441     n_line_strings++;
2442     if (trs->skip_char(','))			// Didn't find ','
2443       break;
2444   }
2445   wkb->write_at_position(ls_pos, n_line_strings);
2446   return 0;
2447 }
2448 
2449 
init_from_opresult(String * bin,const char * opres,uint res_len)2450 uint Gis_multi_line_string::init_from_opresult(String *bin,
2451                                                const char *opres, uint res_len)
2452 {
2453   const char *opres_orig= opres;
2454   int ns_pos= bin->length();
2455   uint n_linestring= 0;
2456 
2457   if (bin->reserve(4, 512))
2458     return 0;
2459   bin->q_append(n_linestring);
2460 
2461   while (res_len)
2462   {
2463     Gis_line_string ls;
2464     int ls_len;
2465 
2466     if (bin->reserve(WKB_HEADER_SIZE, 512))
2467       return 0;
2468 
2469     bin->q_append((char) wkb_ndr);
2470     bin->q_append((uint32) wkb_linestring);
2471 
2472     if (!(ls_len= ls.init_from_opresult(bin, opres, res_len)))
2473       return 0;
2474     opres+= ls_len;
2475     res_len-= ls_len;
2476     n_linestring++;
2477   }
2478   bin->write_at_position(ns_pos, n_linestring);
2479   return (uint) (opres - opres_orig);
2480 }
2481 
2482 
init_from_wkb(const char * wkb,uint len,wkbByteOrder bo,String * res)2483 uint Gis_multi_line_string::init_from_wkb(const char *wkb, uint len,
2484                                           wkbByteOrder bo, String *res)
2485 {
2486   uint32 n_line_strings;
2487   const char *wkb_orig= wkb;
2488 
2489   if (len < 4 ||
2490       (n_line_strings= wkb_get_uint(wkb, bo))< 1)
2491     return 0;
2492 
2493   if (res->reserve(4, 512))
2494     return 0;
2495   res->q_append(n_line_strings);
2496 
2497   wkb+= 4;
2498   while (n_line_strings--)
2499   {
2500     Gis_line_string ls;
2501     int ls_len;
2502 
2503     if ((len < WKB_HEADER_SIZE) ||
2504         res->reserve(WKB_HEADER_SIZE, 512))
2505       return 0;
2506 
2507     res->q_append((char) wkb_ndr);
2508     res->q_append((uint32) wkb_linestring);
2509 
2510     if (!(ls_len= ls.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
2511                                    (wkbByteOrder) wkb[0], res)))
2512       return 0;
2513     ls_len+= WKB_HEADER_SIZE;;
2514     wkb+= ls_len;
2515     len-= ls_len;
2516   }
2517   return (uint) (wkb - wkb_orig);
2518 }
2519 
2520 
init_from_json(json_engine_t * je,bool er_on_3D,String * wkb)2521 bool Gis_multi_line_string::init_from_json(json_engine_t *je, bool er_on_3D,
2522                                            String *wkb)
2523 {
2524   uint32 n_line_strings= 0;
2525   uint32 ls_pos= wkb->length();
2526 
2527   if (json_read_value(je))
2528     return TRUE;
2529 
2530   if (je->value_type != JSON_VALUE_ARRAY)
2531   {
2532     je->s.error= GEOJ_INCORRECT_GEOJSON;
2533     return TRUE;
2534   }
2535 
2536   if (wkb->reserve(4, 512))
2537     return TRUE;
2538   wkb->length(wkb->length()+4);	// Reserve space for n_rings
2539 
2540   while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
2541   {
2542     Gis_line_string ls;
2543     DBUG_ASSERT(je->state == JST_VALUE);
2544 
2545     if (wkb->reserve(1 + 4, 512))
2546       return TRUE;
2547     wkb->q_append((char) wkb_ndr);
2548     wkb->q_append((uint32) wkb_linestring);
2549 
2550     if (ls.init_from_json(je, er_on_3D, wkb))
2551       return TRUE;
2552 
2553     n_line_strings++;
2554   }
2555 
2556   if (je->s.error)
2557     return TRUE;
2558 
2559   if (n_line_strings == 0)
2560   {
2561     je->s.error= Geometry::GEOJ_EMPTY_COORDINATES;
2562     return TRUE;
2563   }
2564 
2565   wkb->write_at_position(ls_pos, n_line_strings);
2566   return FALSE;
2567 }
2568 
2569 
get_data_as_wkt(String * txt,const char ** end) const2570 bool Gis_multi_line_string::get_data_as_wkt(String *txt,
2571 					     const char **end) const
2572 {
2573   uint32 n_line_strings;
2574   const char *data= m_data;
2575 
2576   if (no_data(data, 4))
2577     return 1;
2578   n_line_strings= uint4korr(data);
2579   data+= 4;
2580 
2581   while (n_line_strings--)
2582   {
2583     uint32 n_points;
2584     if (no_data(data, (WKB_HEADER_SIZE + 4)))
2585       return 1;
2586     n_points= uint4korr(data + WKB_HEADER_SIZE);
2587     data+= WKB_HEADER_SIZE + 4;
2588     if (not_enough_points(data, n_points) ||
2589 	txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
2590       return 1;
2591     txt->qs_append('(');
2592     data= append_points(txt, n_points, data, 0);
2593     (*txt) [txt->length() - 1]= ')';
2594     txt->qs_append(',');
2595   }
2596   txt->length(txt->length() - 1);
2597   *end= data;
2598   return 0;
2599 }
2600 
2601 
get_data_as_json(String * txt,uint max_dec_digits,const char ** end) const2602 bool Gis_multi_line_string::get_data_as_json(String *txt, uint max_dec_digits,
2603                                              const char **end) const
2604 {
2605   uint32 n_line_strings;
2606   const char *data= m_data;
2607 
2608   if (no_data(data, 4) || txt->reserve(1, 512))
2609     return 1;
2610   n_line_strings= uint4korr(data);
2611   data+= 4;
2612 
2613   txt->qs_append('[');
2614   while (n_line_strings--)
2615   {
2616     uint32 n_points;
2617     if (no_data(data, (WKB_HEADER_SIZE + 4)))
2618       return 1;
2619     n_points= uint4korr(data + WKB_HEADER_SIZE);
2620     data+= WKB_HEADER_SIZE + 4;
2621     if (not_enough_points(data, n_points) ||
2622 	txt->reserve(2 + (MAX_DIGITS_IN_DOUBLE * 2 + 6) * n_points))
2623       return 1;
2624     data= append_json_points(txt, max_dec_digits, n_points, data, 0);
2625     txt->qs_append(", ", 2);
2626   }
2627   txt->length(txt->length() - 2);
2628   txt->qs_append(']');
2629   *end= data;
2630   return 0;
2631 }
2632 
2633 
get_mbr(MBR * mbr,const char ** end) const2634 bool Gis_multi_line_string::get_mbr(MBR *mbr, const char **end) const
2635 {
2636   uint32 n_line_strings;
2637   const char *data= m_data;
2638 
2639   if (no_data(data, 4))
2640     return 1;
2641   n_line_strings= uint4korr(data);
2642   data+= 4;
2643 
2644   while (n_line_strings--)
2645   {
2646     data+= WKB_HEADER_SIZE;
2647     if (!(data= get_mbr_for_points(mbr, data, 0)))
2648       return 1;
2649   }
2650   *end= data;
2651   return 0;
2652 }
2653 
2654 
num_geometries(uint32 * num) const2655 int Gis_multi_line_string::num_geometries(uint32 *num) const
2656 {
2657   *num= uint4korr(m_data);
2658   return 0;
2659 }
2660 
2661 
geometry_n(uint32 num,String * result) const2662 int Gis_multi_line_string::geometry_n(uint32 num, String *result) const
2663 {
2664   uint32 n_line_strings, n_points, length;
2665   const char *data= m_data;
2666 
2667   if (no_data(data, 4))
2668     return 1;
2669   n_line_strings= uint4korr(data);
2670   data+= 4;
2671 
2672   if ((num > n_line_strings) || (num < 1))
2673     return 1;
2674 
2675   for (;;)
2676   {
2677     if (no_data(data, WKB_HEADER_SIZE + 4))
2678       return 1;
2679     n_points= uint4korr(data + WKB_HEADER_SIZE);
2680     length= WKB_HEADER_SIZE + 4+ POINT_DATA_SIZE * n_points;
2681     if (not_enough_points(data+WKB_HEADER_SIZE+4, n_points))
2682       return 1;
2683     if (!--num)
2684       break;
2685     data+= length;
2686   }
2687   return result->append(data, length, (uint32) 0);
2688 }
2689 
2690 
geom_length(double * len,const char ** end) const2691 int Gis_multi_line_string::geom_length(double *len, const char **end) const
2692 {
2693   uint32 n_line_strings;
2694   const char *data= m_data;
2695   const char *line_end;
2696 
2697   if (no_data(data, 4))
2698     return 1;
2699   n_line_strings= uint4korr(data);
2700   data+= 4;
2701 
2702   *len=0;
2703   while (n_line_strings--)
2704   {
2705     double ls_len;
2706     Gis_line_string ls;
2707     data+= WKB_HEADER_SIZE;
2708     ls.set_data_ptr(data, (uint32) (m_data_end - data));
2709     if (ls.geom_length(&ls_len, &line_end))
2710       return 1;
2711     *len+= ls_len;
2712     /*
2713       We know here that ls was ok, so we can call the trivial function
2714       Gis_line_string::get_data_size without error checking
2715     */
2716     data+= ls.get_data_size();
2717   }
2718   *end= data;
2719   return 0;
2720 }
2721 
2722 
is_closed(int * closed) const2723 int Gis_multi_line_string::is_closed(int *closed) const
2724 {
2725   uint32 n_line_strings;
2726   const char *data= m_data;
2727 
2728   if (no_data(data, 4 + WKB_HEADER_SIZE))
2729     return 1;
2730   n_line_strings= uint4korr(data);
2731   data+= 4 + WKB_HEADER_SIZE;
2732 
2733   while (n_line_strings--)
2734   {
2735     Gis_line_string ls;
2736     if (no_data(data, 0))
2737       return 1;
2738     ls.set_data_ptr(data, (uint32) (m_data_end - data));
2739     if (ls.is_closed(closed))
2740       return 1;
2741     if (!*closed)
2742       return 0;
2743     /*
2744       We know here that ls was ok, so we can call the trivial function
2745       Gis_line_string::get_data_size without error checking
2746     */
2747     data+= ls.get_data_size() + WKB_HEADER_SIZE;
2748   }
2749   return 0;
2750 }
2751 
2752 
store_shapes(Gcalc_shape_transporter * trn) const2753 int Gis_multi_line_string::store_shapes(Gcalc_shape_transporter *trn) const
2754 {
2755   uint32 n_lines;
2756   Gis_line_string ls;
2757   const char *data= m_data;
2758 
2759   if (no_data(data, 4))
2760     return 1;
2761   n_lines= uint4korr(data);
2762   data+= 4;
2763 
2764   if (trn->start_collection(n_lines))
2765     return 1;
2766 
2767   while (n_lines--)
2768   {
2769     if (no_data(data, WKB_HEADER_SIZE))
2770       return 1;
2771     data+= WKB_HEADER_SIZE;
2772     ls.set_data_ptr(data, (uint32) (m_data_end - data));
2773     if (ls.store_shapes(trn))
2774       return 1;
2775     data+= ls.get_data_size();
2776   }
2777   return 0;
2778 }
2779 
2780 
get_class_info() const2781 const Geometry::Class_info *Gis_multi_line_string::get_class_info() const
2782 {
2783   return &multilinestring_class;
2784 }
2785 
2786 
2787 /***************************** MultiPolygon *******************************/
2788 
get_data_size() const2789 uint32 Gis_multi_polygon::get_data_size() const
2790 {
2791   uint32 n_polygons;
2792   uint32 n_points;
2793   const char *data= m_data;
2794 
2795   if (no_data(data, 4))
2796     return GET_SIZE_ERROR;
2797   n_polygons= uint4korr(data);
2798   data+= 4;
2799 
2800   while (n_polygons--)
2801   {
2802     uint32 n_linear_rings;
2803     if (no_data(data, 4 + WKB_HEADER_SIZE))
2804       return GET_SIZE_ERROR;
2805 
2806     n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
2807     data+= 4 + WKB_HEADER_SIZE;
2808 
2809     while (n_linear_rings--)
2810     {
2811       if (no_data(data, 4) ||
2812           not_enough_points(data+4, (n_points= uint4korr(data))))
2813 	return GET_SIZE_ERROR;
2814       data+= 4 + n_points * POINT_DATA_SIZE;
2815     }
2816   }
2817   if (no_data(data, 0))
2818     return GET_SIZE_ERROR;
2819   return (uint32) (data - m_data);
2820 }
2821 
2822 
init_from_wkt(Gis_read_stream * trs,String * wkb)2823 bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
2824 {
2825   uint32 n_polygons= 0;
2826   int np_pos= wkb->length();
2827   Gis_polygon p;
2828 
2829   if (wkb->reserve(4, 512))
2830     return 1;
2831   wkb->length(wkb->length()+4);			// Reserve space for points
2832 
2833   for (;;)
2834   {
2835     if (wkb->reserve(1 + 4, 512))
2836       return 1;
2837     wkb->q_append((char) wkb_ndr);
2838     wkb->q_append((uint32) wkb_polygon);
2839 
2840     if (trs->check_next_symbol('(') ||
2841 	p.init_from_wkt(trs, wkb) ||
2842 	trs->check_next_symbol(')'))
2843       return 1;
2844     n_polygons++;
2845     if (trs->skip_char(','))			// Didn't find ','
2846       break;
2847   }
2848   wkb->write_at_position(np_pos, n_polygons);
2849   return 0;
2850 }
2851 
2852 
init_from_wkb(const char * wkb,uint len,wkbByteOrder bo,String * res)2853 uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len,
2854                                       wkbByteOrder bo, String *res)
2855 {
2856   uint32 n_poly;
2857   const char *wkb_orig= wkb;
2858 
2859   if (len < 4)
2860     return 0;
2861   n_poly= wkb_get_uint(wkb, bo);
2862 
2863   if (res->reserve(4, 512))
2864     return 0;
2865   res->q_append(n_poly);
2866 
2867   wkb+=4;
2868   while (n_poly--)
2869   {
2870     Gis_polygon p;
2871     int p_len;
2872 
2873     if (len < WKB_HEADER_SIZE ||
2874         res->reserve(WKB_HEADER_SIZE, 512))
2875       return 0;
2876     res->q_append((char) wkb_ndr);
2877     res->q_append((uint32) wkb_polygon);
2878 
2879     if (!(p_len= p.init_from_wkb(wkb + WKB_HEADER_SIZE, len,
2880                                  (wkbByteOrder) wkb[0], res)))
2881       return 0;
2882     p_len+= WKB_HEADER_SIZE;
2883     wkb+= p_len;
2884     len-= p_len;
2885   }
2886   return (uint) (wkb - wkb_orig);
2887 }
2888 
2889 
init_from_opresult(String * bin,const char * opres,uint res_len)2890 uint Gis_multi_polygon::init_from_opresult(String *bin,
2891                                            const char *opres, uint res_len)
2892 {
2893   Gis_polygon p;
2894   const char *opres_orig= opres;
2895   uint p_len;
2896   uint32 n_poly= 0;
2897   uint32 np_pos= bin->length();
2898 
2899   if (bin->reserve(4, 512))
2900     return 0;
2901 
2902   bin->q_append(n_poly);
2903   while (res_len)
2904   {
2905     if (bin->reserve(1 + 4, 512))
2906       return 0;
2907     bin->q_append((char)wkb_ndr);
2908     bin->q_append((uint32)wkb_polygon);
2909     if (!(p_len= p.init_from_opresult(bin, opres, res_len)))
2910       return 0;
2911     opres+= p_len;
2912     res_len-= p_len;
2913     n_poly++;
2914   }
2915   bin->write_at_position(np_pos, n_poly);
2916   return (uint)(opres - opres_orig);
2917 }
2918 
2919 
init_from_json(json_engine_t * je,bool er_on_3D,String * wkb)2920 bool Gis_multi_polygon::init_from_json(json_engine_t *je, bool er_on_3D,
2921                                        String *wkb)
2922 {
2923   uint32 n_polygons= 0;
2924   int np_pos= wkb->length();
2925   Gis_polygon p;
2926 
2927   if (json_read_value(je))
2928     return TRUE;
2929 
2930   if (je->value_type != JSON_VALUE_ARRAY)
2931   {
2932     je->s.error= GEOJ_INCORRECT_GEOJSON;
2933     return TRUE;
2934   }
2935 
2936   if (wkb->reserve(4, 512))
2937     return TRUE;
2938   wkb->length(wkb->length()+4);	// Reserve space for n_rings
2939 
2940   while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
2941   {
2942     DBUG_ASSERT(je->state == JST_VALUE);
2943 
2944     if (wkb->reserve(1 + 4, 512))
2945       return TRUE;
2946     wkb->q_append((char) wkb_ndr);
2947     wkb->q_append((uint32) wkb_polygon);
2948 
2949     if (p.init_from_json(je, er_on_3D, wkb))
2950       return TRUE;
2951 
2952     n_polygons++;
2953   }
2954 
2955   if (je->s.error)
2956     return TRUE;
2957 
2958   if (n_polygons == 0)
2959   {
2960     je->s.error= Geometry::GEOJ_EMPTY_COORDINATES;
2961     return TRUE;
2962   }
2963   wkb->write_at_position(np_pos, n_polygons);
2964   return FALSE;
2965 }
2966 
2967 
get_data_as_wkt(String * txt,const char ** end) const2968 bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const
2969 {
2970   uint32 n_polygons;
2971   const char *data= m_data;
2972 
2973   if (no_data(data, 4))
2974     return 1;
2975   n_polygons= uint4korr(data);
2976   data+= 4;
2977 
2978   while (n_polygons--)
2979   {
2980     uint32 n_linear_rings;
2981     if (no_data(data, 4 + WKB_HEADER_SIZE) ||
2982 	txt->reserve(1, 512))
2983       return 1;
2984     n_linear_rings= uint4korr(data+WKB_HEADER_SIZE);
2985     data+= 4 + WKB_HEADER_SIZE;
2986     txt->q_append('(');
2987 
2988     while (n_linear_rings--)
2989     {
2990       if (no_data(data, 4))
2991         return 1;
2992       uint32 n_points= uint4korr(data);
2993       data+= 4;
2994       if (not_enough_points(data, n_points) ||
2995 	  txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points,
2996 		       512))
2997 	return 1;
2998       txt->qs_append('(');
2999       data= append_points(txt, n_points, data, 0);
3000       (*txt) [txt->length() - 1]= ')';
3001       txt->qs_append(',');
3002     }
3003     (*txt) [txt->length() - 1]= ')';
3004     txt->qs_append(',');
3005   }
3006   txt->length(txt->length() - 1);
3007   *end= data;
3008   return 0;
3009 }
3010 
3011 
get_data_as_json(String * txt,uint max_dec_digits,const char ** end) const3012 bool Gis_multi_polygon::get_data_as_json(String *txt, uint max_dec_digits,
3013                                          const char **end) const
3014 {
3015   uint32 n_polygons;
3016   const char *data= m_data;
3017 
3018   if (no_data(data, 4) || txt->reserve(1, 512))
3019     return 1;
3020   n_polygons= uint4korr(data);
3021   data+= 4;
3022 
3023   txt->q_append('[');
3024   while (n_polygons--)
3025   {
3026     uint32 n_linear_rings;
3027     if (no_data(data, 4 + WKB_HEADER_SIZE) ||
3028 	txt->reserve(1, 512))
3029       return 1;
3030     n_linear_rings= uint4korr(data+WKB_HEADER_SIZE);
3031     data+= 4 + WKB_HEADER_SIZE;
3032     txt->q_append('[');
3033 
3034     while (n_linear_rings--)
3035     {
3036       if (no_data(data, 4))
3037         return 1;
3038       uint32 n_points= uint4korr(data);
3039       data+= 4;
3040       if (not_enough_points(data, n_points) ||
3041 	  txt->reserve(2 + (MAX_DIGITS_IN_DOUBLE * 2 + 6) * n_points,
3042 		       512))
3043 	return 1;
3044       data= append_json_points(txt, max_dec_digits, n_points, data, 0);
3045       txt->qs_append(", ", 2);
3046     }
3047     txt->length(txt->length() - 2);
3048     txt->qs_append("], ", 3);
3049   }
3050   txt->length(txt->length() - 2);
3051   txt->q_append(']');
3052   *end= data;
3053   return 0;
3054 }
3055 
3056 
get_mbr(MBR * mbr,const char ** end) const3057 bool Gis_multi_polygon::get_mbr(MBR *mbr, const char **end) const
3058 {
3059   uint32 n_polygons;
3060   const char *data= m_data;
3061 
3062   if (no_data(data, 4))
3063     return 1;
3064   n_polygons= uint4korr(data);
3065   data+= 4;
3066 
3067   while (n_polygons--)
3068   {
3069     uint32 n_linear_rings;
3070     if (no_data(data, 4+WKB_HEADER_SIZE))
3071       return 1;
3072     n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
3073     data+= WKB_HEADER_SIZE + 4;
3074 
3075     while (n_linear_rings--)
3076     {
3077       if (!(data= get_mbr_for_points(mbr, data, 0)))
3078 	return 1;
3079     }
3080   }
3081   *end= data;
3082   return 0;
3083 }
3084 
3085 
num_geometries(uint32 * num) const3086 int Gis_multi_polygon::num_geometries(uint32 *num) const
3087 {
3088   *num= uint4korr(m_data);
3089   return 0;
3090 }
3091 
3092 
geometry_n(uint32 num,String * result) const3093 int Gis_multi_polygon::geometry_n(uint32 num, String *result) const
3094 {
3095   uint32 n_polygons;
3096   const char *data= m_data, *start_of_polygon;
3097 
3098   if (no_data(data, 4))
3099     return 1;
3100   n_polygons= uint4korr(data);
3101   data+= 4;
3102 
3103   if (num > n_polygons || num < 1)
3104     return -1;
3105 
3106   do
3107   {
3108     uint32 n_linear_rings;
3109     start_of_polygon= data;
3110 
3111     if (no_data(data, WKB_HEADER_SIZE + 4))
3112       return 1;
3113     n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
3114     data+= WKB_HEADER_SIZE + 4;
3115 
3116     while (n_linear_rings--)
3117     {
3118       uint32 n_points;
3119       if (no_data(data, 4))
3120 	return 1;
3121       n_points= uint4korr(data);
3122       if (not_enough_points(data + 4, n_points))
3123         return 1;
3124       data+= 4 + POINT_DATA_SIZE * n_points;
3125     }
3126   } while (--num);
3127   if (no_data(data, 0))				// We must check last segment
3128     return 1;
3129   return result->append(start_of_polygon, (uint32) (data - start_of_polygon),
3130 			(uint32) 0);
3131 }
3132 
3133 
area(double * ar,const char ** end_of_data) const3134 int Gis_multi_polygon::area(double *ar,  const char **end_of_data) const
3135 {
3136   uint32 n_polygons;
3137   const char *data= m_data;
3138   double result= 0;
3139 
3140   if (no_data(data, 4))
3141     return 1;
3142   n_polygons= uint4korr(data);
3143   data+= 4;
3144 
3145   while (n_polygons--)
3146   {
3147     double p_area;
3148     Gis_polygon p;
3149 
3150     data+= WKB_HEADER_SIZE;
3151     p.set_data_ptr(data, (uint32) (m_data_end - data));
3152     if (p.area(&p_area, &data))
3153       return 1;
3154     result+= p_area;
3155   }
3156   *ar= result;
3157   *end_of_data= data;
3158   return 0;
3159 }
3160 
3161 
centroid(String * result) const3162 int Gis_multi_polygon::centroid(String *result) const
3163 {
3164   uint32 n_polygons;
3165   Gis_polygon p;
3166   double res_area= 0.0, res_cx= 0.0, res_cy= 0.0;
3167   double cur_area, cur_cx, cur_cy;
3168   const char *data= m_data;
3169 
3170   if (no_data(data, 4))
3171     return 1;
3172   n_polygons= uint4korr(data);
3173   data+= 4;
3174 
3175   while (n_polygons--)
3176   {
3177     data+= WKB_HEADER_SIZE;
3178     p.set_data_ptr(data, (uint32) (m_data_end - data));
3179     if (p.area(&cur_area, &data) ||
3180 	p.centroid_xy(&cur_cx, &cur_cy))
3181       return 1;
3182 
3183     res_area+= cur_area;
3184     res_cx+= cur_area * cur_cx;
3185     res_cy+= cur_area * cur_cy;
3186   }
3187 
3188   res_cx/= res_area;
3189   res_cy/= res_area;
3190 
3191   return create_point(result, res_cx, res_cy);
3192 }
3193 
3194 
store_shapes(Gcalc_shape_transporter * trn) const3195 int Gis_multi_polygon::store_shapes(Gcalc_shape_transporter *trn) const
3196 {
3197   uint32 n_polygons;
3198   Gis_polygon p;
3199   const char *data= m_data;
3200 
3201   if (no_data(data, 4))
3202     return 1;
3203   n_polygons= uint4korr(data);
3204   data+= 4;
3205 
3206   if (trn->start_collection(n_polygons))
3207     return 1;
3208 
3209   while (n_polygons--)
3210   {
3211     if (no_data(data, WKB_HEADER_SIZE))
3212       return 1;
3213     data+= WKB_HEADER_SIZE;
3214     p.set_data_ptr(data, (uint32) (m_data_end - data));
3215     if (p.store_shapes(trn))
3216       return 1;
3217     data+= p.get_data_size();
3218   }
3219   return 0;
3220 }
3221 
3222 
get_class_info() const3223 const Geometry::Class_info *Gis_multi_polygon::get_class_info() const
3224 {
3225   return &multipolygon_class;
3226 }
3227 
3228 
3229 /************************* GeometryCollection ****************************/
3230 
get_data_size() const3231 uint32 Gis_geometry_collection::get_data_size() const
3232 {
3233   uint32 n_objects;
3234   const char *data= m_data;
3235   Geometry_buffer buffer;
3236   Geometry *geom;
3237 
3238   if (no_data(data, 4))
3239     return GET_SIZE_ERROR;
3240   n_objects= uint4korr(data);
3241   data+= 4;
3242 
3243   while (n_objects--)
3244   {
3245     uint32 wkb_type,object_size;
3246 
3247     if (no_data(data, WKB_HEADER_SIZE))
3248       return GET_SIZE_ERROR;
3249     wkb_type= uint4korr(data + 1);
3250     data+= WKB_HEADER_SIZE;
3251 
3252     if (!(geom= create_by_typeid(&buffer, wkb_type)))
3253       return GET_SIZE_ERROR;
3254     geom->set_data_ptr(data, (uint) (m_data_end - data));
3255     if ((object_size= geom->get_data_size()) == GET_SIZE_ERROR)
3256       return GET_SIZE_ERROR;
3257     data+= object_size;
3258   }
3259   return (uint32) (data - m_data);
3260 }
3261 
3262 
init_from_wkt(Gis_read_stream * trs,String * wkb)3263 bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb)
3264 {
3265   uint32 n_objects= 0;
3266   uint32 no_pos= wkb->length();
3267   Geometry_buffer buffer;
3268   Geometry *g;
3269   char next_sym;
3270 
3271   if (wkb->reserve(4, 512))
3272     return 1;
3273   wkb->length(wkb->length()+4);			// Reserve space for points
3274 
3275   if (!(next_sym= trs->next_symbol()))
3276     return 1;
3277 
3278   if (next_sym != ')')
3279   {
3280     LEX_STRING next_word;
3281     if (trs->lookup_next_word(&next_word))
3282       return 1;
3283 
3284     if (next_word.length != 5 ||
3285 	(my_charset_latin1.strnncoll("empty", 5, next_word.str, 5) != 0))
3286     {
3287       for (;;)
3288       {
3289         if (!(g= create_from_wkt(&buffer, trs, wkb)))
3290           return 1;
3291 
3292         if (g->get_class_info()->m_type_id == wkb_geometrycollection)
3293         {
3294           trs->set_error_msg("Unexpected GEOMETRYCOLLECTION");
3295           return 1;
3296         }
3297         n_objects++;
3298         if (trs->skip_char(','))			// Didn't find ','
3299           break;
3300       }
3301     }
3302   }
3303 
3304   wkb->write_at_position(no_pos, n_objects);
3305   return 0;
3306 }
3307 
3308 
init_from_opresult(String * bin,const char * opres,uint res_len)3309 uint Gis_geometry_collection::init_from_opresult(String *bin,
3310                                                  const char *opres,
3311                                                  uint res_len)
3312 {
3313   const char *opres_orig= opres;
3314   Geometry_buffer buffer;
3315   Geometry *geom;
3316   int g_len;
3317   uint32 wkb_type;
3318   int no_pos= bin->length();
3319   uint32 n_objects= 0;
3320 
3321   if (bin->reserve(4, 512))
3322     return 0;
3323   bin->q_append(n_objects);
3324 
3325   if (res_len == 0)
3326   {
3327     /* Special case of GEOMETRYCOLLECTION EMPTY. */
3328     opres+= 1;
3329     goto empty_geom;
3330   }
3331 
3332   while (res_len)
3333   {
3334     switch ((Gcalc_function::shape_type) uint4korr(opres))
3335     {
3336       case Gcalc_function::shape_point:   wkb_type= wkb_point; break;
3337       case Gcalc_function::shape_line:    wkb_type= wkb_linestring; break;
3338       case Gcalc_function::shape_polygon: wkb_type= wkb_polygon; break;
3339       default: wkb_type= 0; DBUG_ASSERT(FALSE);
3340     };
3341 
3342     if (bin->reserve(WKB_HEADER_SIZE, 512))
3343       return 0;
3344 
3345     bin->q_append((char) wkb_ndr);
3346     bin->q_append(wkb_type);
3347 
3348     if (!(geom= create_by_typeid(&buffer, wkb_type)) ||
3349         !(g_len= geom->init_from_opresult(bin, opres, res_len)))
3350       return 0;
3351     opres+= g_len;
3352     res_len-= g_len;
3353     n_objects++;
3354   }
3355 empty_geom:
3356   bin->write_at_position(no_pos, n_objects);
3357   return (uint) (opres - opres_orig);
3358 }
3359 
3360 
init_from_wkb(const char * wkb,uint len,wkbByteOrder bo,String * res)3361 uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len,
3362                                             wkbByteOrder bo, String *res)
3363 {
3364   uint32 n_geom;
3365   const char *wkb_orig= wkb;
3366 
3367   if (len < 4)
3368     return 0;
3369   n_geom= wkb_get_uint(wkb, bo);
3370 
3371   if (res->reserve(4, 512))
3372     return 0;
3373   res->q_append(n_geom);
3374 
3375   wkb+= 4;
3376   while (n_geom--)
3377   {
3378     Geometry_buffer buffer;
3379     Geometry *geom;
3380     int g_len;
3381     uint32 wkb_type;
3382 
3383     if (len < WKB_HEADER_SIZE ||
3384         res->reserve(WKB_HEADER_SIZE, 512))
3385       return 0;
3386 
3387     res->q_append((char) wkb_ndr);
3388     wkb_type= wkb_get_uint(wkb+1, (wkbByteOrder) wkb[0]);
3389     res->q_append(wkb_type);
3390 
3391     if (!(geom= create_by_typeid(&buffer, wkb_type)) ||
3392         !(g_len= geom->init_from_wkb(wkb + WKB_HEADER_SIZE, len,
3393                                      (wkbByteOrder)  wkb[0], res)))
3394       return 0;
3395     g_len+= WKB_HEADER_SIZE;
3396     wkb+= g_len;
3397     len-= g_len;
3398   }
3399   return (uint) (wkb - wkb_orig);
3400 }
3401 
3402 
init_from_json(json_engine_t * je,bool er_on_3D,String * wkb)3403 bool Gis_geometry_collection::init_from_json(json_engine_t *je, bool er_on_3D,
3404                                              String *wkb)
3405 {
3406   uint32 n_objects= 0;
3407   uint32 no_pos= wkb->length();
3408   Geometry_buffer buffer;
3409   Geometry *g;
3410 
3411   if (json_read_value(je))
3412     return TRUE;
3413 
3414   if (je->value_type != JSON_VALUE_ARRAY)
3415   {
3416     je->s.error= GEOJ_INCORRECT_GEOJSON;
3417     return TRUE;
3418   }
3419 
3420   if (wkb->reserve(4, 512))
3421     return TRUE;
3422   wkb->length(wkb->length()+4);	// Reserve space for n_objects
3423 
3424   while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
3425   {
3426     json_engine_t sav_je= *je;
3427 
3428     DBUG_ASSERT(je->state == JST_VALUE);
3429 
3430     if (!(g= create_from_json(&buffer, je, er_on_3D, wkb)))
3431       return TRUE;
3432 
3433     *je= sav_je;
3434     if (json_skip_array_item(je))
3435       return TRUE;
3436 
3437     n_objects++;
3438   }
3439 
3440   wkb->write_at_position(no_pos, n_objects);
3441   return FALSE;
3442 }
3443 
3444 
get_data_as_wkt(String * txt,const char ** end) const3445 bool Gis_geometry_collection::get_data_as_wkt(String *txt,
3446 					     const char **end) const
3447 {
3448   uint32 n_objects;
3449   Geometry_buffer buffer;
3450   Geometry *geom;
3451   const char *data= m_data;
3452 
3453   if (no_data(data, 4))
3454     return 1;
3455   n_objects= uint4korr(data);
3456   data+= 4;
3457 
3458   if (n_objects == 0)
3459   {
3460     txt->append(STRING_WITH_LEN(" EMPTY"), 512);
3461     goto exit;
3462   }
3463 
3464   txt->qs_append('(');
3465   while (n_objects--)
3466   {
3467     uint32 wkb_type;
3468 
3469     if (no_data(data, WKB_HEADER_SIZE))
3470       return 1;
3471     wkb_type= uint4korr(data + 1);
3472     data+= WKB_HEADER_SIZE;
3473 
3474     if (!(geom= create_by_typeid(&buffer, wkb_type)))
3475       return 1;
3476     geom->set_data_ptr(data, (uint) (m_data_end - data));
3477     if (geom->as_wkt(txt, &data))
3478       return 1;
3479     if (n_objects && txt->append(STRING_WITH_LEN(","), 512))
3480       return 1;
3481   }
3482   txt->qs_append(')');
3483 exit:
3484   *end= data;
3485   return 0;
3486 }
3487 
3488 
get_data_as_json(String * txt,uint max_dec_digits,const char ** end) const3489 bool Gis_geometry_collection::get_data_as_json(String *txt, uint max_dec_digits,
3490                                                const char **end) const
3491 {
3492   uint32 n_objects;
3493   Geometry_buffer buffer;
3494   Geometry *geom;
3495   const char *data= m_data;
3496 
3497   if (no_data(data, 4) || txt->reserve(1, 512))
3498     return 1;
3499   n_objects= uint4korr(data);
3500   data+= 4;
3501 
3502   txt->qs_append('[');
3503   while (n_objects--)
3504   {
3505     uint32 wkb_type;
3506 
3507     if (no_data(data, WKB_HEADER_SIZE))
3508       return 1;
3509     wkb_type= uint4korr(data + 1);
3510     data+= WKB_HEADER_SIZE;
3511 
3512     if (!(geom= create_by_typeid(&buffer, wkb_type)))
3513       return 1;
3514     geom->set_data_ptr(data, (uint) (m_data_end - data));
3515     if (txt->append("{", 1) ||
3516         geom->as_json(txt, max_dec_digits, &data) ||
3517         txt->append(STRING_WITH_LEN("}, "), 512))
3518       return 1;
3519   }
3520   txt->length(txt->length() - 2);
3521   if (txt->append("]", 1))
3522     return 1;
3523 
3524   *end= data;
3525   return 0;
3526 }
3527 
3528 
get_mbr(MBR * mbr,const char ** end) const3529 bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const
3530 {
3531   uint32 n_objects;
3532   const char *data= m_data;
3533   Geometry_buffer buffer;
3534   Geometry *geom;
3535 
3536   if (no_data(data, 4))
3537     return 1;
3538   n_objects= uint4korr(data);
3539   data+= 4;
3540   if (n_objects == 0)
3541     goto exit;
3542 
3543   while (n_objects--)
3544   {
3545     uint32 wkb_type;
3546 
3547     if (no_data(data, WKB_HEADER_SIZE))
3548       return 1;
3549     wkb_type= uint4korr(data + 1);
3550     data+= WKB_HEADER_SIZE;
3551 
3552     if (!(geom= create_by_typeid(&buffer, wkb_type)))
3553       return 1;
3554     geom->set_data_ptr(data, (uint32) (m_data_end - data));
3555     if (geom->get_mbr(mbr, &data))
3556       return 1;
3557   }
3558 exit:
3559   *end= data;
3560   return 0;
3561 }
3562 
3563 
area(double * ar,const char ** end) const3564 int Gis_geometry_collection::area(double *ar,  const char **end) const
3565 {
3566   uint32 n_objects;
3567   const char *data= m_data;
3568   Geometry_buffer buffer;
3569   Geometry *geom;
3570   double result;
3571 
3572   if (no_data(data, 4))
3573     return 1;
3574   n_objects= uint4korr(data);
3575   data+= 4;
3576 
3577   result= 0.0;
3578   if (n_objects == 0)
3579     goto exit;
3580 
3581   while (n_objects--)
3582   {
3583     uint32 wkb_type;
3584 
3585     if (no_data(data, WKB_HEADER_SIZE))
3586       return 1;
3587     wkb_type= uint4korr(data + 1);
3588     data+= WKB_HEADER_SIZE;
3589 
3590     if (!(geom= create_by_typeid(&buffer, wkb_type)))
3591       return 1;
3592     geom->set_data_ptr(data, (uint32) (m_data_end - data));
3593     if (geom->area(ar, &data))
3594       return 1;
3595     result+= *ar;
3596   }
3597 exit:
3598   *end= data;
3599   *ar= result;
3600   return 0;
3601 }
3602 
3603 
geom_length(double * len,const char ** end) const3604 int Gis_geometry_collection::geom_length(double *len, const char **end) const
3605 {
3606   uint32 n_objects;
3607   const char *data= m_data;
3608   Geometry_buffer buffer;
3609   Geometry *geom;
3610   double result;
3611 
3612   if (no_data(data, 4))
3613     return 1;
3614   n_objects= uint4korr(data);
3615   data+= 4;
3616   result= 0.0;
3617 
3618   if (n_objects == 0)
3619     goto exit;
3620 
3621   while (n_objects--)
3622   {
3623     uint32 wkb_type;
3624 
3625     if (no_data(data, WKB_HEADER_SIZE))
3626       return 1;
3627     wkb_type= uint4korr(data + 1);
3628     data+= WKB_HEADER_SIZE;
3629 
3630     if (!(geom= create_by_typeid(&buffer, wkb_type)))
3631       return 1;
3632     geom->set_data_ptr(data, (uint32) (m_data_end - data));
3633     if (geom->geom_length(len, &data))
3634       return 1;
3635     result+= *len;
3636   }
3637 
3638 exit:
3639   *end= data;
3640   *len= result;
3641   return 0;
3642 }
3643 
3644 
num_geometries(uint32 * num) const3645 int Gis_geometry_collection::num_geometries(uint32 *num) const
3646 {
3647   if (no_data(m_data, 4))
3648     return 1;
3649   *num= uint4korr(m_data);
3650   return 0;
3651 }
3652 
3653 
geometry_n(uint32 num,String * result) const3654 int Gis_geometry_collection::geometry_n(uint32 num, String *result) const
3655 {
3656   uint32 n_objects, wkb_type, length;
3657   const char *data= m_data;
3658   Geometry_buffer buffer;
3659   Geometry *geom;
3660 
3661   if (no_data(data, 4))
3662     return 1;
3663   n_objects= uint4korr(data);
3664   data+= 4;
3665   if (num > n_objects || num < 1)
3666     return 1;
3667 
3668   do
3669   {
3670     if (no_data(data, WKB_HEADER_SIZE))
3671       return 1;
3672     wkb_type= uint4korr(data + 1);
3673     data+= WKB_HEADER_SIZE;
3674 
3675     if (!(geom= create_by_typeid(&buffer, wkb_type)))
3676       return 1;
3677     geom->set_data_ptr(data, (uint) (m_data_end - data));
3678     if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
3679       return 1;
3680     data+= length;
3681   } while (--num);
3682 
3683   /* Copy found object to result */
3684   if (result->reserve(1 + 4 + length))
3685     return 1;
3686   result->q_append((char) wkb_ndr);
3687   result->q_append((uint32) wkb_type);
3688   result->q_append(data-length, length);	// data-length = start_of_data
3689   return 0;
3690 }
3691 
3692 
3693 /*
3694   Return dimension for object
3695 
3696   SYNOPSIS
3697     dimension()
3698     res_dim		Result dimension
3699     end			End of object will be stored here. May be 0 for
3700 			simple objects!
3701   RETURN
3702     0	ok
3703     1	error
3704 */
3705 
dimension(uint32 * res_dim,const char ** end) const3706 bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) const
3707 {
3708   uint32 n_objects;
3709   const char *data= m_data;
3710   Geometry_buffer buffer;
3711   Geometry *geom;
3712 
3713   if (no_data(data, 4))
3714     return 1;
3715   n_objects= uint4korr(data);
3716   data+= 4;
3717 
3718   *res_dim= 0;
3719   while (n_objects--)
3720   {
3721     uint32 wkb_type, length, dim;
3722     const char *end_data;
3723 
3724     if (no_data(data, WKB_HEADER_SIZE))
3725       return 1;
3726     wkb_type= uint4korr(data + 1);
3727     data+= WKB_HEADER_SIZE;
3728     if (!(geom= create_by_typeid(&buffer, wkb_type)))
3729       return 1;
3730     geom->set_data_ptr(data, (uint32) (m_data_end - data));
3731     if (geom->dimension(&dim, &end_data))
3732       return 1;
3733     set_if_bigger(*res_dim, dim);
3734     if (end_data)				// Complex object
3735       data= end_data;
3736     else if ((length= geom->get_data_size()) == GET_SIZE_ERROR)
3737       return 1;
3738     else
3739       data+= length;
3740   }
3741   *end= data;
3742   return 0;
3743 }
3744 
3745 
store_shapes(Gcalc_shape_transporter * trn) const3746 int Gis_geometry_collection::store_shapes(Gcalc_shape_transporter *trn) const
3747 {
3748   uint32 n_objects;
3749   const char *data= m_data;
3750   Geometry_buffer buffer;
3751   Geometry *geom;
3752 
3753   if (no_data(data, 4))
3754     return 1;
3755   n_objects= uint4korr(data);
3756   data+= 4;
3757 
3758   if (!n_objects)
3759   {
3760     trn->empty_shape();
3761     return 0;
3762   }
3763 
3764   if (trn->start_collection(n_objects))
3765     return 1;
3766 
3767   while (n_objects--)
3768   {
3769     uint32 wkb_type;
3770 
3771     if (no_data(data, WKB_HEADER_SIZE))
3772       return 1;
3773     wkb_type= uint4korr(data + 1);
3774     data+= WKB_HEADER_SIZE;
3775     if (!(geom= create_by_typeid(&buffer, wkb_type)))
3776       return 1;
3777     geom->set_data_ptr(data, (uint32) (m_data_end - data));
3778     if (geom->store_shapes(trn))
3779       return 1;
3780 
3781     data+= geom->get_data_size();
3782   }
3783   return 0;
3784 }
3785 
3786 
get_class_info() const3787 const Geometry::Class_info *Gis_geometry_collection::get_class_info() const
3788 {
3789   return &geometrycollection_class;
3790 }
3791 
3792 #endif /*HAVE_SPATIAL*/
3793