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