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