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