1 /*
2    Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
23 
24 #include "sql/spatial.h"
25 
26 #include <algorithm>
27 #include <cmath>  // isfinite
28 #include <map>
29 #include <memory>
30 #include <new>
31 #include <type_traits>
32 #include <utility>
33 
34 #include "m_ctype.h"
35 #include "m_string.h"
36 #include "my_byteorder.h"
37 #include "my_dbug.h"
38 #include "my_macros.h"
39 #include "my_sys.h"
40 #include "myisampack.h"
41 #include "mysqld_error.h"
42 #include "prealloced_array.h"
43 #include "sql/check_stack.h"  // check_stack_overrun
44 #include "sql/current_thd.h"
45 #include "sql/gis/srid.h"
46 #include "sql/gis_bg_traits.h"  // IWYU pragma: keep
47 #include "sql/gstream.h"        // Gis_read_stream
48 #include "sql/psi_memory_key.h"
49 #include "sql/sql_const.h"   // STACK_MIN_SIZE
50 #include "sql_string.h"      // String
51 #include "template_utils.h"  // pointer_cast
52 #include "unsafe_string_append.h"
53 
gis_wkb_alloc(size_t sz)54 void *gis_wkb_alloc(size_t sz) {
55   sz += GEOM_HEADER_SIZE;
56   char *p = static_cast<char *>(
57       my_malloc(key_memory_Geometry_objects_data, sz, MYF(MY_FAE)));
58   p += GEOM_HEADER_SIZE;
59   return p;
60 }
61 
gis_wkb_realloc(void * p,size_t sz)62 void *gis_wkb_realloc(void *p, size_t sz) {
63   char *cp = static_cast<char *>(p);
64   if (cp) cp -= GEOM_HEADER_SIZE;
65   sz += GEOM_HEADER_SIZE;
66 
67   p = my_realloc(key_memory_Geometry_objects_data, cp, sz, MYF(MY_FAE));
68   cp = static_cast<char *>(p);
69   return cp + GEOM_HEADER_SIZE;
70 }
71 
72 /***************************** MBR *******************************/
73 
74 /*
75   Returns 0/1 if this MBR doesn't/does touch mbr. Returns -1 if the MBRs
76   contain invalid data. This convention is true for all MBR relation test
77   functions.
78 */
touches(const MBR * mbr) const79 int MBR::touches(const MBR *mbr) const {
80   const MBR *mbr2 = mbr;
81   const MBR *mbr1 = this;
82   int ret = 0;
83   int dim1 = dimension();
84   int dim2 = mbr->dimension();
85 
86   DBUG_ASSERT(dim1 >= 0 && dim1 <= 2 && dim2 >= 0 && dim2 <= 2);
87   if (dim1 == 0 && dim2 == 0) return 0;
88   if (dim1 == 0 && dim2 == 1)
89     return ((mbr1->xmin == mbr2->xmin && mbr1->ymin == mbr2->ymin) ||
90             (mbr1->xmin == mbr2->xmax && mbr1->ymin == mbr2->ymax));
91   if (dim1 == 1 && dim2 == 0) return mbr->touches(this);
92 
93   DBUG_ASSERT(dim1 + dim2 >= 2);
94   ret = ((mbr2->xmin == mbr1->xmax || mbr2->xmax == mbr1->xmin) &&
95          (mbr1->ymin <= mbr2->ymax && mbr1->ymax >= mbr2->ymin)) ||
96         ((mbr2->ymin == mbr1->ymax || mbr2->ymax == mbr1->ymin) &&
97          (mbr1->xmin <= mbr2->xmax && mbr1->xmax >= mbr2->xmin));
98 
99   if (ret && dim1 == 1 && dim2 == 1) {
100     // The two line segments may overlap, rather than touch.
101     int overlaps = ((mbr1->ymin == mbr1->ymax && mbr1->ymin == mbr2->ymax &&
102                      mbr2->ymin == mbr2->ymax && mbr1->xmin < mbr2->xmax &&
103                      mbr1->xmax > mbr2->xmin) ||
104                     (mbr1->xmin == mbr1->xmax && mbr2->xmin == mbr2->xmax &&
105                      mbr1->xmin == mbr2->xmin && mbr1->ymin < mbr2->ymax &&
106                      mbr1->ymax > mbr2->ymin));
107     if (overlaps) ret = 0;
108   }
109 
110   return ret;
111 }
112 
within(const MBR * mbr) const113 int MBR::within(const MBR *mbr) const {
114   int dim1 = dimension();
115   int dim2 = mbr->dimension();
116 
117   DBUG_ASSERT(dim1 >= 0 && dim1 <= 2 && dim2 >= 0 && dim2 <= 2);
118 
119   /*
120     Either/both of the two operands can degrade to a point or a
121     horizontal/vertical line segment, and we have to treat such cases
122     separately.
123    */
124   switch (dim1) {
125     case 0:
126       DBUG_ASSERT(xmin == xmax && ymin == ymax);
127       switch (dim2) {
128         case 0:
129           DBUG_ASSERT(mbr->xmin == mbr->xmax && mbr->ymin == mbr->ymax);
130           return equals(mbr);
131           break;
132         case 1:
133           DBUG_ASSERT((mbr->xmin == mbr->xmax && mbr->ymin != mbr->ymax) ||
134                       (mbr->ymin == mbr->ymax && mbr->xmin != mbr->xmax));
135           return ((xmin > mbr->xmin && xmin < mbr->xmax && ymin == mbr->ymin) ||
136                   (ymin > mbr->ymin && ymin < mbr->ymax && xmin == mbr->xmin));
137           break;
138         case 2:
139           DBUG_ASSERT(mbr->xmin != mbr->xmax && mbr->ymin != mbr->ymax);
140           return (xmin > mbr->xmin && xmax < mbr->xmax && ymin > mbr->ymin &&
141                   ymax < mbr->ymax);
142           break;
143       }
144       break;
145     case 1:
146       DBUG_ASSERT((xmin == xmax && ymin != ymax) ||
147                   (ymin == ymax && xmin != xmax));
148       switch (dim2) {
149         case 0:
150           DBUG_ASSERT(mbr->xmin == mbr->xmax && mbr->ymin == mbr->ymax);
151           return 0;
152           break;
153         case 1:
154           DBUG_ASSERT((mbr->xmin == mbr->xmax && mbr->ymin != mbr->ymax) ||
155                       (mbr->ymin == mbr->ymax && mbr->xmin != mbr->xmax));
156           return (
157               (xmin == xmax && mbr->xmin == mbr->xmax && mbr->xmin == xmin &&
158                mbr->ymin <= ymin && mbr->ymax >= ymax) ||
159               (ymin == ymax && mbr->ymin == mbr->ymax && mbr->ymin == ymin &&
160                mbr->xmin <= xmin && mbr->xmax >= xmax));
161           break;
162         case 2:
163           DBUG_ASSERT(mbr->xmin != mbr->xmax && mbr->ymin != mbr->ymax);
164           return ((xmin == xmax && xmin > mbr->xmin && xmax < mbr->xmax &&
165                    ymin >= mbr->ymin && ymax <= mbr->ymax) ||
166                   (ymin == ymax && ymin > mbr->ymin && ymax < mbr->ymax &&
167                    xmin >= mbr->xmin && xmax <= mbr->xmax));
168           break;
169       }
170       break;
171     case 2:
172       DBUG_ASSERT(xmin != xmax && ymin != ymax);
173       switch (dim2) {
174         case 0:
175         case 1:
176           return 0;
177           break;
178         case 2:
179           DBUG_ASSERT(mbr->xmin != mbr->xmax && mbr->ymin != mbr->ymax);
180           return ((mbr->xmin <= xmin) && (mbr->ymin <= ymin) &&
181                   (mbr->xmax >= xmax) && (mbr->ymax >= ymax));
182           break;
183       }
184       break;
185   }
186 
187   // Never reached.
188   DBUG_ASSERT(false);
189   return 0;
190 }
191 
192 /*
193   exponential notation :
194   1   sign
195   1   number before the decimal point
196   1   decimal point
197   17  number of significant digits (see String::qs_append(double))
198   1   'e' sign
199   1   exponent sign
200   3   exponent digits
201   ==
202   25
203 
204   "f" notation :
205   1   optional 0
206   1   sign
207   17  number significant digits (see String::qs_append(double) )
208   1   decimal point
209   ==
210   20
211 */
212 
213 #define MAX_DIGITS_IN_DOUBLE 25
214 
215 /**
216   Distance to another point.
217 */
distance(const point_xy & p) const218 double point_xy::distance(const point_xy &p) const {
219   /* On 32bit platforms, sqrt(inf) may produce a wrong number that isn't inf. */
220   const double a = pow(x - p.x, 2.0);
221   if (!std::isfinite(a)) return a;
222   const double b = pow(y - p.y, 2.0);
223   if (!std::isfinite(a + b)) return a + b;
224   return sqrt(a + b);
225 }
226 
227 /***************************** Gis_class_info *******************************/
228 
229 String Geometry::bad_geometry_data("Bad object", &my_charset_bin);
230 
231 Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_last + 1] = {
232     nullptr};
233 
234 static Geometry::Class_info **ci_collection_end =
235     Geometry::ci_collection + Geometry::wkb_last + 1;
236 
Class_info(const char * name,int type_id,create_geom_t create_func)237 Geometry::Class_info::Class_info(const char *name, int type_id,
238                                  create_geom_t create_func)
239     : m_name{name, strlen(name)},
240       m_type_id(type_id),
241       m_create_func(create_func) {
242   ci_collection[type_id] = this;
243 }
244 
create_point(char * buffer)245 inline static Geometry *create_point(char *buffer) {
246   return ::new (buffer) Gis_point(false);
247 }
248 
create_linestring(char * buffer)249 inline static Geometry *create_linestring(char *buffer) {
250   return ::new (buffer) Gis_line_string(false);
251 }
252 
create_polygon(char * buffer)253 inline static Geometry *create_polygon(char *buffer) {
254   return ::new (buffer) Gis_polygon(false);
255 }
256 
create_multipoint(char * buffer)257 inline static Geometry *create_multipoint(char *buffer) {
258   return ::new (buffer) Gis_multi_point(false);
259 }
260 
create_multipolygon(char * buffer)261 inline static Geometry *create_multipolygon(char *buffer) {
262   return ::new (buffer) Gis_multi_polygon(false);
263 }
264 
create_multilinestring(char * buffer)265 inline static Geometry *create_multilinestring(char *buffer) {
266   return ::new (buffer) Gis_multi_line_string(false);
267 }
268 
create_geometrycollection(char * buffer)269 inline static Geometry *create_geometrycollection(char *buffer) {
270   return ::new (buffer) Gis_geometry_collection();
271 }
272 
273 /**
274   Check if geometry type sub is a subtype of super.
275 
276   Since Geometry::wkbType can't represent the geometry type, the
277   superclass of all geometry types, this function can't check
278   that. The supertype has to be a subtype of geometry.
279 
280   @param sub The type to check
281   @param super The supertype
282 
283   @return True if t1 is a subtype of t2
284  */
is_subtype_of(Geometry::wkbType sub,Geometry::wkbType super)285 inline static bool is_subtype_of(Geometry::wkbType sub,
286                                  Geometry::wkbType super) {
287   return (super == Geometry::wkb_geometrycollection &&
288           (sub == Geometry::wkb_multipoint ||
289            sub == Geometry::wkb_multilinestring ||
290            sub == Geometry::wkb_multipolygon));
291 }
292 
293 static Geometry::Class_info point_class("POINT", Geometry::wkb_point,
294                                         create_point);
295 
296 static Geometry::Class_info linestring_class("LINESTRING",
297                                              Geometry::wkb_linestring,
298                                              create_linestring);
299 static Geometry::Class_info polygon_class("POLYGON", Geometry::wkb_polygon,
300                                           create_polygon);
301 static Geometry::Class_info multipoint_class("MULTIPOINT",
302                                              Geometry::wkb_multipoint,
303                                              create_multipoint);
304 static Geometry::Class_info multilinestring_class("MULTILINESTRING",
305                                                   Geometry::wkb_multilinestring,
306                                                   create_multilinestring);
307 static Geometry::Class_info multipolygon_class("MULTIPOLYGON",
308                                                Geometry::wkb_multipolygon,
309                                                create_multipolygon);
310 static Geometry::Class_info geometrycollection_class(
311     "GEOMCOLLECTION", Geometry::wkb_geometrycollection,
312     create_geometrycollection);
313 
314 /***************************** Geometry *******************************/
315 
find_class(const char * name,size_t len)316 Geometry::Class_info *Geometry::find_class(const char *name, size_t len) {
317   for (Class_info **cur_rt = ci_collection; cur_rt < ci_collection_end;
318        cur_rt++) {
319     if (*cur_rt && (*cur_rt)->m_type_id == Geometry::wkb_geometrycollection) {
320       if (len == 18 &&
321           my_strnncoll(&my_charset_latin1,
322                        pointer_cast<const uchar *>("GEOMETRYCOLLECTION"), len,
323                        pointer_cast<const uchar *>(name), len) == 0)
324         return *cur_rt;
325     } else if (*cur_rt && ((*cur_rt)->m_name.length == len) &&
326                (my_strnncoll(&my_charset_latin1,
327                              pointer_cast<const uchar *>((*cur_rt)->m_name.str),
328                              len, pointer_cast<const uchar *>(name), len) == 0))
329       return *cur_rt;
330   }
331   return nullptr;
332 }
333 
create_by_typeid(Geometry_buffer * buffer,int type_id)334 Geometry *Geometry::create_by_typeid(Geometry_buffer *buffer, int type_id) {
335   Class_info *ci;
336   if (!(ci = find_class(type_id))) return nullptr;
337   return (*ci->m_create_func)(buffer->data);
338 }
339 
340 /**
341   Construct a Geometry object using GEOMETRY byte string. This function is
342   called by all GIS functions to make a Geometry object from a GEOMETRY byte
343   string, which can come from table storage, or returned from other GIS
344   function, or directly provided by user via client.
345 
346   The WKB can be of either endianess --- when user directly pass WKB
347   byte string to us, he/she can pass big endian WKB, otherwise the WKB is
348   always little endian. And we should reject big endian WKB because all the
349   rest of the GIS code assumes the internal WKB data being always little endian.
350 
351   @param buffer The place where the Geometry object is constructed on.
352   @param data is a byte string with an optional srid prepending a WKB format
353   byte string, which is called a GEOMETRY byte string and which is the inner
354   storage format of all geometries in MySQL.
355   @param data_len number of bytes of the byte string refered by data.
356   @param has_srid whether data argument starts with an srid or not.
357   By default it's true, if false, data starts with WKB header, and caller
358   is responsible to specify an srid to this object later.
359   @return Constructed geometry object.
360  */
construct(Geometry_buffer * buffer,const char * data,uint32 data_len,bool has_srid)361 Geometry *Geometry::construct(Geometry_buffer *buffer, const char *data,
362                               uint32 data_len, bool has_srid) {
363   uint32 geom_type;
364   Geometry *result;
365   wkbByteOrder bo;
366   String wkb_le;
367   uint32 srid_sz = has_srid ? SRID_SIZE : 0;
368   // Check the GEOMETRY byte string is valid, which would at least have an
369   // SRID, a WKB header, and 4 more bytes for object count or Point
370   // coordinate.
371   if (data_len < srid_sz + WKB_HEADER_SIZE + 4) return nullptr;
372 
373   bo = ::get_byte_order(data + srid_sz);
374 
375   if (bo != Geometry::wkb_ndr) {
376     my_error(ER_GIS_DATA_WRONG_ENDIANESS, MYF(0));
377     return nullptr;
378     /*
379       Don't try to convert endianess but error out because we can't
380       replace the bytes refered by data, it can be from any source.
381       Users can call GeometryFromWKB to use WKB of either endianess
382       if they have to pass WKB/Geometry byte string from client to us.
383      */
384   }
385 
386   /* + 1 to skip the byte order (stored in position SRID_SIZE). */
387   geom_type = uint4korr(data + srid_sz + 1);
388   if (geom_type < wkb_first || geom_type > wkb_last ||
389       !(result = create_by_typeid(buffer, (int)geom_type)))
390     return nullptr;
391 
392   gis::srid_t srid = 0;
393   if (has_srid) {
394     srid = uint4korr(data);
395     result->set_srid(srid);
396   }
397 
398   if (geom_type == wkb_point) {
399     if (data_len - srid_sz - WKB_HEADER_SIZE < POINT_DATA_SIZE) return nullptr;
400     result->set_data_ptr(data + srid_sz + WKB_HEADER_SIZE, POINT_DATA_SIZE);
401   } else
402     result->set_data_ptr(data + srid_sz + WKB_HEADER_SIZE,
403                          data_len - srid_sz - WKB_HEADER_SIZE);
404   result->has_geom_header_space(has_srid);
405   if (result->get_geotype() == wkb_polygon) result->polygon_is_wkb_form(true);
406 
407   /*
408     Check whether the GEOMETRY byte string is a valid and complete one.
409     Do not allow extra trailing bytes if this is a GEOMETRY byte string,
410     otherwise we are creating a geometry object using part of the byte string
411     which is longer than we need here but are not trash bytes.
412   */
413   const uint32 result_len = result->get_data_size();
414   const uint32 header_size = (has_srid ? GEOM_HEADER_SIZE : WKB_HEADER_SIZE);
415   if (result_len == GET_SIZE_ERROR ||
416       (has_srid && (result_len + header_size) != data_len))
417     return nullptr;
418 
419   return result;
420 }
421 
422 /**
423   Read wkt text from trs, and write little endian wkb encoding into 'wkt',
424   and create a Geometry instance in 'buffer'. If 'init_stream' is true,
425   shallow assign data in 'wkt' to the Geometry object to be returned.
426   @param buffer Place to create the returned Geometry object at.
427   @param trs WKT read stream.
428   @param wkb Little endian WKB buffer for WKB data of the returned Geometry
429   object.
430   @param init_stream Whether set WKB buffer pointer to returned Geometry
431   object.
432   @param check_trailing Whether to flag an error (by returning nullptr) if there
433   are trailing bytes in the string.
434   @return A Geometry object with data specified by the WKT.
435  */
create_from_wkt(Geometry_buffer * buffer,Gis_read_stream * trs,String * wkb,bool init_stream,bool check_trailing)436 Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer,
437                                     Gis_read_stream *trs, String *wkb,
438                                     bool init_stream, bool check_trailing) {
439   LEX_CSTRING name;
440   Class_info *ci;
441 
442   if (trs->get_next_word(&name)) {
443     trs->set_error_msg("Geometry name expected");
444     return nullptr;
445   }
446   if (!(ci = find_class(name.str, name.length)) ||
447       wkb->reserve(WKB_HEADER_SIZE, 512))
448     return nullptr;
449   Geometry *result = (*ci->m_create_func)(buffer->data);
450   q_append((char)wkb_ndr, wkb);
451   q_append((uint32)result->get_class_info()->m_type_id, wkb);
452 
453   if (result->init_from_wkt(trs, wkb) ||
454       (check_trailing && !trs->is_end_of_stream()))
455     return nullptr;
456 
457   if (init_stream)
458     result->set_data_ptr(wkb->ptr() + WKB_HEADER_SIZE,
459                          wkb->length() - WKB_HEADER_SIZE);
460   result->has_geom_header_space(true);
461   if (result->get_geotype() == wkb_polygon) result->polygon_is_wkb_form(true);
462 
463   return result;
464 }
465 
466 /**
467   Write this geometry's WKB byte string into specified buffer, the SRID is
468   not written into the buffer.
469 
470   @param wkb The buffer to write WKB byte string into.
471   @param shallow_copy Whether do shallow copy by using this object's memory
472          without owning it or duplicating the byte string.
473   @return true if got error, false if successful.
474  */
as_wkb(String * wkb,bool shallow_copy) const475 bool Geometry::as_wkb(String *wkb, bool shallow_copy) const {
476   DBUG_ASSERT(wkb->ptr() < get_cptr() - GEOM_HEADER_SIZE ||
477               wkb->ptr() > get_cptr() + get_nbytes());
478 
479   if (shallow_copy) {
480     /*
481       This object must have GEOMETRY header space, and we simply assign to
482       wkb, the memory is still owned by the String object of this Geometry
483       object, i.e. the String object holding WKB data for this object.
484 
485       Don't write to this object's own String buffer.
486      */
487     DBUG_ASSERT(wkb->ptr() != get_cptr() - GEOM_HEADER_SIZE);
488 
489     DBUG_ASSERT(!(get_geotype() == wkb_polygon &&
490                   (!polygon_is_wkb_form() || is_bg_adapter())));
491     wkb->set(get_cptr() - WKB_HEADER_SIZE, get_nbytes() + WKB_HEADER_SIZE,
492              &my_charset_bin);
493     return false;
494   }
495 
496   if (wkb->reserve(WKB_HEADER_SIZE + this->get_nbytes(), 512) ||
497       get_data_ptr() == nullptr)
498     return true;
499 
500   write_wkb_header(wkb, get_geotype());
501   if (get_geotype() != wkb_polygon)
502     q_append(static_cast<const char *>(this->get_data_ptr()),
503              this->get_nbytes(), wkb);
504   else {
505     size_t len = 0;
506     void *ptr = get_packed_ptr(this, &len);
507     wkb->append(static_cast<char *>(ptr), len);
508     gis_wkb_free(ptr);
509   }
510 
511   return false;
512 }
513 
514 /**
515   Write this geometry's GEOMETRY byte string into specified buffer, the SRID
516   will be written before the WKB string to form a GEOMETRY byte string.
517 
518   @param buf The buffer to write GEOMETRY byte string into.
519   @param shallow_copy Whether do shallow copy by using this object's memory
520          without owning it or duplicating the byte string.
521   @return true if got error, false if successful.
522 */
as_geometry(String * buf,bool shallow_copy) const523 bool Geometry::as_geometry(String *buf, bool shallow_copy) const {
524   if (shallow_copy) {
525     /*
526       This object must have GEOMETRY header space, and we simply assign to
527       buf, the memory is still owned by the String object of this Geometry
528       object, i.e. the String object holding WKB data for this object.
529 
530       Don't write to this object's own String buffer.
531      */
532     DBUG_ASSERT(has_geom_header_space());
533 
534     DBUG_ASSERT(!(get_geotype() == wkb_polygon &&
535                   (!polygon_is_wkb_form() || is_bg_adapter())));
536 
537     if (buf->ptr() != get_cptr() - GEOM_HEADER_SIZE) {
538       DBUG_ASSERT(buf->ptr() < get_cptr() - GEOM_HEADER_SIZE ||
539                   buf->ptr() > get_cptr() + get_nbytes());
540       buf->set(get_cptr() - GEOM_HEADER_SIZE, get_nbytes() + GEOM_HEADER_SIZE,
541                &my_charset_bin);
542     }
543     return false;
544   }
545 
546   if ((buf->ptr() == get_cptr() - GEOM_HEADER_SIZE)) {
547     if (buf->is_alloced()) return false;
548   } else
549     DBUG_ASSERT(buf->ptr() < get_cptr() - GEOM_HEADER_SIZE ||
550                 buf->ptr() > get_cptr() + get_nbytes());
551 
552   if (buf->reserve(SRID_SIZE + WKB_HEADER_SIZE + this->get_nbytes(), 512) ||
553       get_data_ptr() == nullptr)
554     return true;
555 
556   write_geometry_header(buf, get_srid(), get_geotype());
557   if (get_geotype() != wkb_polygon)
558     q_append(static_cast<const char *>(this->get_data_ptr()),
559              this->get_nbytes(), buf);
560   else {
561     size_t len = 0;
562     void *ptr = get_packed_ptr(this, &len);
563     buf->append(static_cast<char *>(ptr), len);
564     gis_wkb_free(ptr);
565   }
566   return false;
567 }
568 
569 /**
570   WKB scanner event handler that checks if the WKB string is well formed.
571 
572   This doesn't check if the geometry is valid (e.g., it's not checking
573   if a polygon is self-intersecting), it only checks some simple rules
574   for WKB well-formedness:
575 
576   R1. The byte order is as specified (constructor parameter)
577   R2. The wkbType is within the supported range
578   R3. The geometry is of the specified type (constructor parameter),
579       or a subtype
580   R4. Nested geometries contain only geometries that can be contained
581       by that type
582   R5. Linestrings have at least two points
583   R6. Polygon rings have at least four points
584   R7. Polygons have at least one ring
585   R8. Collections, except geometrycollection, contain at least one
586       element.
587 
588   An additional requirement, that the WKB ends exactly at the end of
589   the string, is checked by Geometry::is_well_formed(). The last parse
590   position is maintained as last_position here to make that test
591   possible.
592  */
593 class Geometry_well_formed_checker : public WKB_scanner_event_handler {
594  private:
595   Prealloced_array<Geometry::wkbType, 8> type;  /// Current stack of types
596   Geometry::wkbType previous_type;              /// Type of previous start/end
597   int points_in_linestring;                     /// Points in current ls
598   const void *last_position;                    /// Last wkb pointer seen
599   bool is_ok;                                   /// Whether the WKB is OK so far
600   Geometry::wkbByteOrder required_byte_order;
601 
602  public:
603   /**
604     Create a new even handler.
605 
606     @param type Expected geometry type. If set to
607                 Geometry::wkb_invalid_type, any geometry is allowed.
608     @param required_byte_order The expected byted order
609    */
Geometry_well_formed_checker(Geometry::wkbType type,Geometry::wkbByteOrder required_byte_order)610   Geometry_well_formed_checker(Geometry::wkbType type,
611                                Geometry::wkbByteOrder required_byte_order)
612       : type(PSI_NOT_INSTRUMENTED),
613         previous_type(Geometry::wkb_invalid_type),
614         points_in_linestring(0),
615         last_position(nullptr),
616         is_ok(true),
617         required_byte_order(required_byte_order) {
618     this->type.push_back(type);
619   }
620 
on_wkb_start(Geometry::wkbByteOrder bo,Geometry::wkbType geotype,const void *,uint32,bool has_hdr)621   virtual void on_wkb_start(Geometry::wkbByteOrder bo,
622                             Geometry::wkbType geotype, const void *, uint32,
623                             bool has_hdr) {
624     if (!is_ok) return;
625 
626     // The byte order must be the specified one (R1).
627     if (required_byte_order != Geometry::wkb_invalid &&
628         bo != required_byte_order) {
629       is_ok = false;
630       return;
631     }
632 
633     Geometry::wkbType outer_type = type[type.size() - 1];
634 
635     type.push_back(geotype);
636     previous_type = geotype;
637 
638     // The geometry type must be in the valid range (R2).
639     if (geotype < Geometry::wkb_first ||
640         geotype > Geometry::wkb_geometrycollection) {
641       is_ok = false;
642       return;
643     }
644 
645     // First geometry must be of the specified type (if specified), or
646     // a subtype (R3).
647     if (type.size() == 2) {
648       if (geotype != outer_type && outer_type != Geometry::wkb_invalid_type &&
649           !is_subtype_of(geotype, outer_type))
650         is_ok = false;
651       return;
652     }
653 
654     // Any type is allowed in geometry collections (R4).
655     if (outer_type == Geometry::wkb_geometrycollection) return;
656 
657     switch (geotype) {
658       case Geometry::wkb_point:
659         // Points can only appear in multipoints and in linestrings (R4).
660         if (!(outer_type == Geometry::wkb_multipoint ||
661               (!has_hdr && outer_type == Geometry::wkb_linestring)))
662           is_ok = false;
663         if (outer_type == Geometry::wkb_linestring) ++points_in_linestring;
664         break;
665       case Geometry::wkb_linestring:
666         // Linestrings can only appear in multilinestrings and as rings
667         // in polygons (R4).
668         if (!(outer_type == Geometry::wkb_multilinestring ||
669               (!has_hdr && outer_type == Geometry::wkb_polygon)))
670           is_ok = false;
671         break;
672       case Geometry::wkb_polygon:
673         // Polygons can only appear in multipolygons (R4).
674         if (outer_type != Geometry::wkb_multipolygon) is_ok = false;
675         break;
676       case Geometry::wkb_multipoint:
677       case Geometry::wkb_multilinestring:
678       case Geometry::wkb_multipolygon:
679       case Geometry::wkb_geometrycollection:
680         // These are only allowed if outer_type is geometry collection,
681         // in which case they're handled before entering the switch (R4).
682         is_ok = false;
683         break;
684       default:
685         // The list of cases above should be complete (R2).
686         DBUG_ASSERT(0);
687         break;
688     }
689   }
690 
on_wkb_end(const void * wkb)691   virtual void on_wkb_end(const void *wkb) {
692     if (!is_ok) return;
693 
694     Geometry::wkbType current_type = type[type.size() - 1];
695     type.pop_back();
696     last_position = wkb;
697 
698     switch (current_type) {
699       case Geometry::wkb_linestring:
700         // Linestrings must have at least two points. Polygon rings must
701         // have at least four points (R5, R6).
702         if (points_in_linestring < 2 ||
703             (type[type.size() - 1] == Geometry::wkb_polygon &&
704              points_in_linestring < 4))
705           is_ok = false;
706         points_in_linestring = 0;
707         break;
708       case Geometry::wkb_polygon:
709         // Polygons must have at least one ring (R7).
710         if (previous_type != Geometry::wkb_linestring) is_ok = false;
711         break;
712       case Geometry::wkb_multipoint:
713         // Multipoints must contain at least one point (R8).
714         if (previous_type != Geometry::wkb_point) is_ok = false;
715         break;
716       case Geometry::wkb_multilinestring:
717         // Multilinestrings must contain at least one linestring (R8).
718         if (previous_type != Geometry::wkb_linestring) is_ok = false;
719         break;
720       case Geometry::wkb_multipolygon:
721         // Multipolygons must contain at least one polygon (R8).
722         if (previous_type != Geometry::wkb_polygon) is_ok = false;
723         break;
724       default:
725         break;
726     }
727 
728     previous_type = current_type;
729   }
730 
continue_scan() const731   virtual bool continue_scan() const { return is_ok; }
732 
733   /**
734     Check if the parsed WKB was well-formed, as far as this handler
735     knows.
736 
737     There may be other conditions that cause the object to not be
738     well-formed.
739 
740     @see Geometry::is_well_formed
741 
742     @return True if the WKB was well-formed, false otherwise.
743    */
is_well_formed()744   bool is_well_formed() { return is_ok; }
745 
746   /**
747     Get the position after the last parsed byte.
748 
749     @return Pointer pointing to after the last parsed byte.
750   */
get_last_position()751   const char *get_last_position() {
752     return static_cast<const char *>(last_position);
753   }
754 };
755 
is_well_formed(const char * from,size_t length,Geometry::wkbType type,Geometry::wkbByteOrder bo)756 bool Geometry::is_well_formed(const char *from, size_t length,
757                               Geometry::wkbType type,
758                               Geometry::wkbByteOrder bo) {
759   bool is_well_formed = true;
760   Geometry_well_formed_checker checker(type, bo);
761   uint32 len = length - SRID_SIZE;
762 
763   if (length < GEOM_HEADER_SIZE) return false;
764 
765   is_well_formed = (wkb_scanner(current_thd, from + SRID_SIZE, &len, 0, true,
766                                 &checker) != nullptr);
767 
768   return (is_well_formed && checker.is_well_formed() &&
769           checker.get_last_position() == from + length);
770 }
771 
wkb_get_double(const char * ptr,Geometry::wkbByteOrder bo)772 static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo) {
773   if (bo == Geometry::wkb_ndr)
774     return float8get(ptr);
775   else
776     return mi_float8get(pointer_cast<const uchar *>(ptr));
777 }
778 
779 /**
780    Check that a pair of geographic coordinates are within the valid range.
781 
782    Checks if the coordinates are within the allowed range for geographic
783    coordinates. Valid range for longitude and latitude coordinates in geographic
784    spatial reference systems are (-180, 180) and [-90, 90] degrees,
785    respectively.
786 
787    @param[in] x Longitude coordinate.
788    @param[in] y Latitude coordinate.
789    @param[in] srs_angular_unit Unit to radians conversion factor.
790    @param[out] long_out_of_range Longitude is out of range.
791    @param[out] lat_out_of_range Latitude is out of range.
792    @param[out] out_of_range_value The value that is out of range.
793 
794    @retval false Coordinates are within allowed range.
795    @retval true Coordinates are not within allowed range.
796 */
797 
check_coordinate_range(double x,double y,double srs_angular_unit,bool * long_out_of_range,bool * lat_out_of_range,double * out_of_range_value)798 static bool check_coordinate_range(double x, double y, double srs_angular_unit,
799                                    bool *long_out_of_range,
800                                    bool *lat_out_of_range,
801                                    double *out_of_range_value) {
802   // Check if longitude coordinates are within allowed range.
803   if (x * srs_angular_unit <= -M_PI || x * srs_angular_unit > M_PI) {
804     *long_out_of_range = true;
805     *out_of_range_value = x;
806     return true;
807   }
808 
809   // Check if latitude coordinates are within allowed range.
810   if (y * srs_angular_unit < -M_PI_2 || y * srs_angular_unit > M_PI_2) {
811     *lat_out_of_range = true;
812     *out_of_range_value = y;
813     return true;
814   }
815 
816   return false;
817 }
818 
wkb_get_uint(const char * ptr,Geometry::wkbByteOrder bo)819 static uint32 wkb_get_uint(const char *ptr, Geometry::wkbByteOrder bo) {
820   if (bo == Geometry::wkb_ndr)
821     return uint4korr(ptr);
822   else
823     return mi_uint4korr(pointer_cast<const uchar *>(ptr));
824 }
825 
826 /**
827   Scan WKB byte string and notify WKB events by calling registered callbacks.
828   @param wkb a little endian WKB byte string of 'len' bytes, with or
829              without WKB header.
830   @param[in] thd Thread context.
831   @param [in,out] len remaining number of bytes of the wkb string.
832   @param geotype the type of the geometry to be scanned.
833   @param has_hdr whether the 'wkb' point to a WKB header or right after
834                 the header. If it is true, the
835                 'geotype' should be the same as the type in the header;
836                 otherwise, and we will use the type specified in WKB header.
837   @param handler the registered WKB_scanner_event_handler object to be notified.
838   @return the next byte after last valid geometry just scanned, or NULL on error
839  */
wkb_scanner(THD * thd,const char * wkb,uint32 * len,uint32 geotype,bool has_hdr,WKB_scanner_event_handler * handler)840 const char *wkb_scanner(THD *thd, const char *wkb, uint32 *len, uint32 geotype,
841                         bool has_hdr, WKB_scanner_event_handler *handler) {
842   if (check_stack_overrun(current_thd, STACK_MIN_SIZE, nullptr)) return nullptr;
843 
844   Geometry::wkbType gt;
845   const char *q = nullptr;
846   uint32 ngeos = 0, comp_type = 0, gtype = 0;
847   bool comp_hashdr = false, done = false;
848 
849   if (has_hdr) {
850     if (*len < WKB_HEADER_SIZE) return nullptr;  // Invalid WKB data.
851 
852     gtype = uint4korr(wkb + 1);
853     // The geotype isn't used in this case.
854     if (geotype != gtype && geotype != 0 /* unknown */) return nullptr;
855 
856     if ((*wkb != Geometry::wkb_ndr && *wkb != Geometry::wkb_xdr) ||
857         gtype < Geometry::wkb_first || gtype > Geometry::wkb_last)
858       return nullptr;
859 
860     gt = static_cast<Geometry::wkbType>(gtype);
861 
862     q = wkb + WKB_HEADER_SIZE;
863     *len -= WKB_HEADER_SIZE;
864     if (*len <= 0) return nullptr;
865     handler->on_wkb_start(get_byte_order(wkb), gt, q, *len, true);
866     if (!handler->continue_scan()) return nullptr;
867   } else {
868     DBUG_ASSERT(geotype >= Geometry::wkb_first &&
869                 geotype <= Geometry::wkb_last);
870     q = wkb;
871     gt = static_cast<Geometry::wkbType>(geotype);
872     handler->on_wkb_start(Geometry::wkb_ndr, gt, q, *len, false);
873     if (!handler->continue_scan()) return nullptr;
874   }
875 
876   if (gt != Geometry::wkb_point) {
877     if (*len < 4) return nullptr;
878     ngeos = uint4korr(q);
879     q += sizeof(uint32);
880     *len -= 4;
881   }
882 
883   switch (gt) {
884     case Geometry::wkb_point:
885       if (*len < POINT_DATA_SIZE) return nullptr;
886       q += POINT_DATA_SIZE;
887       *len -= POINT_DATA_SIZE;
888       done = true;
889       handler->on_wkb_end(q);
890       if (!handler->continue_scan()) return nullptr;
891       break;
892     case Geometry::wkb_linestring:
893       comp_type = Geometry::wkb_point;
894       break;
895     case Geometry::wkb_polygon:
896       comp_type = Geometry::wkb_linestring;
897       break;
898     case Geometry::wkb_multipoint:
899       comp_type = Geometry::wkb_point;
900       comp_hashdr = true;
901       break;
902     case Geometry::wkb_multilinestring:
903       comp_type = Geometry::wkb_linestring;
904       comp_hashdr = true;
905       break;
906     case Geometry::wkb_multipolygon:
907       comp_type = Geometry::wkb_polygon;
908       comp_hashdr = true;
909       break;
910     case Geometry::wkb_geometrycollection:
911       comp_hashdr = true;
912       break;
913     default:
914       DBUG_ASSERT(false);
915       break;
916   }
917 
918   if (!done && q != nullptr) {
919     for (uint32 i = 0; i < ngeos; i++) {
920       q = wkb_scanner(thd, q, len, comp_type, comp_hashdr, handler);
921       if (q == nullptr) return nullptr;
922     }
923     handler->on_wkb_end(q);
924     if (!handler->continue_scan()) return nullptr;
925   }
926 
927   return q;
928 }
929 
930 /**
931   Read from 'wkb' (which contains WKB encoded in either endianess) the
932   geometry data, and write WKB of returned Geometry object in little endianess
933   into 'res', and also create geometry object on 'buffer' and return it.
934   The returned Geometry object points to bytes (without WKB HEADER) in 'res'.
935 
936   @param thd Thread context.
937   @param buffer the place to create the returned Geometry object at.
938   @param wkb the input WKB buffer which contains WKB of either endianess.
939   @param len the number of bytes of WKB in 'wkb'.
940   @param res the buffer to write little endian WKB into.
941   @param init_stream Whether set WKB buffer pointer to returned Geometry
942   object.
943   @return the created Geometry object.
944  */
create_from_wkb(THD * thd,Geometry_buffer * buffer,const char * wkb,uint32 len,String * res,bool init_stream)945 Geometry *Geometry::create_from_wkb(THD *thd, Geometry_buffer *buffer,
946                                     const char *wkb, uint32 len, String *res,
947                                     bool init_stream) {
948   uint32 geom_type;
949   Geometry *geom;
950 
951   if (len < WKB_HEADER_SIZE) return nullptr;
952 
953   geom_type = wkb_get_uint(wkb + 1, ::get_byte_order(wkb));
954   if ((*wkb != wkb_xdr && *wkb != wkb_ndr) || geom_type < wkb_first ||
955       geom_type > wkb_last ||
956       !(geom = create_by_typeid(buffer, (int)geom_type)) ||
957       res->reserve(WKB_HEADER_SIZE, 512))
958     return nullptr;
959 
960   q_append((char)wkb_ndr, res);
961   q_append(geom_type, res);
962 
963   uint tret =
964       geom->init_from_wkb(thd, wkb + WKB_HEADER_SIZE, len - WKB_HEADER_SIZE,
965                           ::get_byte_order(wkb), res);
966 
967   // The WKB string is invalid if it has trailing trash bytes.
968   if (tret != len - WKB_HEADER_SIZE) return nullptr;
969 
970   if (init_stream)
971     geom->set_data_ptr(res->ptr() + WKB_HEADER_SIZE,
972                        res->length() - WKB_HEADER_SIZE);
973   geom->has_geom_header_space(true);
974   if (geom->get_geotype() == wkb_polygon) geom->polygon_is_wkb_form(true);
975   return tret ? geom : nullptr;
976 }
977 
envelope(MBR * mbr) const978 bool Geometry::envelope(MBR *mbr) const {
979   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
980 
981   if (get_mbr(mbr, &wkb)) return true;
982 
983   return false;
984 }
985 
986 class GeomColl_component_counter : public WKB_scanner_event_handler {
987  public:
988   size_t num;
989 
GeomColl_component_counter()990   GeomColl_component_counter() : num(0) {}
991 
on_wkb_start(Geometry::wkbByteOrder,Geometry::wkbType geotype,const void *,uint32,bool)992   virtual void on_wkb_start(Geometry::wkbByteOrder, Geometry::wkbType geotype,
993                             const void *, uint32, bool) {
994     if (geotype != Geometry::wkb_geometrycollection) num++;
995   }
996 
on_wkb_end(const void *)997   virtual void on_wkb_end(const void *) {}
998 };
999 
envelope(String * result) const1000 bool Geometry::envelope(String *result) const {
1001   MBR mbr;
1002   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
1003 
1004   if (result->reserve(1 + 4 * 3 + SIZEOF_STORED_DOUBLE * 10)) return true;
1005 
1006   if (get_mbr(&mbr, &wkb)) {
1007     /*
1008       The geometry has no effective components in this branch, which is
1009       impossible for geometries other than geometry collections(GC).
1010       A GC may have empty nested GCs.
1011     */
1012     if (get_type() != wkb_geometrycollection) return true;
1013 
1014     uint32 num = uint4korr(get_cptr());
1015     if (num != 0) {
1016       GeomColl_component_counter counter;
1017       uint32 wkb_len = get_data_size();
1018 
1019       wkb_scanner(current_thd, get_cptr(), &wkb_len,
1020                   Geometry::wkb_geometrycollection, false, &counter);
1021       // Non-empty nested geometry collections.
1022       if (counter.num > 0) return true;
1023     }
1024 
1025     // An empty geometry collection's envelope is an empty geometry.
1026     write_wkb_header(result, wkb_geometrycollection, 0);
1027     return false;
1028   }
1029 
1030   q_append(static_cast<char>(wkb_ndr), result);
1031 
1032   int dim = mbr.dimension();
1033   if (dim < 0) return true;
1034 
1035   uint32 num_elems, num_elems2;
1036 
1037   if (dim == 0) {
1038     q_append(static_cast<uint32>(wkb_point), result);
1039     q_append(mbr.xmin, result);
1040     q_append(mbr.ymin, result);
1041   } else if (dim == 1) {
1042     q_append(static_cast<uint32>(wkb_linestring), result);
1043     num_elems = 2;
1044     q_append(num_elems, result);
1045     q_append(mbr.xmin, result);
1046     q_append(mbr.ymin, result);
1047     q_append(mbr.xmax, result);
1048     q_append(mbr.ymax, result);
1049   } else {
1050     q_append(static_cast<uint32>(wkb_polygon), result);
1051     num_elems = 1;
1052     q_append(num_elems, result);
1053     num_elems2 = 5;
1054     q_append(num_elems2, result);
1055     q_append(mbr.xmin, result);
1056     q_append(mbr.ymin, result);
1057     q_append(mbr.xmax, result);
1058     q_append(mbr.ymin, result);
1059     q_append(mbr.xmax, result);
1060     q_append(mbr.ymax, result);
1061     q_append(mbr.xmin, result);
1062     q_append(mbr.ymax, result);
1063     q_append(mbr.xmin, result);
1064     q_append(mbr.ymin, result);
1065   }
1066   return false;
1067 }
1068 
1069 /**
1070   Create a point from data.
1071 
1072   @param [out] result   Put result here
1073   @param wkb          Data for point is here.
1074 
1075   @return             false on success, true on error
1076 */
1077 
create_point(String * result,wkb_parser * wkb) const1078 bool Geometry::create_point(String *result, wkb_parser *wkb) const {
1079   if (wkb->no_data(POINT_DATA_SIZE) ||
1080       result->reserve(WKB_HEADER_SIZE + POINT_DATA_SIZE, 32))
1081     return true;
1082   q_append((char)wkb_ndr, result);
1083   q_append((uint32)wkb_point, result);
1084   /* Copy two double in same format */
1085   q_append(wkb->data(), POINT_DATA_SIZE, result);
1086   return false;
1087 }
1088 
1089 /**
1090   Create a point from coordinates.
1091 
1092   @param [out] result The resulting point
1093   @param p  coordinates for point
1094 
1095   @return  false on success, true on error
1096 */
1097 
create_point(String * result,point_xy p) const1098 bool Geometry::create_point(String *result, point_xy p) const {
1099   if (result->reserve(1 + 4 + POINT_DATA_SIZE, 32)) return true;
1100 
1101   q_append((char)wkb_ndr, result);
1102   q_append((uint32)wkb_point, result);
1103   q_append(p.x, result);
1104   q_append(p.y, result);
1105   return false;
1106 }
1107 
1108 /**
1109   Append N points from packed format to text
1110   Before calling this function, caller must have already checked that wkb's
1111   buffer is complete and not truncated.
1112 
1113   @param [out] txt        Append points here
1114   @param     n_points   Number of points
1115   @param     wkb        Packed data
1116   @param     offset     Offset between points
1117   @param     bracket_pt whether to bracket the point coordinate with (),
1118                         multipoint need so.
1119 */
1120 
append_points(String * txt,uint32 n_points,wkb_parser * wkb,uint32 offset,bool bracket_pt) const1121 void Geometry::append_points(String *txt, uint32 n_points, wkb_parser *wkb,
1122                              uint32 offset, bool bracket_pt) const {
1123   DBUG_ASSERT(0.0 == 0 && 0 == -0 && -0.0 == 0.0);
1124 
1125   while (n_points--) {
1126     point_xy p;
1127     wkb->skip_unsafe(offset);
1128     wkb->scan_xy_unsafe(&p);
1129     txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 1);
1130     if (bracket_pt) qs_append('(', txt);
1131     qs_append(p.x, MAX_DIGITS_IN_DOUBLE, txt);
1132     qs_append(' ', txt);
1133     qs_append(p.y, MAX_DIGITS_IN_DOUBLE, txt);
1134     if (bracket_pt) qs_append(')', txt);
1135     qs_append(',', txt);
1136   }
1137 }
1138 
1139 /**
1140   Get most bounding rectangle (mbr) for X points
1141 
1142   @param [out] mbr      Result
1143   @param wkb          Data for point is here.
1144   @param offset       Offset between points
1145 
1146   @return             false on success, true on error
1147 */
1148 
get_mbr_for_points(MBR * mbr,wkb_parser * wkb,uint offset) const1149 bool Geometry::get_mbr_for_points(MBR *mbr, wkb_parser *wkb,
1150                                   uint offset) const {
1151   uint32 n_points;
1152 
1153   if (wkb->scan_n_points_and_check_data(&n_points, offset)) return true;
1154 
1155   /* Calculate MBR for points */
1156   while (n_points--) {
1157     wkb->skip_unsafe(offset);
1158 
1159     point_xy p;
1160     wkb->scan_xy_unsafe(&p);
1161     if (!std::isfinite(p.x) || !std::isfinite(p.y)) return true;
1162     mbr->add_xy(p);
1163   }
1164   return false;
1165 }
1166 
Geometry(const Geometry & geo)1167 Geometry::Geometry(const Geometry &geo) {
1168 #if !defined(DBUG_OFF)
1169   wkbType geotype = geo.get_geotype();
1170 #endif
1171   DBUG_ASSERT(is_valid_geotype(geotype) &&
1172               ((geo.get_ptr() != nullptr && geo.get_nbytes() > 0) ||
1173                (geo.get_ptr() == nullptr && geo.get_nbytes() == 0) ||
1174                (geo.get_geotype() == wkb_polygon && geo.get_nbytes() == 0)));
1175 
1176   m_ptr = geo.m_ptr;
1177   m_flags = geo.m_flags;
1178   m_owner = geo.m_owner;
1179   set_srid(geo.get_srid());
1180 }
1181 
~Geometry()1182 Geometry::~Geometry() {
1183 /*
1184   Make sure no exceptions can be thrown in destructors of Geometry classes,
1185   by asserting in debug builds, so that future code won't accidentally throw.
1186 
1187   If an exception is thrown when we destroy a geometry object G,
1188   although the exception will still be caught and converted to MySQL
1189   error report, the geometries that are in the same container as G and
1190   that are placed after G will not be properly destroyed. This is the
1191   problem we want to address/avoid by forbiding throwing exceptions in
1192   destructors of Geometry classes.
1193 
1194   Since DBUG_ASSERT only works when DBUG_OFF is not defined, the
1195   try/catch is only enabled here depending on the same condition, so that
1196   in release builds we don't have the overhead of the try-catch statement.
1197 
1198   This is true also for destructors of children classes of Geometry.
1199 */
1200 #if !defined(DBUG_OFF)
1201   try {
1202 #endif
1203     if (!is_bg_adapter()) return;
1204 
1205     Geometry::wkbType gt = get_geotype();
1206 
1207     if (gt != Geometry::wkb_polygon) {
1208       if (get_ownmem() && m_ptr) {
1209         set_ownmem(false);
1210         gis_wkb_free(m_ptr);
1211         m_ptr = nullptr;
1212       }
1213 
1214       set_nbytes(0);
1215     }
1216 
1217     donate_data();
1218 
1219 #if !defined(DBUG_OFF)
1220   } catch (...) {
1221     // Should never throw exceptions in destructor.
1222     DBUG_ASSERT(false);
1223   }
1224 #endif
1225 }
1226 
1227 /**
1228   Assignment operator for Geometry class, assignment operators of children
1229   classes calls this to do general assignment.
1230   */
operator =(const Geometry & rhs)1231 Geometry &Geometry::operator=(const Geometry &rhs) {
1232   if (this == &rhs) return *this;
1233 
1234 #if !defined(DBUG_OFF)
1235   Geometry::wkbType geotype = rhs.get_geotype();
1236 #endif
1237   DBUG_ASSERT((is_bg_adapter() || rhs.is_bg_adapter()) &&
1238               m_flags.geotype == rhs.m_flags.geotype &&
1239               is_valid_geotype(geotype));
1240 
1241   set_bg_adapter(true);
1242 
1243   /*
1244     Update the mutable state of rhs.
1245    */
1246   rhs.set_bg_adapter(true);
1247   set_srid(rhs.get_srid());
1248   // Don't set_flags, it's done in operator= of children classes.
1249 
1250   return *this;
1251 }
1252 
1253 /***************************** Point *******************************/
1254 
Gis_point(const self & pt)1255 Gis_point::Gis_point(const self &pt) : Geometry(pt) {
1256   size_t nbytes = get_nbytes();
1257   DBUG_ASSERT((nbytes == SIZEOF_STORED_DOUBLE * GEOM_DIM || nbytes == 0));
1258   if (nbytes == 0) {
1259     DBUG_ASSERT(get_ownmem() == false);
1260     // Allocate even if pt isn't initialized with proper value, this is
1261     // required behavior from Boost Geometry.
1262     nbytes = SIZEOF_STORED_DOUBLE * GEOM_DIM;
1263     set_nbytes(nbytes);
1264   }
1265 
1266   m_ptr = gis_wkb_fixed_alloc(nbytes);
1267   if (m_ptr == nullptr) {
1268     set_nbytes(0);
1269     set_ownmem(false);
1270     return;
1271   }
1272 
1273   if (pt.get_nbytes() > 0)
1274     memcpy(m_ptr, pt.get_ptr(), pt.get_nbytes());
1275   else
1276     memset(m_ptr, 0, nbytes);
1277   set_ownmem(true);
1278 }
1279 
1280 /**
1281   Deep assignment from point 'p' to this object.
1282   @param rhs the Gis_point to duplicate from.
1283 */
operator =(const Gis_point & rhs)1284 Gis_point &Gis_point::operator=(const Gis_point &rhs) {
1285   if (this == &rhs) return *this;
1286   Geometry::operator=(rhs);
1287 
1288   // This point may or may not have own memory. we allow this because in bg,
1289   // std::reverse is called to reverse a linestring/ring, and also,
1290   // points are of equal size. Not allowed on any other type of geometries.
1291   DBUG_ASSERT(
1292       (m_ptr != nullptr && get_nbytes() == SIZEOF_STORED_DOUBLE * GEOM_DIM) ||
1293       (m_ptr == nullptr && get_nbytes() == 0 && !get_ownmem()));
1294 
1295   DBUG_ASSERT(
1296       (rhs.get_ptr() != nullptr &&
1297        rhs.get_nbytes() == SIZEOF_STORED_DOUBLE * GEOM_DIM) ||
1298       (rhs.get_ptr() == nullptr && rhs.get_nbytes() == 0 && !rhs.get_ownmem()));
1299 
1300   if (m_owner == nullptr) m_owner = rhs.get_owner();
1301 
1302   size_t plen = rhs.get_nbytes();
1303 
1304   // May or may not have own memory. We allow assignment to a Gis_point
1305   // owning no memory because in BG, std::reverse is called to reverse a
1306   // linestring/ring, and also, points are of equal size.
1307   // Not allowed on any other type of geometries.
1308   if (m_ptr == nullptr) {
1309     set_nbytes(SIZEOF_STORED_DOUBLE * GEOM_DIM);
1310     set_ownmem(true);
1311     m_ptr = gis_wkb_fixed_alloc(get_nbytes());
1312     if (m_ptr == nullptr) {
1313       set_nbytes(0);
1314       set_ownmem(false);
1315       return *this;
1316     }
1317   }
1318 
1319   /*
1320     Boost Geometry may use a point that is only default constructed that has
1321     no meaningful value, and in such a case the default value are all zeros.
1322    */
1323   if (plen > 0)
1324     memcpy(m_ptr, rhs.get_ptr(), plen);
1325   else
1326     memset(m_ptr, 0, get_nbytes());
1327 
1328   return *this;
1329 }
1330 
1331 /**
1332   Shallow assignment, let this point object refer to the specified memory
1333   address as its WKB data, and this object never owns the memory assigned.
1334   @param ptr WKB data address for the point.
1335   @param len WKB data length for the point.
1336  */
set_ptr(void * ptr,size_t len)1337 void Gis_point::set_ptr(void *ptr, size_t len) {
1338   set_bg_adapter(true);
1339   if (m_ptr && get_ownmem()) {
1340     DBUG_ASSERT(get_nbytes() == SIZEOF_STORED_DOUBLE * GEOM_DIM);
1341     gis_wkb_free(m_ptr);
1342   }
1343   m_ptr = ptr;
1344   set_nbytes(len);
1345   set_ownmem(false);
1346   DBUG_ASSERT(
1347       (m_ptr != nullptr && get_nbytes() == SIZEOF_STORED_DOUBLE * GEOM_DIM) ||
1348       (m_ptr == nullptr && get_nbytes() == 0));
1349 }
1350 
get_data_size() const1351 uint32 Gis_point::get_data_size() const {
1352   if (check_stack_overrun(current_thd, STACK_MIN_SIZE, nullptr))
1353     return GET_SIZE_ERROR;
1354   if (get_nbytes() != POINT_DATA_SIZE) return GET_SIZE_ERROR;
1355 
1356   return POINT_DATA_SIZE;
1357 }
1358 
init_from_wkt(Gis_read_stream * trs,String * wkb,const bool parens)1359 bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb,
1360                               const bool parens) {
1361   if (check_stack_overrun(trs->thd(), STACK_MIN_SIZE, nullptr)) return true;
1362 
1363   double x, y;
1364   if ((parens && trs->check_next_symbol('(')) || trs->get_next_number(&x) ||
1365       trs->get_next_number(&y) || wkb->reserve(POINT_DATA_SIZE, 256) ||
1366       (parens && trs->check_next_symbol(')')))
1367     return true;
1368   q_append(x, wkb);
1369   q_append(y, wkb);
1370   return false;
1371 }
1372 
1373 /*
1374   Initialize point using WKB data, the WKB data may come from user input or
1375   internally table-stored geometry, and user's WKB data may be either endian.
1376   The WKB data may be of either little endian or big endian, thus we need to
1377   read them using endian-ness aware functions wkb_get_uint, wkb_get_double,
1378   and store them as portable (little endian) format into res.
1379   Only xxx_from_wkb SQL functions can see big endian WKB data, all other
1380   function Items see portable little endian WKB data.
1381   This is true for all the init_from_wkb functions of all Geometry classes.
1382  */
init_from_wkb(THD * thd,const char * wkb,uint len,wkbByteOrder bo,String * res)1383 uint Gis_point::init_from_wkb(THD *thd, const char *wkb, uint len,
1384                               wkbByteOrder bo, String *res) {
1385   if (check_stack_overrun(thd, STACK_MIN_SIZE, nullptr)) return 0;
1386   double x, y;
1387   if (len < POINT_DATA_SIZE || res->reserve(POINT_DATA_SIZE, 256)) return 0;
1388   x = wkb_get_double(wkb, bo);
1389   y = wkb_get_double(wkb + SIZEOF_STORED_DOUBLE, bo);
1390   q_append(x, res);
1391   q_append(y, res);
1392   return POINT_DATA_SIZE;
1393 }
1394 
get_data_as_wkt(String * txt,wkb_parser * wkb) const1395 bool Gis_point::get_data_as_wkt(String *txt, wkb_parser *wkb) const {
1396   point_xy p;
1397   if (wkb->scan_xy(&p)) return true;
1398   if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 3)) return true;
1399   if (!std::isfinite(p.x) || !std::isfinite(p.y)) return true;
1400   qs_append('(', txt);
1401   qs_append(p.x, MAX_DIGITS_IN_DOUBLE, txt);
1402   qs_append(' ', txt);
1403   qs_append(p.y, MAX_DIGITS_IN_DOUBLE, txt);
1404   qs_append(')', txt);
1405   return false;
1406 }
1407 
get_mbr(MBR * mbr,wkb_parser * wkb) const1408 bool Gis_point::get_mbr(MBR *mbr, wkb_parser *wkb) const {
1409   point_xy p;
1410   if (wkb->scan_xy(&p)) return true;
1411   if (!std::isfinite(p.x) || !std::isfinite(p.y)) return true;
1412   mbr->add_xy(p);
1413   return false;
1414 }
1415 
reverse_coordinates()1416 bool Gis_point::reverse_coordinates() {
1417   double x;
1418   double y;
1419 
1420   if (get_x(&x) || get_y(&y)) {
1421     return true;
1422   }
1423 
1424   float8store(get_cptr(), y);
1425   float8store((get_cptr() + SIZEOF_STORED_DOUBLE), x);
1426 
1427   return false;
1428 }
1429 
validate_coordinate_range(double srs_angular_unit,bool * long_out_of_range,bool * lat_out_of_range,double * out_of_range_value)1430 bool Gis_point::validate_coordinate_range(double srs_angular_unit,
1431                                           bool *long_out_of_range,
1432                                           bool *lat_out_of_range,
1433                                           double *out_of_range_value) {
1434   double x;
1435   double y;
1436 
1437   *long_out_of_range = false;
1438   *lat_out_of_range = false;
1439 
1440   if (get_x(&x) || get_y(&y)) {
1441     return true; /* purecov: inspected */
1442   }
1443 
1444   return check_coordinate_range(x, y, srs_angular_unit, long_out_of_range,
1445                                 lat_out_of_range, out_of_range_value);
1446 }
1447 
get_class_info() const1448 const Geometry::Class_info *Gis_point::get_class_info() const {
1449   return &point_class;
1450 }
1451 
1452 /***************************** LineString *******************************/
get_data_size() const1453 uint32 Gis_line_string::get_data_size() const {
1454   if (check_stack_overrun(current_thd, STACK_MIN_SIZE, nullptr))
1455     return GET_SIZE_ERROR;
1456 
1457   if (is_length_verified()) return static_cast<uint32>(get_nbytes());
1458 
1459   uint32 n_points;
1460   uint32 len;
1461   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
1462   if (wkb.scan_n_points_and_check_data(&n_points)) return GET_SIZE_ERROR;
1463 
1464   len = 4 + n_points * POINT_DATA_SIZE;
1465   if (len != get_nbytes()) set_nbytes(len);
1466   set_length_verified(true);
1467   return len;
1468 }
1469 
1470 // Helper function to get coordinate value from a linestring of WKB format.
coord_val(const char * p,int i,int x)1471 inline double coord_val(const char *p, int i, int x) {
1472   return float8get(p + i * POINT_DATA_SIZE + (x ? SIZEOF_STORED_DOUBLE : 0));
1473 }
1474 
init_from_wkt(Gis_read_stream * trs,String * wkb)1475 bool Gis_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb) {
1476   if (check_stack_overrun(trs->thd(), STACK_MIN_SIZE, nullptr)) return true;
1477 
1478   uint32 n_points = 0;
1479   uint32 np_pos = wkb->length();
1480   Gis_point p(false);
1481 
1482   if (trs->check_next_symbol('(')) return true;
1483   if (wkb->reserve(4, 512)) return true;
1484   wkb->length(wkb->length() + 4);  // Reserve space for points
1485 
1486   for (;;) {
1487     if (p.init_from_wkt(trs, wkb, false)) return true;
1488     n_points++;
1489     if (trs->skip_char(','))  // Didn't find ','
1490       break;
1491   }
1492 
1493   if (n_points < 2) {
1494     trs->set_error_msg("Too few points in LINESTRING");
1495     return true;
1496   }
1497 
1498   const char *firstpt = nullptr, *lastpt = nullptr;
1499   if (!is_polygon_ring()) goto out;
1500 
1501   // Make sure all rings of a polygon are closed, and a ring must have
1502   // at least 4 points.
1503   firstpt = wkb->ptr() + np_pos + 4;
1504   lastpt = wkb->ptr() + wkb->length() - POINT_DATA_SIZE;
1505 
1506   if (n_points < 4 || memcmp(lastpt, firstpt, POINT_DATA_SIZE)) return true;
1507 
1508   DBUG_ASSERT(n_points == (lastpt - firstpt) / POINT_DATA_SIZE + 1);
1509 
1510 out:
1511 
1512   write_at_position(np_pos, n_points, wkb);
1513   if (trs->check_next_symbol(')')) return true;
1514   return false;
1515 }
1516 
init_from_wkb(THD * thd,const char * wkb,uint len,wkbByteOrder bo,String * res)1517 uint Gis_line_string::init_from_wkb(THD *thd, const char *wkb, uint len,
1518                                     wkbByteOrder bo, String *res) {
1519   if (check_stack_overrun(thd, STACK_MIN_SIZE, nullptr)) return 0;
1520 
1521   uint32 n_points, proper_length;
1522   const char *wkb_end;
1523   Gis_point p(false);
1524 
1525   if (len < 4 || (n_points = wkb_get_uint(wkb, bo)) < 2 ||
1526       (is_polygon_ring() && n_points < 4) || n_points > max_n_points)
1527     return 0;
1528   proper_length = 4 + n_points * POINT_DATA_SIZE;
1529   wkb_end = wkb + proper_length;
1530 
1531   if (len < proper_length) return 0;
1532 
1533   // Make sure all rings of a polygon are closed.
1534   if (is_polygon_ring() &&
1535       memcmp(wkb + 4, wkb_end - POINT_DATA_SIZE, POINT_DATA_SIZE))
1536     return 0;
1537 
1538   if (res->reserve(proper_length, 512)) return 0;
1539 
1540   q_append(n_points, res);
1541   for (wkb += 4; wkb < wkb_end; wkb += POINT_DATA_SIZE) {
1542     if (!p.init_from_wkb(thd, wkb, POINT_DATA_SIZE, bo, res)) return 0;
1543   }
1544 
1545   return proper_length;
1546 }
1547 
get_data_as_wkt(String * txt,wkb_parser * wkb) const1548 bool Gis_line_string::get_data_as_wkt(String *txt, wkb_parser *wkb) const {
1549   uint32 n_points;
1550   if (wkb->scan_n_points_and_check_data(&n_points) ||
1551       txt->reserve(1 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
1552     return true;
1553 
1554   qs_append('(', txt);
1555   while (n_points--) {
1556     point_xy p;
1557     wkb->scan_xy_unsafe(&p);
1558     if (!std::isfinite(p.x) || !std::isfinite(p.y)) return true;
1559     qs_append(p.x, MAX_DIGITS_IN_DOUBLE, txt);
1560     qs_append(' ', txt);
1561     qs_append(p.y, MAX_DIGITS_IN_DOUBLE, txt);
1562     qs_append(',', txt);
1563   }
1564   txt->length(txt->length() - 1);  // Remove end ','
1565   qs_append(')', txt);
1566   return false;
1567 }
1568 
get_mbr(MBR * mbr,wkb_parser * wkb) const1569 bool Gis_line_string::get_mbr(MBR *mbr, wkb_parser *wkb) const {
1570   return get_mbr_for_points(mbr, wkb, 0);
1571 }
1572 
geom_length(double * len) const1573 int Gis_line_string::geom_length(double *len) const {
1574   uint32 n_points;
1575   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
1576 
1577   *len = 0;  // In case of errors
1578   if (wkb.scan_n_points_and_check_data(&n_points)) return 1;
1579 
1580   point_xy prev;
1581   wkb.scan_xy_unsafe(&prev);
1582   while (--n_points) {
1583     point_xy p;
1584     wkb.scan_xy_unsafe(&p);
1585     *len += prev.distance(p);
1586     if (!std::isfinite(*len)) return 1;
1587     prev = p;
1588   }
1589   return 0;
1590 }
1591 
is_closed(int * closed) const1592 int Gis_line_string::is_closed(int *closed) const {
1593   uint32 n_points;
1594   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
1595 
1596   if (wkb.scan_n_points_and_check_data(&n_points)) return 1;
1597 
1598   if (n_points == 1) {
1599     *closed = 1;
1600     return 0;
1601   }
1602 
1603   point_xy p1, p2;
1604 
1605   /* Get first point. */
1606   wkb.scan_xy_unsafe(&p1);
1607 
1608   /* Get last point. */
1609   wkb.skip_unsafe((n_points - 2) * POINT_DATA_SIZE);
1610   wkb.scan_xy_unsafe(&p2);
1611 
1612   *closed = p1.eq(p2);
1613   return 0;
1614 }
1615 
num_points(uint32 * n_points) const1616 int Gis_line_string::num_points(uint32 *n_points) const {
1617   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
1618   return wkb.scan_uint4(n_points) ? 1 : 0;
1619 }
1620 
start_point(String * result) const1621 int Gis_line_string::start_point(String *result) const {
1622   uint32 n_points;
1623   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
1624   if (wkb.scan_n_points_and_check_data(&n_points)) return 1;
1625   return create_point(result, &wkb);
1626 }
1627 
end_point(String * result) const1628 int Gis_line_string::end_point(String *result) const {
1629   uint32 n_points;
1630   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
1631   if (wkb.scan_n_points_and_check_data(&n_points)) return 1;
1632   wkb.skip_unsafe((n_points - 1) * POINT_DATA_SIZE);
1633   return create_point(result, &wkb);
1634 }
1635 
point_n(uint32 num,String * result) const1636 int Gis_line_string::point_n(uint32 num, String *result) const {
1637   uint32 n_points;
1638   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
1639   if (num < 1 || wkb.scan_n_points_and_check_data(&n_points) || num > n_points)
1640     return 1;
1641   wkb.skip_unsafe((num - 1) * POINT_DATA_SIZE);
1642   return create_point(result, &wkb);
1643 }
1644 
reverse_coordinates()1645 bool Gis_line_string::reverse_coordinates() {
1646   uint32 num_of_points;
1647 
1648   if (num_points(&num_of_points)) {
1649     return true;
1650   }
1651 
1652   for (uint32 i = 0; i < num_of_points; i++) {
1653     // +4 in below functions to skip numPoints field.
1654     double x = float8get(get_cptr() + 4 + i * POINT_DATA_SIZE);
1655     double y =
1656         float8get(get_cptr() + 4 + i * POINT_DATA_SIZE + SIZEOF_STORED_DOUBLE);
1657 
1658     float8store(get_cptr() + 4 + i * POINT_DATA_SIZE, y);
1659     float8store(get_cptr() + 4 + i * POINT_DATA_SIZE + SIZEOF_STORED_DOUBLE, x);
1660   }
1661 
1662   return false;
1663 }
1664 
validate_coordinate_range(double srs_angular_unit,bool * long_out_of_range,bool * lat_out_of_range,double * out_of_range_value)1665 bool Gis_line_string::validate_coordinate_range(double srs_angular_unit,
1666                                                 bool *long_out_of_range,
1667                                                 bool *lat_out_of_range,
1668                                                 double *out_of_range_value) {
1669   uint32 num_of_points;
1670   *long_out_of_range = false;
1671   *lat_out_of_range = false;
1672 
1673   if (num_points(&num_of_points)) {
1674     return true; /* purecov: inspected */
1675   }
1676 
1677   for (uint32 i = 0; i < num_of_points; i++) {
1678     // +4 in below functions to skip numPoints field.
1679     double x = float8get(get_cptr() + 4 + i * POINT_DATA_SIZE);
1680     double y =
1681         float8get(get_cptr() + 4 + i * POINT_DATA_SIZE + SIZEOF_STORED_DOUBLE);
1682 
1683     if (check_coordinate_range(x, y, srs_angular_unit, long_out_of_range,
1684                                lat_out_of_range, out_of_range_value)) {
1685       return true;
1686     }
1687   }
1688 
1689   return false;
1690 }
1691 
get_class_info() const1692 const Geometry::Class_info *Gis_line_string::get_class_info() const {
1693   return &linestring_class;
1694 }
1695 
1696 /***************************** Polygon *******************************/
1697 /**
1698   Copy constructor.
1699   Coordinate type, closed-ness and direction will never change.
1700   @param r another polygon of same coordinate type, ring closed-ness and
1701   ring direction.
1702 */
Gis_polygon(const self & r)1703 Gis_polygon::Gis_polygon(const self &r) : Geometry(r), m_inn_rings(nullptr) {
1704   Gis_polygon::ring_type *r_out = nullptr, *outer = nullptr;
1705   Gis_polygon::inner_container_type *r_inners = nullptr, *inners = nullptr;
1706 
1707   if (r.is_bg_adapter() == false || r.get_ptr() == nullptr) return;
1708 
1709   std::unique_ptr<Gis_polygon::ring_type> guard1;
1710   std::unique_ptr<Gis_polygon::inner_container_type> guard2;
1711 
1712   if (r.get_ptr()) {
1713     r_out = outer_ring(&r);
1714     outer = new Gis_polygon::ring_type(*r_out);
1715     guard1.reset(outer);
1716     outer->set_owner(this);
1717     m_ptr = outer;
1718   }
1719 
1720   if (r.inner_rings()) {
1721     r_inners = r.inner_rings();
1722     inners = new Gis_polygon::inner_container_type(*r_inners);
1723     guard2.reset(inners);
1724     inners->set_owner(this);
1725     set_inner_rings(inners);
1726   }
1727 
1728   set_ownmem(false);
1729   set_bg_adapter(true);
1730   guard1.release();
1731   guard2.release();
1732 }
1733 
Gis_polygon(const void * wkb,size_t nbytes,const Flags_t & flags,gis::srid_t srid)1734 Gis_polygon::Gis_polygon(const void *wkb, size_t nbytes, const Flags_t &flags,
1735                          gis::srid_t srid)
1736     : Geometry(nullptr, nbytes, flags, srid) {
1737   set_geotype(wkb_polygon);
1738   // Make use of Gis_wkb_vector::parse_wkb_data.
1739   inner_container_type v(wkb, nbytes, get_flags(), srid);
1740   m_ptr = v.get_ptr();
1741   m_inn_rings = reinterpret_cast<inner_container_type *>(v.get_geo_vect());
1742   set_ownmem(false);
1743   if (m_ptr) outer_ring(this)->set_owner(this);
1744   if (m_inn_rings) m_inn_rings->set_owner(this);
1745 
1746   set_bg_adapter(true);
1747   v.donate_data();
1748 }
1749 
~Gis_polygon()1750 Gis_polygon::~Gis_polygon() {
1751 /* See ~Geometry() for why we do try-catch like this. */
1752 #if !defined(DBUG_OFF)
1753   try {
1754 #endif
1755     if (!is_bg_adapter() && !get_ownmem()) return;
1756 
1757     if (m_ptr) {
1758       if (polygon_is_wkb_form()) {
1759         if (get_ownmem()) gis_wkb_free(m_ptr);
1760       } else
1761         delete outer_ring(this);
1762       m_ptr = nullptr;
1763     }
1764     if (m_inn_rings) {
1765       delete m_inn_rings;
1766       m_inn_rings = nullptr;
1767     }
1768     /*
1769       Never need to free polygon's wkb memory here, because if it's one chunk
1770       given to us, we don't own it; otherwise the two pieces are already freed
1771       above.
1772      */
1773 #if !defined(DBUG_OFF)
1774   } catch (...) {
1775     // Should never throw exceptions in destructor.
1776     DBUG_ASSERT(false);
1777   }
1778 #endif
1779 }
1780 
1781 /**
1782   Deep assignment from polygon 'o' to this object.
1783   @param rhs the Gis_polygon instance to duplicate from.
1784 */
operator =(const Gis_polygon & rhs)1785 Gis_polygon &Gis_polygon::operator=(const Gis_polygon &rhs) {
1786   if (this == &rhs || !is_bg_adapter() || !rhs.is_bg_adapter()) return *this;
1787   Geometry::operator=(rhs);
1788 
1789   this->set_flags(rhs.get_flags());
1790   if (this->m_owner == nullptr) this->m_owner = rhs.get_owner();
1791 
1792   if (m_ptr) delete outer_ring(this);
1793   if (m_inn_rings) delete m_inn_rings;
1794   m_ptr = nullptr;
1795   m_inn_rings = nullptr;
1796 
1797   if (rhs.get_ptr()) {
1798     Gis_polygon::ring_type *outer =
1799         new Gis_polygon::ring_type(*outer_ring(&rhs));
1800     outer->set_owner(this);
1801     m_ptr = outer;
1802   }
1803 
1804   if (rhs.inner_rings()) {
1805     Gis_polygon::inner_container_type *inners =
1806         new Gis_polygon::inner_container_type(*rhs.inner_rings());
1807     inners->set_owner(this);
1808     set_inner_rings(inners);
1809   }
1810 
1811   return *this;
1812 }
1813 
1814 /**
1815   Set WKB data to this object, the WKB data will be used read only.
1816   @param ptr WKB data pointer.
1817   @param len WKB data number of bytes.
1818  */
set_ptr(void * ptr,size_t len)1819 void Gis_polygon::set_ptr(void *ptr, size_t len) {
1820   set_bg_adapter(true);
1821   ring_type *outer = outer_ring(this);
1822 
1823   if (outer) delete outer;
1824   if (m_inn_rings) delete m_inn_rings;
1825 
1826   set_nbytes(len);
1827 
1828   Gis_wkb_vector<ring_type> plgn(ptr, len, get_flags(), get_srid());
1829   m_ptr = plgn.get_ptr();
1830   m_inn_rings = reinterpret_cast<inner_container_type *>(plgn.get_geo_vect());
1831 
1832   outer = outer_ring(this);
1833   if (outer != nullptr) outer->set_owner(this);
1834   if (m_inn_rings != nullptr) m_inn_rings->set_owner(this);
1835   // Prevent destructor deleting m_ptr/m_inn_rings.
1836   plgn.donate_data();
1837 }
1838 
1839 /**
1840   Make the polygon's data in a single buffer as WKB format. This polygon
1841   must be one for BG use before this call, and after this call it can
1842   never be passed into BG functions directly after this call, and it
1843   is suitable as a Gis_polygon for MySQL GIS code, because it's exactly the
1844   same as a Gis_polygon object returned by Geometry::create_from_wkt/wkb.
1845  */
to_wkb_unparsed()1846 void Gis_polygon::to_wkb_unparsed() {
1847   DBUG_ASSERT(polygon_is_wkb_form() == false && is_bg_adapter());
1848 
1849   size_t nbytes = 0;
1850   void *ptr = get_packed_ptr(this, &nbytes);
1851   delete outer_ring(this);
1852   delete m_inn_rings;
1853   m_ptr = ptr;
1854   set_nbytes(nbytes);
1855   m_inn_rings = nullptr;
1856   polygon_is_wkb_form(true);
1857   set_bg_adapter(false);
1858   set_ownmem(true);
1859 }
1860 
1861 /**
1862   Set the specified ring to counter-clockwise(CCW) or clockwise(CW) if it's not.
1863   Assuems the ring is closed, i.e. the 1st point is the same as the last one.
1864   Allow duplicate vertices at any position, even rings degraded to a point;
1865   Works for convex and concave rings; Can detect those with spikes and
1866   reject them.
1867 
1868   @param want_ccw whether want CCW ring(true) or CW ring(false).
1869   @return false if successful, true if got error -- invalid geometry data.
1870  */
set_ring_order(bool want_ccw)1871 bool Gis_polygon_ring::set_ring_order(bool want_ccw) {
1872   DBUG_ASSERT(is_bg_adapter());
1873   Gis_polygon_ring &ring = *this;
1874   double x1, x2, y1, y2, minx = DBL_MAX, miny = DBL_MAX;
1875   size_t min_i = 0, prev_i, post_i, rsz = ring.size();
1876 
1877   static_assert(sizeof(double) == POINT_DATA_SIZE / 2 &&
1878                     sizeof(double) == SIZEOF_STORED_DOUBLE,
1879                 "");
1880 
1881   /*
1882     User input WKT/WKB may contain invalid geometry data that has less
1883     than 3 points in a polygon ring, so we should return error in this case.
1884    */
1885   if (rsz < 3) return true;
1886 
1887   for (size_t i = 0; i < rsz; i++) {
1888     x1 = ring[i].get<0>();
1889     y1 = ring[i].get<1>();
1890 
1891     if (i == 0) {
1892       minx = x1;
1893       miny = y1;
1894       continue;
1895     }
1896 
1897     if (x1 < minx) {
1898       minx = x1;
1899       miny = y1;
1900       min_i = i;
1901     } else if (x1 == minx) {
1902       if (y1 < miny) {
1903         miny = y1;
1904         min_i = i;
1905       }
1906     }
1907   }
1908 
1909   prev_i = min_i - 1;
1910   post_i = min_i + 1;
1911 
1912   if (min_i == 0) {
1913     // 1st pt and last pt is the same pt, i.e. a closed polygon data, we
1914     // shouldn't use the last pt as prev_i in this case otherwise we will
1915     // get 0 sign.
1916     if (ring[0].get<0>() == ring[rsz - 1].get<0>() &&
1917         ring[0].get<1>() == ring[rsz - 1].get<1>()) {
1918       prev_i = rsz - 2;
1919       /*
1920         Survive from continuous duplicates before prev_i points.
1921        */
1922       while (ring[prev_i].get<0>() == ring[min_i].get<0>() &&
1923              ring[prev_i].get<1>() == ring[min_i].get<1>()) {
1924         prev_i--;
1925         /*
1926           Since the ring must be closed, we will never arrive at the first point
1927           otherwise the 1st point would be the min_i and all points would be
1928           the same and this ring would be a point.
1929          */
1930         if (prev_i == static_cast<size_t>(-1)) return true;
1931       }
1932     } else
1933       prev_i = rsz - 1;
1934   } else if (min_i == rsz - 1) {
1935     // Since we are scanning from 1st point, it's impossible for post_i(0) to
1936     // be the same as min_i here.
1937     post_i = 0;
1938     // Can never come here if all polygon rings are closed.
1939     return true;
1940   }
1941 
1942   /*
1943     Survive from continuous duplicates after min_i points. min_i must be
1944     the 1st of such duplicates if any, so no duplicates before min_i.
1945    */
1946   while (ring[post_i].get<0>() == ring[min_i].get<0>() &&
1947          ring[post_i].get<1>() == ring[min_i].get<1>()) {
1948     post_i++;
1949     /*
1950       Since the ring must be closed, we will never arrive at the last point
1951       otherwise the 1st point would be the min_i, i.e. all points are the same,
1952       and this ring would be a point.
1953      */
1954     if (post_i == rsz) return true;
1955   }
1956 
1957   // The triangle's area tells the direction.
1958   x1 = ring[min_i].get<0>() - ring[prev_i].get<0>();
1959   y1 = ring[min_i].get<1>() - ring[prev_i].get<1>();
1960   x2 = ring[post_i].get<0>() - ring[min_i].get<0>();
1961   y2 = ring[post_i].get<1>() - ring[min_i].get<1>();
1962   double sign = x1 * y2 - x2 * y1;
1963 
1964   if (sign == 0) return true;  // Catches error: there is a spike in the ring.
1965 
1966   // Reverse points in the ring, do direct memory manipulation rather
1967   // than using std::reverse for better performance.
1968   if ((sign > 0 && !want_ccw) || (sign < 0 && want_ccw)) {
1969     char *p = static_cast<char *>(ring.get_ptr()) + sizeof(uint32);
1970     char *q = nullptr, *p0;
1971     char pt[POINT_DATA_SIZE];
1972     size_t s = ring.size();
1973 
1974     DBUG_ASSERT(ring.get_nbytes() == (s * POINT_DATA_SIZE + 4));
1975     p0 = p;
1976 
1977     for (size_t i = 0; i < s / 2; i++, p += POINT_DATA_SIZE) {
1978       q = p0 + (s - i - 1) * POINT_DATA_SIZE;
1979       memcpy(&pt, p, POINT_DATA_SIZE);
1980       memcpy(p, q, POINT_DATA_SIZE);
1981       memcpy(q, &pt, POINT_DATA_SIZE);
1982     }
1983   }
1984   return false;
1985 }
1986 
1987 /**
1988   Set this polygon's outer ring to be CCW and inner rings to be CW.
1989   @return on error returns true, on success returns false.
1990 */
set_polygon_ring_order()1991 bool Gis_polygon::set_polygon_ring_order() {
1992   DBUG_ASSERT(is_bg_adapter());
1993   if (outer().set_ring_order(true /* Ring order: CCW. */)) return true;
1994   Gis_polygon::inner_container_type::iterator itr;
1995   Gis_polygon::inner_container_type &inns = inners();
1996   for (itr = inns.begin(); itr != inns.end(); ++itr)
1997     if (itr->set_ring_order(false /* Ring order: CW. */)) return true;
1998 
1999   return false;
2000 }
2001 
2002 /**
2003   Make outer ring and inner rings objects for this polygon if it doesn't
2004   have one yet.
2005   Outer ring and inner rings have to have separated memory space, because
2006   we can't predict which one will be edited first. So the polygon object
2007   doesn't directly have memory, its m_ptr points to the outer ring, its
2008   m_inn_rings points to the inner rings, each have its own memory address
2009   and length, and Gis_polygon::get_nbytes returns the sum of them.
2010 
2011   If the polygon doesn't own memory, then there is only one piece of memory
2012   passed into it and used by it, otherwise the two pieces of memory are
2013   separately allocated and released.
2014  */
make_rings()2015 void Gis_polygon::make_rings() {
2016   ring_type *outer = nullptr;
2017 
2018   if (this->m_ptr == nullptr) {
2019     outer = new ring_type(nullptr, 0, Flags_t(wkb_linestring, 0), get_srid());
2020     outer->set_owner(this);
2021     this->m_ptr = outer;
2022   }
2023 
2024   if (m_inn_rings == nullptr) {
2025     m_inn_rings = new inner_container_type(
2026         nullptr, 0, Flags_t(wkb_polygon_inner_rings, 0), get_srid());
2027     m_inn_rings->set_owner(this);
2028   }
2029   this->set_ownmem(false);
2030 }
2031 
get_data_size() const2032 uint32 Gis_polygon::get_data_size() const {
2033   if (check_stack_overrun(current_thd, STACK_MIN_SIZE, nullptr))
2034     return GET_SIZE_ERROR;
2035 
2036   uint32 n_linear_rings;
2037   uint32 len;
2038   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2039 
2040   if (is_length_verified()) return get_nbytes();
2041 
2042   /*
2043     For a BG adapter polygon, its Gis_polygon::m_ptr points to its outer ring
2044     rather than the WKB buffer, it is the only exception.
2045    */
2046   DBUG_ASSERT(polygon_is_wkb_form() || !is_bg_adapter());
2047 
2048   if (wkb.scan_non_zero_uint4(&n_linear_rings)) return GET_SIZE_ERROR;
2049 
2050   while (n_linear_rings--) {
2051     uint32 n_points;
2052     if (wkb.scan_n_points_and_check_data(&n_points)) return GET_SIZE_ERROR;
2053     wkb.skip_unsafe(n_points * POINT_DATA_SIZE);
2054   }
2055   len = static_cast<uint32>(wkb.data() - (const char *)get_data_ptr());
2056   if (len != get_nbytes()) set_nbytes(len);
2057   set_length_verified(true);
2058   return len;
2059 }
2060 
init_from_wkt(Gis_read_stream * trs,String * wkb)2061 bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb) {
2062   if (check_stack_overrun(trs->thd(), STACK_MIN_SIZE, nullptr)) return true;
2063 
2064   uint32 n_linear_rings = 0;
2065   uint32 lr_pos = wkb->length();
2066 
2067   if (trs->check_next_symbol('(')) return true;
2068   if (wkb->reserve(4, 512)) return true;
2069   wkb->length(wkb->length() + 4);  // Reserve space for points
2070 
2071   bool is_first = true;
2072   for (;;) {
2073     Gis_line_string ls(false);
2074     ls.set_props(is_first ? POLYGON_OUTER_RING : POLYGON_INNER_RING);
2075     is_first = false;
2076 
2077     if (ls.init_from_wkt(trs, wkb)) return true;
2078 
2079     n_linear_rings++;
2080     if (trs->skip_char(','))  // Didn't find ','
2081       break;
2082   }
2083   write_at_position(lr_pos, n_linear_rings, wkb);
2084   if (trs->check_next_symbol(')')) return true;
2085   return false;
2086 }
2087 
init_from_wkb(THD * thd,const char * wkb,uint len,wkbByteOrder bo,String * res)2088 uint Gis_polygon::init_from_wkb(THD *thd, const char *wkb, uint len,
2089                                 wkbByteOrder bo, String *res) {
2090   if (check_stack_overrun(thd, STACK_MIN_SIZE, nullptr)) return 0;
2091 
2092   uint32 n_linear_rings;
2093   const char *wkb_orig = wkb;
2094 
2095   if (len < 4) return 0;
2096 
2097   if (0 == (n_linear_rings = wkb_get_uint(wkb, bo)) || res->reserve(4, 512))
2098     return 0;
2099   wkb += 4;
2100   len -= 4;
2101   q_append(n_linear_rings, res);
2102 
2103   bool is_first = true;
2104   while (n_linear_rings--) {
2105     Gis_line_string ls(false);
2106     ls.set_props(is_first ? POLYGON_OUTER_RING : POLYGON_INNER_RING);
2107     is_first = false;
2108 
2109     uint ls_len = 0;
2110 
2111     if (!(ls_len = ls.init_from_wkb(thd, wkb, len, bo, res))) return 0;
2112 
2113     wkb += ls_len;
2114     DBUG_ASSERT(len >= ls_len);
2115     len -= ls_len;
2116   }
2117 
2118   return (uint)(wkb - wkb_orig);
2119 }
2120 
get_data_as_wkt(String * txt,wkb_parser * wkb) const2121 bool Gis_polygon::get_data_as_wkt(String *txt, wkb_parser *wkb) const {
2122   uint32 n_linear_rings;
2123 
2124   if (wkb->scan_non_zero_uint4(&n_linear_rings)) return true;
2125 
2126   txt->append('(');
2127   while (n_linear_rings--) {
2128     uint32 n_points;
2129     if (wkb->scan_n_points_and_check_data(&n_points) ||
2130         txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
2131       return true;
2132     qs_append('(', txt);
2133     append_points(txt, n_points, wkb, 0);
2134     (*txt)[txt->length() - 1] = ')';  // Replace end ','
2135     qs_append(',', txt);
2136   }
2137   txt->length(txt->length() - 1);  // Remove end ','
2138   qs_append(')', txt);
2139   return false;
2140 }
2141 
get_mbr(MBR * mbr,wkb_parser * wkb) const2142 bool Gis_polygon::get_mbr(MBR *mbr, wkb_parser *wkb) const {
2143   uint32 n_linear_rings;
2144 
2145   if (wkb->scan_non_zero_uint4(&n_linear_rings)) return true;
2146 
2147   while (n_linear_rings--) {
2148     if (get_mbr_for_points(mbr, wkb, 0)) return true;
2149   }
2150   return false;
2151 }
2152 
exterior_ring(String * result) const2153 int Gis_polygon::exterior_ring(String *result) const {
2154   uint32 n_points, n_linear_rings, length;
2155   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2156 
2157   if (wkb.scan_non_zero_uint4(&n_linear_rings) ||
2158       wkb.scan_n_points_and_check_data(&n_points))
2159     return 1;
2160   length = n_points * POINT_DATA_SIZE;
2161   if (result->reserve(1 + 4 + 4 + length, 512)) return 1;
2162 
2163   q_append((char)wkb_ndr, result);
2164   q_append((uint32)wkb_linestring, result);
2165   q_append(n_points, result);
2166   q_append(wkb.data(), length, result);
2167   return 0;
2168 }
2169 
num_interior_ring(uint32 * n_int_rings) const2170 int Gis_polygon::num_interior_ring(uint32 *n_int_rings) const {
2171   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2172   if (wkb.scan_non_zero_uint4(n_int_rings)) return 1;
2173   *n_int_rings -= 1;
2174   return 0;
2175 }
2176 
interior_ring_n(uint32 num,String * result) const2177 int Gis_polygon::interior_ring_n(uint32 num, String *result) const {
2178   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2179   uint32 n_linear_rings;
2180   uint32 n_points;
2181   uint32 points_size;
2182 
2183   if (num < 1 || wkb.scan_non_zero_uint4(&n_linear_rings) ||
2184       num >= n_linear_rings)
2185     return 1;
2186 
2187   while (num--) {
2188     if (wkb.scan_n_points_and_check_data(&n_points)) return 1;
2189     wkb.skip_unsafe(n_points * POINT_DATA_SIZE);
2190   }
2191   if (wkb.scan_n_points_and_check_data(&n_points)) return 1;
2192   points_size = n_points * POINT_DATA_SIZE;
2193   if (result->reserve(1 + 4 + 4 + points_size, 512)) return 1;
2194 
2195   q_append((char)wkb_ndr, result);
2196   q_append((uint32)wkb_linestring, result);
2197   q_append(n_points, result);
2198   q_append(wkb.data(), points_size, result);
2199   return 0;
2200 }
2201 
reverse_coordinates()2202 bool Gis_polygon::reverse_coordinates() {
2203   uint32 current_data_offset = 0;
2204   uint32 numrings;
2205 
2206   if (num_interior_ring(&numrings)) {
2207     return true;
2208   }
2209 
2210   numrings += 1;             // add exterior ring to number of rings.
2211   current_data_offset += 4;  // add numRings header size to data offset.
2212 
2213   for (uint32 i = 0; i < numrings; i++) {
2214     uint32 num_of_points = uint4korr(get_ucptr() + current_data_offset);
2215     current_data_offset += 4;  // add linear ring header size to data offset.
2216 
2217     for (uint32 j = 0; j < num_of_points; j++) {
2218       double x = float8get(get_cptr() + current_data_offset);
2219       double y =
2220           float8get(get_cptr() + current_data_offset + SIZEOF_STORED_DOUBLE);
2221 
2222       float8store(get_cptr() + current_data_offset, y);
2223       float8store(get_cptr() + current_data_offset + SIZEOF_STORED_DOUBLE, x);
2224 
2225       current_data_offset += POINT_DATA_SIZE;
2226     }
2227   }
2228 
2229   return false;
2230 }
2231 
validate_coordinate_range(double srs_angular_unit,bool * long_out_of_range,bool * lat_out_of_range,double * out_of_range_value)2232 bool Gis_polygon::validate_coordinate_range(double srs_angular_unit,
2233                                             bool *long_out_of_range,
2234                                             bool *lat_out_of_range,
2235                                             double *out_of_range_value) {
2236   uint32 numrings;
2237   *long_out_of_range = false;
2238   *lat_out_of_range = false;
2239 
2240   if (num_interior_ring(&numrings)) {
2241     return true; /* purecov: inspected */
2242   }
2243 
2244   numrings += 1;                   // Add exterior ring to number of rings.
2245   uint32 current_data_offset = 4;  // Add numRings header size to data offset.
2246 
2247   for (uint32 i = 0; i < numrings; i++) {
2248     uint32 num_of_points = uint4korr(get_ucptr() + current_data_offset);
2249     current_data_offset += 4;  // Add linear ring header size to data offset.
2250 
2251     for (uint32 j = 0; j < num_of_points; j++) {
2252       double x = float8get(get_cptr() + current_data_offset);
2253       double y =
2254           float8get(get_cptr() + current_data_offset + SIZEOF_STORED_DOUBLE);
2255 
2256       if (check_coordinate_range(x, y, srs_angular_unit, long_out_of_range,
2257                                  lat_out_of_range, out_of_range_value)) {
2258         return true;
2259       }
2260 
2261       current_data_offset += POINT_DATA_SIZE;
2262     }
2263   }
2264 
2265   return false;
2266 }
2267 
get_class_info() const2268 const Geometry::Class_info *Gis_polygon::get_class_info() const {
2269   return &polygon_class;
2270 }
2271 
2272 /**
2273    Packup a polygon's outer ring and inner rings into a single chunk of
2274    memory as result. nbytes returns the number of bytes in WKB data.
2275    The returned WKB has no WKB header.
2276    Never call get_ptr to obtain a polygon's WKB data.
2277 
2278    @param geo0 The polygon whose WKB data we want to pack up.
2279    @param[out] pnbytes Takes back the number of bytes of the packed WKB string.
2280    @return The address of the packed WKB string buffer.
2281   */
get_packed_ptr(const Geometry * geo0,size_t * pnbytes)2282 void *get_packed_ptr(const Geometry *geo0, size_t *pnbytes) {
2283   DBUG_ASSERT(geo0->get_geotype() == Geometry::wkb_polygon &&
2284               pnbytes != nullptr);
2285   const Gis_polygon *geo = static_cast<const Gis_polygon *>(geo0);
2286   Gis_polygon::ring_type *out_ring = outer_ring(geo);
2287   Gis_polygon::inner_container_type *inn_rings = geo->inner_rings();
2288   size_t &nbytes = *pnbytes;
2289 
2290   if (out_ring == nullptr) {
2291     DBUG_ASSERT(inn_rings == nullptr);
2292     *pnbytes = 0;
2293     return nullptr;
2294   }
2295 
2296   // Inner rings may have out of line rings.
2297   if (inn_rings) inn_rings->reassemble();
2298 
2299   size_t vallen = sizeof(uint32) + out_ring->get_nbytes() +
2300                   (inn_rings ? inn_rings->get_nbytes() : 0);
2301   void *src_val = gis_wkb_alloc(vallen);
2302   if (src_val == nullptr) {
2303     nbytes = 0;
2304     return nullptr;
2305   }
2306 
2307   memcpy(static_cast<char *>(src_val) + sizeof(uint32), out_ring->get_ptr(),
2308          out_ring->get_nbytes());
2309 
2310   size_t n_inns = 0;
2311   if (inn_rings && inn_rings->get_nbytes()) {
2312     memcpy(
2313         static_cast<char *>(src_val) + sizeof(uint32) + out_ring->get_nbytes(),
2314         inn_rings->get_ptr(), inn_rings->get_nbytes());
2315     n_inns = inn_rings->size();
2316   }
2317 
2318   DBUG_ASSERT(1 + n_inns <= 0xFFFFFFFF);
2319   int4store(static_cast<uchar *>(src_val), static_cast<uint32>(1 + n_inns));
2320 
2321   nbytes = vallen;
2322   return src_val;
2323 }
2324 
2325 /**
2326   Get a polygon's WKB string's starting address. The polygon is already
2327   packed so that its outer ring and inner rings point to different locations
2328   of a continuous chunk of WKB buffer.
2329 
2330   @param geo0 The already packed polygon, we want to get its data address.
2331   @return The WKB string starting address, right after the WKB header if any.
2332  */
get_packed_ptr(Geometry * geo0)2333 const char *get_packed_ptr(Geometry *geo0) {
2334   DBUG_ASSERT(geo0->get_geotype() == Geometry::wkb_polygon);
2335   Gis_polygon *geo = static_cast<Gis_polygon *>(geo0);
2336   Gis_polygon::ring_type *out_ring = outer_ring(geo);
2337   Gis_polygon::inner_container_type *inn_rings = geo->inner_rings();
2338   if (inn_rings)
2339     DBUG_ASSERT(out_ring->get_cptr() + out_ring->get_nbytes() ==
2340                 inn_rings->get_cptr());
2341   return (out_ring->get_cptr() - sizeof(uint32) /*polygon's ring count */);
2342 }
2343 
2344 /**
2345   Check whether plgn is packed into its owner mplgn's WKB buffer.
2346   @param plgn the polygon to be checked
2347   @param mplgn the multipolygon, owner/holder of plgn.
2348   @return true if plgn is packed into mplgn, false otherwise.
2349  */
polygon_is_packed(Geometry * plgn,Geometry * mplgn)2350 bool polygon_is_packed(Geometry *plgn, Geometry *mplgn) {
2351   DBUG_ASSERT(plgn->get_geotype() == Geometry::wkb_polygon &&
2352               mplgn->get_geotype() == Geometry::wkb_multipolygon);
2353   Gis_polygon *geo = static_cast<Gis_polygon *>(plgn);
2354   Gis_polygon::ring_type *out_ring = outer_ring(geo);
2355   Gis_polygon::inner_container_type *inn_rings = geo->inner_rings();
2356   const char *orstart = out_ring->get_cptr();
2357   bool ret = false;
2358 
2359   if (orstart < mplgn->get_cptr() + mplgn->get_nbytes() &&
2360       orstart > mplgn->get_cptr()) {
2361     // This polygon is already stored packed and inline
2362     if (inn_rings && inn_rings->get_nbytes())
2363       DBUG_ASSERT(orstart + out_ring->get_nbytes() == inn_rings->get_ptr());
2364 
2365     ret = true;
2366   }
2367 
2368   return ret;
2369 }
2370 
own_rings(Geometry * geo0)2371 void own_rings(Geometry *geo0) {
2372   DBUG_ASSERT(geo0->get_geotype() == Geometry::wkb_polygon);
2373   Gis_polygon *geo = static_cast<Gis_polygon *>(geo0);
2374 
2375   if (outer_ring(geo)) outer_ring(geo)->set_owner(geo);
2376   if (geo->inner_rings()) geo->inner_rings()->set_owner(geo);
2377 }
2378 
2379 /***************************** MultiPoint *******************************/
get_data_size() const2380 uint32 Gis_multi_point::get_data_size() const {
2381   if (check_stack_overrun(current_thd, STACK_MIN_SIZE, nullptr))
2382     return GET_SIZE_ERROR;
2383 
2384   uint32 n_points;
2385   uint32 len;
2386   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2387 
2388   if (is_length_verified()) return get_nbytes();
2389   if (wkb.scan_n_points_and_check_data(&n_points, WKB_HEADER_SIZE))
2390     return GET_SIZE_ERROR;
2391 
2392   len = 4 + n_points * (POINT_DATA_SIZE + WKB_HEADER_SIZE);
2393   if (len != get_nbytes()) set_nbytes(len);
2394   set_length_verified(true);
2395   return len;
2396 }
2397 
init_from_wkt(Gis_read_stream * trs,String * wkb)2398 bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb) {
2399   if (check_stack_overrun(trs->thd(), STACK_MIN_SIZE, nullptr)) return true;
2400 
2401   uint32 n_points = 0;
2402   uint32 np_pos = wkb->length();
2403   Gis_point p(false);
2404 
2405   if (trs->check_next_symbol('(')) return true;
2406   if (wkb->reserve(4, 512)) return true;
2407   wkb->length(wkb->length() + 4);  // Reserve space for points
2408 
2409   /*
2410     According to OGC, the WKT for a multipoint is something like:
2411     MULTIPOINT((1 1), (2 2))
2412     and to be backward compatible with older versions of MySQL, we still
2413     support the MySQL format:
2414     MULTIPOINT(1 1, 2 2)
2415     But we don't allow the mixture of both formats in the same multipoint
2416     geometry.
2417   */
2418   const bool match_pt_lbra =
2419       (trs->get_next_toc_type() == Gis_read_stream::l_bra);
2420 
2421   for (;;) {
2422     if (wkb->reserve(1 + 4, 512)) return true;
2423     q_append((char)wkb_ndr, wkb);
2424     q_append((uint32)wkb_point, wkb);
2425 
2426     if (match_pt_lbra && trs->check_next_symbol('(')) return true;
2427 
2428     if (p.init_from_wkt(trs, wkb, false)) return true;
2429 
2430     if (match_pt_lbra && trs->check_next_symbol(')')) return true;
2431 
2432     n_points++;
2433     if (trs->skip_char(','))  // Didn't find ','
2434       break;
2435   }
2436   write_at_position(np_pos, n_points, wkb);  // Store number of found points
2437   if (trs->check_next_symbol(')')) return true;
2438   return false;
2439 }
2440 
init_from_wkb(THD * thd,const char * wkb,uint len,wkbByteOrder bo,String * res)2441 uint Gis_multi_point::init_from_wkb(THD *thd, const char *wkb, uint len,
2442                                     wkbByteOrder bo, String *res) {
2443   if (check_stack_overrun(thd, STACK_MIN_SIZE, nullptr)) return 0;
2444 
2445   uint32 n_points;
2446   uint proper_size;
2447   Gis_point p(false);
2448   const char *wkb_end;
2449 
2450   if (len < 4 || (n_points = wkb_get_uint(wkb, bo)) > max_n_points) return 0;
2451   proper_size = 4 + n_points * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
2452 
2453   if (len < proper_size || res->reserve(proper_size, 512)) return 0;
2454 
2455   q_append(n_points, res);
2456   wkb_end = wkb + proper_size;
2457   for (wkb += 4; wkb < wkb_end; wkb += (WKB_HEADER_SIZE + POINT_DATA_SIZE)) {
2458     write_wkb_header(res, wkb_point);
2459     if ((*wkb != wkb_xdr && *wkb != wkb_ndr) ||
2460         wkb_point != uint4korr(wkb + 1) ||
2461         !p.init_from_wkb(thd, wkb + WKB_HEADER_SIZE, POINT_DATA_SIZE,
2462                          (wkbByteOrder)wkb[0], res))
2463       return 0;
2464   }
2465   return proper_size;
2466 }
2467 
get_data_as_wkt(String * txt,wkb_parser * wkb) const2468 bool Gis_multi_point::get_data_as_wkt(String *txt, wkb_parser *wkb) const {
2469   uint32 n_points;
2470 
2471   txt->append('(');
2472   if (wkb->scan_n_points_and_check_data(&n_points, WKB_HEADER_SIZE) ||
2473       txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
2474     return true;
2475 
2476   /*
2477     Now we will output multipoint in OGC format, i.e. for each of its point,
2478     bracket its coordinates with ().
2479   */
2480   append_points(txt, n_points, wkb, WKB_HEADER_SIZE, true);
2481   txt->length(txt->length() - 1);  // Remove end ','
2482   qs_append(')', txt);
2483   return false;
2484 }
2485 
get_mbr(MBR * mbr,wkb_parser * wkb) const2486 bool Gis_multi_point::get_mbr(MBR *mbr, wkb_parser *wkb) const {
2487   return get_mbr_for_points(mbr, wkb, WKB_HEADER_SIZE);
2488 }
2489 
num_geometries(uint32 * num) const2490 int Gis_multi_point::num_geometries(uint32 *num) const {
2491   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2492   return wkb.scan_non_zero_uint4(num) ? 1 : 0;
2493 }
2494 
geometry_n(uint32 num,String * result) const2495 int Gis_multi_point::geometry_n(uint32 num, String *result) const {
2496   uint32 n_points;
2497   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2498 
2499   if (num < 1 || wkb.scan_n_points_and_check_data(&n_points, WKB_HEADER_SIZE) ||
2500       num > n_points || result->reserve(WKB_HEADER_SIZE + POINT_DATA_SIZE, 32))
2501     return 1;
2502   wkb.skip_unsafe((num - 1) * (WKB_HEADER_SIZE + POINT_DATA_SIZE));
2503 
2504   q_append(wkb.data(), WKB_HEADER_SIZE + POINT_DATA_SIZE, result);
2505   return 0;
2506 }
2507 
reverse_coordinates()2508 bool Gis_multi_point::reverse_coordinates() {
2509   uint32 current_data_offset = 0;
2510   uint32 num_of_points;
2511   if (num_geometries(&num_of_points)) {
2512     return true;
2513   }
2514 
2515   current_data_offset += 4;  // add number of points header to offset.
2516 
2517   for (uint32 i = 0; i < num_of_points; i++) {
2518     current_data_offset +=
2519         WKB_HEADER_SIZE;  // since each point includes a header.
2520 
2521     double x = float8get(get_cptr() + current_data_offset);
2522     double y =
2523         float8get(get_cptr() + current_data_offset + SIZEOF_STORED_DOUBLE);
2524 
2525     float8store(get_cptr() + current_data_offset, y);
2526     float8store(get_cptr() + current_data_offset + SIZEOF_STORED_DOUBLE, x);
2527 
2528     current_data_offset += POINT_DATA_SIZE;
2529   }
2530 
2531   return false;
2532 }
2533 
validate_coordinate_range(double srs_angular_unit,bool * long_out_of_range,bool * lat_out_of_range,double * out_of_range_value)2534 bool Gis_multi_point::validate_coordinate_range(double srs_angular_unit,
2535                                                 bool *long_out_of_range,
2536                                                 bool *lat_out_of_range,
2537                                                 double *out_of_range_value) {
2538   uint32 num_of_points;
2539   *long_out_of_range = false;
2540   *lat_out_of_range = false;
2541 
2542   if (num_geometries(&num_of_points)) {
2543     return true; /* purecov: inspected */
2544   }
2545 
2546   uint32 current_data_offset = 4;  // Add number of points header to offset.
2547 
2548   for (uint32 i = 0; i < num_of_points; i++) {
2549     current_data_offset +=
2550         WKB_HEADER_SIZE;  // Since each point includes a header.
2551 
2552     double x = float8get(get_cptr() + current_data_offset);
2553     double y =
2554         float8get(get_cptr() + current_data_offset + SIZEOF_STORED_DOUBLE);
2555 
2556     if (check_coordinate_range(x, y, srs_angular_unit, long_out_of_range,
2557                                lat_out_of_range, out_of_range_value)) {
2558       return true;
2559     }
2560 
2561     current_data_offset += POINT_DATA_SIZE;
2562   }
2563 
2564   return false;
2565 }
2566 
get_class_info() const2567 const Geometry::Class_info *Gis_multi_point::get_class_info() const {
2568   return &multipoint_class;
2569 }
2570 
2571 /***************************** MultiLineString *******************************/
get_data_size() const2572 uint32 Gis_multi_line_string::get_data_size() const {
2573   if (check_stack_overrun(current_thd, STACK_MIN_SIZE, nullptr))
2574     return GET_SIZE_ERROR;
2575 
2576   uint32 n_line_strings;
2577   uint32 len;
2578   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2579 
2580   if (is_length_verified()) return get_nbytes();
2581   if (wkb.scan_non_zero_uint4(&n_line_strings)) return GET_SIZE_ERROR;
2582 
2583   while (n_line_strings--) {
2584     uint32 n_points;
2585 
2586     if (wkb.skip_wkb_header() || wkb.scan_n_points_and_check_data(&n_points))
2587       return GET_SIZE_ERROR;
2588 
2589     wkb.skip_unsafe(n_points * POINT_DATA_SIZE);
2590   }
2591 
2592   len = static_cast<uint32>(wkb.data() - (const char *)get_data_ptr());
2593   if (len != get_nbytes()) set_nbytes(len);
2594   set_length_verified(true);
2595   return len;
2596 }
2597 
init_from_wkt(Gis_read_stream * trs,String * wkb)2598 bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb) {
2599   if (check_stack_overrun(trs->thd(), STACK_MIN_SIZE, nullptr)) return true;
2600 
2601   uint32 n_line_strings = 0;
2602   uint32 ls_pos = wkb->length();
2603 
2604   if (trs->check_next_symbol('(')) return true;
2605   if (wkb->reserve(4, 512)) return true;
2606   wkb->length(wkb->length() + 4);  // Reserve space for points
2607 
2608   for (;;) {
2609     Gis_line_string ls(false);
2610 
2611     if (wkb->reserve(1 + 4, 512)) return true;
2612     q_append((char)wkb_ndr, wkb);
2613     q_append((uint32)wkb_linestring, wkb);
2614 
2615     if (ls.init_from_wkt(trs, wkb)) return true;
2616     n_line_strings++;
2617     if (trs->skip_char(','))  // Didn't find ','
2618       break;
2619   }
2620   write_at_position(ls_pos, n_line_strings, wkb);
2621   if (trs->check_next_symbol(')')) return true;
2622   return false;
2623 }
2624 
init_from_wkb(THD * thd,const char * wkb,uint len,wkbByteOrder bo,String * res)2625 uint Gis_multi_line_string::init_from_wkb(THD *thd, const char *wkb, uint len,
2626                                           wkbByteOrder bo, String *res) {
2627   if (check_stack_overrun(thd, STACK_MIN_SIZE, nullptr)) return 0;
2628 
2629   uint32 n_line_strings;
2630   const char *wkb_orig = wkb;
2631 
2632   if (len < 4 || (n_line_strings = wkb_get_uint(wkb, bo)) < 1) return 0;
2633 
2634   if (res->reserve(4, 512)) return 0;
2635   q_append(n_line_strings, res);
2636 
2637   wkb += 4;
2638   len -= 4;
2639 
2640   while (n_line_strings--) {
2641     Gis_line_string ls(false);
2642     uint ls_len = 0;
2643 
2644     if ((len < WKB_HEADER_SIZE) || uint4korr(wkb + 1) != wkb_linestring ||
2645         (*wkb != wkb_xdr && *wkb != wkb_ndr) ||
2646         res->reserve(WKB_HEADER_SIZE, 512))
2647       return 0;
2648 
2649     write_wkb_header(res, wkb_linestring);
2650     if (!(ls_len = ls.init_from_wkb(thd, wkb + WKB_HEADER_SIZE,
2651                                     len - WKB_HEADER_SIZE, (wkbByteOrder)wkb[0],
2652                                     res)))
2653       return 0;
2654     ls_len += WKB_HEADER_SIZE;
2655     ;
2656     wkb += ls_len;
2657     DBUG_ASSERT(len >= ls_len);
2658     len -= ls_len;
2659   }
2660   return (uint)(wkb - wkb_orig);
2661 }
2662 
get_data_as_wkt(String * txt,wkb_parser * wkb) const2663 bool Gis_multi_line_string::get_data_as_wkt(String *txt,
2664                                             wkb_parser *wkb) const {
2665   uint32 n_line_strings;
2666 
2667   if (wkb->scan_non_zero_uint4(&n_line_strings)) return true;
2668 
2669   txt->append('(');
2670   while (n_line_strings--) {
2671     uint32 n_points;
2672 
2673     if (wkb->skip_wkb_header() ||
2674         wkb->scan_n_points_and_check_data(&n_points) ||
2675         txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
2676       return true;
2677     qs_append('(', txt);
2678     append_points(txt, n_points, wkb, 0);
2679     (*txt)[txt->length() - 1] = ')';
2680     qs_append(',', txt);
2681   }
2682   txt->length(txt->length() - 1);
2683   qs_append(')', txt);
2684   return false;
2685 }
2686 
get_mbr(MBR * mbr,wkb_parser * wkb) const2687 bool Gis_multi_line_string::get_mbr(MBR *mbr, wkb_parser *wkb) const {
2688   uint32 n_line_strings;
2689 
2690   if (wkb->scan_non_zero_uint4(&n_line_strings)) return true;
2691 
2692   while (n_line_strings--) {
2693     if (wkb->skip_wkb_header() || get_mbr_for_points(mbr, wkb, 0)) return true;
2694   }
2695   return false;
2696 }
2697 
num_geometries(uint32 * num) const2698 int Gis_multi_line_string::num_geometries(uint32 *num) const {
2699   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2700   return wkb.scan_non_zero_uint4(num) ? 1 : 0;
2701 }
2702 
geometry_n(uint32 num,String * result) const2703 int Gis_multi_line_string::geometry_n(uint32 num, String *result) const {
2704   uint32 n_line_strings, n_points, length;
2705   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2706 
2707   if (wkb.scan_non_zero_uint4(&n_line_strings)) return 1;
2708 
2709   if ((num > n_line_strings) || (num < 1)) return 1;
2710 
2711   for (;;) {
2712     if (wkb.skip_wkb_header() || wkb.scan_n_points_and_check_data(&n_points))
2713       return 1;
2714     length = POINT_DATA_SIZE * n_points;
2715     if (!--num) break;
2716     wkb.skip_unsafe(length);
2717   }
2718   return result->append(wkb.data() - 4 - WKB_HEADER_SIZE,
2719                         length + 4 + WKB_HEADER_SIZE, static_cast<size_t>(0));
2720 }
2721 
geom_length(double * len) const2722 int Gis_multi_line_string::geom_length(double *len) const {
2723   uint32 n_line_strings;
2724   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2725 
2726   if (wkb.scan_non_zero_uint4(&n_line_strings)) return 1;
2727 
2728   *len = 0;
2729   while (n_line_strings--) {
2730     double ls_len;
2731     Gis_line_string ls(false);
2732     if (wkb.skip_wkb_header()) return 1;
2733     ls.set_data_ptr(&wkb);
2734     if (ls.geom_length(&ls_len)) return 1;
2735     *len += ls_len;
2736     /*
2737       We know here that ls was ok, so we can call the trivial function
2738       Gis_line_string::get_data_size without error checking.
2739     */
2740     wkb.skip_unsafe(ls.get_data_size());
2741   }
2742   return 0;
2743 }
2744 
is_closed(int * closed) const2745 int Gis_multi_line_string::is_closed(int *closed) const {
2746   uint32 n_line_strings;
2747   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2748 
2749   if (wkb.scan_non_zero_uint4(&n_line_strings)) return 1;
2750 
2751   while (n_line_strings--) {
2752     Gis_line_string ls(false);
2753     if (wkb.skip_wkb_header()) return 1;
2754     ls.set_data_ptr(&wkb);
2755     if (ls.is_closed(closed)) return 1;
2756     if (!*closed) return 0;
2757     wkb.skip_unsafe(ls.get_data_size());
2758   }
2759   return 0;
2760 }
2761 
reverse_coordinates()2762 bool Gis_multi_line_string::reverse_coordinates() {
2763   uint32 num_of_linestrings;
2764   size_t current_data_offset = 4;  // Skip num_wkbLineStrings header size.
2765 
2766   String str(get_cptr(), get_nbytes(), &my_charset_bin);
2767 
2768   if (num_geometries(&num_of_linestrings)) {
2769     return true;
2770   }
2771   for (uint32 i = 1; i <= num_of_linestrings; i++) {
2772     String result;
2773 
2774     if (geometry_n(i, &result)) {
2775       return true;
2776     }
2777 
2778     Geometry *g;
2779     Geometry_buffer buffer;
2780     if (!(g = Geometry::construct(&buffer, &result, false))) {
2781       return true;
2782     }
2783 
2784     if (g->reverse_coordinates()) {
2785       return true;
2786     }
2787 
2788     if (str.replace(current_data_offset, result.length(), result.ptr(),
2789                     result.length())) {
2790       return true;
2791     }
2792 
2793     current_data_offset += result.length();
2794   }
2795 
2796   return false;
2797 }
2798 
validate_coordinate_range(double srs_angular_unit,bool * long_out_of_range,bool * lat_out_of_range,double * out_of_range_value)2799 bool Gis_multi_line_string::validate_coordinate_range(
2800     double srs_angular_unit, bool *long_out_of_range, bool *lat_out_of_range,
2801     double *out_of_range_value) {
2802   uint32 num_of_linestrings;
2803   *long_out_of_range = false;
2804   *lat_out_of_range = false;
2805 
2806   if (num_geometries(&num_of_linestrings)) {
2807     return true; /* purecov: inspected */
2808   }
2809 
2810   for (uint32 i = 1; i <= num_of_linestrings; i++) {
2811     String result;
2812 
2813     if (geometry_n(i, &result)) {
2814       return true; /* purecov: inspected */
2815     }
2816 
2817     Geometry *g;
2818     Geometry_buffer buffer;
2819     if (!(g = Geometry::construct(&buffer, &result, false))) {
2820       return true; /* purecov: inspected */
2821     }
2822 
2823     if (g->validate_coordinate_range(srs_angular_unit, long_out_of_range,
2824                                      lat_out_of_range, out_of_range_value)) {
2825       return true;
2826     }
2827   }
2828 
2829   return false;
2830 }
2831 
get_class_info() const2832 const Geometry::Class_info *Gis_multi_line_string::get_class_info() const {
2833   return &multilinestring_class;
2834 }
2835 
2836 /***************************** MultiPolygon *******************************/
get_data_size() const2837 uint32 Gis_multi_polygon::get_data_size() const {
2838   if (check_stack_overrun(current_thd, STACK_MIN_SIZE, nullptr))
2839     return GET_SIZE_ERROR;
2840 
2841   uint32 n_polygons;
2842   uint32 len;
2843   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2844 
2845   if (is_length_verified()) return get_nbytes();
2846   if (wkb.scan_non_zero_uint4(&n_polygons)) return GET_SIZE_ERROR;
2847 
2848   while (n_polygons--) {
2849     uint32 n_linear_rings;
2850     if (wkb.skip_wkb_header() || wkb.scan_non_zero_uint4(&n_linear_rings))
2851       return GET_SIZE_ERROR;
2852 
2853     while (n_linear_rings--) {
2854       uint32 n_points;
2855 
2856       if (wkb.scan_n_points_and_check_data(&n_points)) return GET_SIZE_ERROR;
2857 
2858       wkb.skip_unsafe(n_points * POINT_DATA_SIZE);
2859     }
2860   }
2861 
2862   len = static_cast<uint32>(wkb.data() - (const char *)get_data_ptr());
2863   if (len != get_nbytes()) set_nbytes(len);
2864   set_length_verified(true);
2865   return len;
2866 }
2867 
init_from_wkt(Gis_read_stream * trs,String * wkb)2868 bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb) {
2869   if (check_stack_overrun(trs->thd(), STACK_MIN_SIZE, nullptr)) return true;
2870 
2871   uint32 n_polygons = 0;
2872   uint32 np_pos = wkb->length();
2873   Gis_polygon p(false);
2874 
2875   if (trs->check_next_symbol('(')) return true;
2876   if (wkb->reserve(4, 512)) return true;
2877   wkb->length(wkb->length() + 4);  // Reserve space for points
2878 
2879   for (;;) {
2880     if (wkb->reserve(1 + 4, 512)) return true;
2881     q_append((char)wkb_ndr, wkb);
2882     q_append((uint32)wkb_polygon, wkb);
2883 
2884     if (p.init_from_wkt(trs, wkb)) return true;
2885     n_polygons++;
2886     if (trs->skip_char(','))  // Didn't find ','
2887       break;
2888   }
2889   write_at_position(np_pos, n_polygons, wkb);
2890   if (trs->check_next_symbol(')')) return true;
2891   return false;
2892 }
2893 
init_from_wkb(THD * thd,const char * wkb,uint len,wkbByteOrder bo,String * res)2894 uint Gis_multi_polygon::init_from_wkb(THD *thd, const char *wkb, uint len,
2895                                       wkbByteOrder bo, String *res) {
2896   if (check_stack_overrun(thd, STACK_MIN_SIZE, nullptr)) return 0;
2897 
2898   uint32 n_poly;
2899   const char *wkb_orig = wkb;
2900 
2901   if (len < 4) return 0;
2902   n_poly = wkb_get_uint(wkb, bo);
2903 
2904   if (res->reserve(4, 512)) return 0;
2905   q_append(n_poly, res);
2906 
2907   wkb += 4;
2908   len -= 4;
2909 
2910   while (n_poly--) {
2911     Gis_polygon p(false);
2912     uint p_len = 0;
2913 
2914     if (len < WKB_HEADER_SIZE || uint4korr(wkb + 1) != wkb_polygon ||
2915         (*wkb != wkb_xdr && *wkb != wkb_ndr) ||
2916         res->reserve(WKB_HEADER_SIZE, 512))
2917       return 0;
2918     write_wkb_header(res, wkb_polygon);
2919     if (!(p_len =
2920               p.init_from_wkb(thd, wkb + WKB_HEADER_SIZE, len - WKB_HEADER_SIZE,
2921                               (wkbByteOrder)wkb[0], res)))
2922       return 0;
2923     p_len += WKB_HEADER_SIZE;
2924     wkb += p_len;
2925     DBUG_ASSERT(len >= p_len);
2926     len -= p_len;
2927   }
2928   return (uint)(wkb - wkb_orig);
2929 }
2930 
get_data_as_wkt(String * txt,wkb_parser * wkb) const2931 bool Gis_multi_polygon::get_data_as_wkt(String *txt, wkb_parser *wkb) const {
2932   uint32 n_polygons;
2933 
2934   if (wkb->scan_non_zero_uint4(&n_polygons)) return true;
2935 
2936   txt->append('(');
2937   while (n_polygons--) {
2938     uint32 n_linear_rings;
2939 
2940     if (wkb->skip_wkb_header() || wkb->scan_non_zero_uint4(&n_linear_rings) ||
2941         txt->reserve(1, 512))
2942       return true;
2943     q_append('(', txt);
2944 
2945     while (n_linear_rings--) {
2946       uint32 n_points;
2947       if (wkb->scan_n_points_and_check_data(&n_points) ||
2948           txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
2949         return true;
2950       qs_append('(', txt);
2951       append_points(txt, n_points, wkb, 0);
2952       (*txt)[txt->length() - 1] = ')';
2953       qs_append(',', txt);
2954     }
2955     (*txt)[txt->length() - 1] = ')';
2956     qs_append(',', txt);
2957   }
2958   txt->length(txt->length() - 1);
2959   qs_append(')', txt);
2960   return false;
2961 }
2962 
get_mbr(MBR * mbr,wkb_parser * wkb) const2963 bool Gis_multi_polygon::get_mbr(MBR *mbr, wkb_parser *wkb) const {
2964   uint32 n_polygons;
2965 
2966   if (wkb->scan_non_zero_uint4(&n_polygons)) return true;
2967 
2968   while (n_polygons--) {
2969     uint32 n_linear_rings;
2970     if (wkb->skip_wkb_header() || wkb->scan_non_zero_uint4(&n_linear_rings))
2971       return true;
2972 
2973     while (n_linear_rings--) {
2974       if (get_mbr_for_points(mbr, wkb, 0)) return true;
2975     }
2976   }
2977   return false;
2978 }
2979 
num_geometries(uint32 * num) const2980 int Gis_multi_polygon::num_geometries(uint32 *num) const {
2981   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2982   return wkb.scan_non_zero_uint4(num) ? 1 : 0;
2983 }
2984 
geometry_n(uint32 num,String * result) const2985 int Gis_multi_polygon::geometry_n(uint32 num, String *result) const {
2986   uint32 n_polygons;
2987   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
2988   const char *start_of_polygon = wkb.data();
2989 
2990   if (wkb.scan_non_zero_uint4(&n_polygons)) return 1;
2991 
2992   if (num > n_polygons || num < 1) return -1;
2993 
2994   do {
2995     uint32 n_linear_rings;
2996     start_of_polygon = wkb.data();
2997 
2998     if (wkb.skip_wkb_header() || wkb.scan_non_zero_uint4(&n_linear_rings))
2999       return 1;
3000 
3001     while (n_linear_rings--) {
3002       uint32 n_points;
3003       if (wkb.scan_n_points_and_check_data(&n_points)) return 1;
3004       wkb.skip_unsafe(POINT_DATA_SIZE * n_points);
3005     }
3006   } while (--num);
3007   if (wkb.no_data(0))  // We must check last segment
3008     return 1;
3009   return result->append(start_of_polygon,
3010                         (uint32)(wkb.data() - start_of_polygon),
3011                         static_cast<size_t>(0));
3012 }
3013 
reverse_coordinates()3014 bool Gis_multi_polygon::reverse_coordinates() {
3015   uint32 num_of_polygons;
3016   size_t current_data_offset = 4;  // Skip num_polygons header size.
3017 
3018   String str(get_cptr(), get_nbytes(), &my_charset_bin);
3019 
3020   if (num_geometries(&num_of_polygons)) {
3021     return true;
3022   }
3023 
3024   for (uint32 i = 1; i <= num_of_polygons; i++) {
3025     String result;
3026 
3027     if (geometry_n(i, &result)) {
3028       return true;
3029     }
3030 
3031     Geometry *g;
3032     Geometry_buffer buffer;
3033     if (!(g = Geometry::construct(&buffer, &result, false))) {
3034       return true;
3035     }
3036 
3037     if (g->reverse_coordinates()) {
3038       return true;
3039     }
3040 
3041     if (str.replace(current_data_offset, result.length(), result.ptr(),
3042                     result.length())) {
3043       return true;
3044     }
3045 
3046     current_data_offset += result.length();
3047   }
3048 
3049   return false;
3050 }
3051 
validate_coordinate_range(double srs_angular_unit,bool * long_out_of_range,bool * lat_out_of_range,double * out_of_range_value)3052 bool Gis_multi_polygon::validate_coordinate_range(double srs_angular_unit,
3053                                                   bool *long_out_of_range,
3054                                                   bool *lat_out_of_range,
3055                                                   double *out_of_range_value) {
3056   uint32 num_of_polygons;
3057   *long_out_of_range = false;
3058   *lat_out_of_range = false;
3059 
3060   if (num_geometries(&num_of_polygons)) {
3061     return true; /* purecov: inspected */
3062   }
3063 
3064   for (uint32 i = 1; i <= num_of_polygons; i++) {
3065     String result;
3066 
3067     if (geometry_n(i, &result)) {
3068       return true; /* purecov: inspected */
3069     }
3070 
3071     Geometry *g;
3072     Geometry_buffer buffer;
3073     if (!(g = Geometry::construct(&buffer, &result, false))) {
3074       return true; /* purecov: inspected */
3075     }
3076 
3077     if (g->validate_coordinate_range(srs_angular_unit, long_out_of_range,
3078                                      lat_out_of_range, out_of_range_value)) {
3079       return true;
3080     }
3081   }
3082 
3083   return false;
3084 }
3085 
get_class_info() const3086 const Geometry::Class_info *Gis_multi_polygon::get_class_info() const {
3087   return &multipolygon_class;
3088 }
3089 
3090 /************************* GeometryCollection ****************************/
3091 
3092 /**
3093   Create a Geometry object from WKB.
3094 
3095   This function creates an intermediate geometry object which may have wrong
3096   length property (longer than what's needed by the geometry), use it only
3097   within this class. Do not check for exact length here, caller will do
3098   that if necessary.
3099 
3100   @param wkb The input WKB.
3101   @param buffer A buffer for the output geometry.
3102   @return NULL if the input WKB was found invalid. Otherwise, the constructed
3103           geometry.
3104 */
scan_header_and_create(wkb_parser * wkb,Geometry_buffer * buffer)3105 Geometry *Gis_geometry_collection::scan_header_and_create(
3106     wkb_parser *wkb, Geometry_buffer *buffer) {
3107   Geometry *geom;
3108   wkb_header header;
3109 
3110   if (wkb->scan_wkb_header(&header) ||
3111       !(geom = create_by_typeid(buffer, header.wkb_type)))
3112     return nullptr;
3113   geom->set_data_ptr(wkb->data(), wkb->length());
3114 
3115   /*
3116     The length in geom might be wrong, since it's set to the total length of
3117     the geometry collection's WKB. Such error is only allowed for temporary
3118     geometry objects created here.
3119 
3120     Correct the length only for points because other types has known structure
3121     and can deduce the valid length. But for point we have to always require
3122     the exact length.
3123   */
3124   if (geom->get_type() == wkb_point) {
3125     if (geom->get_nbytes() < POINT_DATA_SIZE) return nullptr;
3126     geom->set_nbytes(POINT_DATA_SIZE);
3127   }
3128 
3129   return geom;
3130 }
3131 
3132 /**
3133   Append geometry into geometry collection which can be empty.
3134   @param geo geometry to be appended, it can't be empty.
3135   @param gcbuf this geometry collection's data buffer, it's of GEOMETRY format
3136          and is a separate String buffer.
3137   @return false if no error, otherwise true.
3138 
3139  */
append_geometry(const Geometry * geo,String * gcbuf)3140 bool Gis_geometry_collection::append_geometry(const Geometry *geo,
3141                                               String *gcbuf) {
3142   uint32 collection_len = gcbuf->length(), geo_len = geo->get_data_size();
3143   if (geo_len == GET_SIZE_ERROR) return true;
3144   DBUG_ASSERT(collection_len == 0 ||
3145               get_data_size() == collection_len - GEOM_HEADER_SIZE);
3146   if (gcbuf->reserve((collection_len == 0 ? GEOM_HEADER_SIZE + 4 : 0) +
3147                          geo_len + WKB_HEADER_SIZE,
3148                      512))
3149     return true;
3150 
3151   char *ptr = gcbuf->ptr();
3152   uint32 extra = 0;
3153   if (collection_len == 0) {
3154     collection_len = GEOM_HEADER_SIZE + 4;
3155     extra = GEOM_HEADER_SIZE;
3156     write_geometry_header(ptr, geo->get_srid(), wkb_geometrycollection, 0);
3157     set_srid(geo->get_srid());
3158     has_geom_header_space(true);
3159   }
3160 
3161   // Skip GEOMETRY header.
3162   ptr += GEOM_HEADER_SIZE;
3163   const char *start = ptr;
3164 
3165   int4store(ptr, uint4korr(ptr) + 1);  // Increment object count.
3166   ptr += collection_len - GEOM_HEADER_SIZE;
3167   ptr = write_wkb_header(ptr, geo->get_type());
3168   memcpy(ptr, geo->get_data_ptr(), geo_len);
3169   gcbuf->length(collection_len + geo_len + WKB_HEADER_SIZE);
3170   set_data_ptr(start, extra + collection_len + geo_len - SRID_SIZE);
3171   return false;
3172 }
3173 
3174 /**
3175   Append geometry into geometry collection, which can be empty. This object
3176   must be created from default constructor or below one:
3177   Gis_geometry_collection(gis::srid_t srid, wkbType gtype,
3178                           const String *gbuf,
3179                           String *gcbuf);
3180 
3181   @param srid srid of geometry to be appended.
3182   @param gtype type of geometry to be appended.
3183   @param gbuf WKB data of geometry to be appended, gbuf->ptr isn't NULL and
3184          points right after the WKB header, this buffer can't be empty.
3185   @param gcbuf this geometry collection's data buffer, it's of GEOMETRY format
3186          and is a separate String buffer.
3187   @return false if no error, otherwise true.
3188 
3189  */
append_geometry(gis::srid_t srid,wkbType gtype,const String * gbuf,String * gcbuf)3190 bool Gis_geometry_collection::append_geometry(gis::srid_t srid, wkbType gtype,
3191                                               const String *gbuf,
3192                                               String *gcbuf) {
3193   DBUG_ASSERT(gbuf != nullptr && gbuf->ptr() != nullptr && gbuf->length() > 0);
3194 
3195   uint32 collection_len = gcbuf->length(), geo_len = gbuf->length();
3196   DBUG_ASSERT(collection_len == 0 ||
3197               get_data_size() == collection_len - GEOM_HEADER_SIZE);
3198   if (gcbuf->reserve((collection_len == 0 ? GEOM_HEADER_SIZE + 4 : 0) +
3199                          geo_len + WKB_HEADER_SIZE,
3200                      512))
3201     return true;
3202 
3203   char *ptr = gcbuf->ptr();
3204   uint32 extra = 0;
3205   if (collection_len == 0) {
3206     collection_len = GEOM_HEADER_SIZE + 4;
3207     extra = GEOM_HEADER_SIZE;
3208     write_geometry_header(ptr, srid, wkb_geometrycollection, 0);
3209     set_srid(srid);
3210     has_geom_header_space(true);
3211   } else if (srid != get_srid())
3212     return true;
3213 
3214   // Skip GEOMETRY header.
3215   ptr += GEOM_HEADER_SIZE;
3216   const char *start = ptr;
3217 
3218   int4store(ptr, uint4korr(ptr) + 1);  // Increment object count.
3219   ptr += collection_len - GEOM_HEADER_SIZE;
3220   ptr = write_wkb_header(ptr, gtype);
3221   memcpy(ptr, gbuf->ptr(), geo_len);
3222   gcbuf->length(collection_len + geo_len + WKB_HEADER_SIZE);
3223   set_data_ptr(start, extra + collection_len + geo_len - SRID_SIZE);
3224   return false;
3225 }
3226 
3227 /**
3228   Create a geometry collection from a single geometry, and the created object
3229   refers to position right after the WKB header inside the 'gcbuf' buffer.
3230   @param srid the SRID of the first geometry to put into this
3231               geometry collection. Its SRID is used as the SRID of this
3232               geometry collection.
3233   @param gtype the type of the first geometry to put into this object.
3234   @param gbuf stores the WKB data of the first geometry to put into this object,
3235               not including its WKB header. if gbuf is NULL or gbuf->ptr is
3236               NULL, the created geometry collection is empty.
3237   @param gcbuf this geometry collection's data buffer in GEOMETRY format.
3238  */
Gis_geometry_collection(gis::srid_t srid,wkbType gtype,const String * gbuf,String * gcbuf)3239 Gis_geometry_collection::Gis_geometry_collection(gis::srid_t srid,
3240                                                  wkbType gtype,
3241                                                  const String *gbuf,
3242                                                  String *gcbuf)
3243     : Geometry(nullptr, 0, Flags_t(wkb_geometrycollection, 0), srid) {
3244   uint32 geo_len = gbuf ? gbuf->length() : 0, total_len = 0;
3245   DBUG_ASSERT(
3246       (gbuf == nullptr || (gbuf->ptr() == nullptr && gbuf->length() == 0)) ||
3247       (gbuf->ptr() != nullptr && gbuf->length() > 0));
3248   total_len = geo_len + sizeof(uint32) /*NUM-objs*/ + SRID_SIZE +
3249               WKB_HEADER_SIZE + (geo_len > 0 ? WKB_HEADER_SIZE : 0);
3250 
3251   // Reserve 512 bytes extra space for geometries to be appended later,
3252   // to avoid some reallocations.
3253   if (gcbuf->reserve(total_len + 512, 1024))
3254     my_error(ER_OUTOFMEMORY, total_len + 512);
3255 
3256   char *ptr = gcbuf->ptr();
3257   const char *start = ptr + GEOM_HEADER_SIZE;
3258 
3259   ptr = write_geometry_header(ptr, srid, Geometry::wkb_geometrycollection,
3260                               geo_len ? 1 : 0);
3261   if (geo_len > 0) {
3262     ptr = write_wkb_header(ptr, gtype);
3263     memcpy(ptr, gbuf->ptr(), geo_len);
3264   }
3265 
3266   gcbuf->length(total_len);
3267   set_data_ptr(start, total_len - GEOM_HEADER_SIZE);
3268   set_srid(srid);
3269   has_geom_header_space(true);
3270 }
3271 
3272 /**
3273   Create a geometry collection from a single geometry, and this object refer
3274   to position right after the WKB header inside the 'gcbuf' buffer.
3275   @param geo the first valid geometry to put into this geometry collection.
3276          Its SRID is used as the SRID of this geometry collection. It must be
3277          a valid geometry.
3278   @param gcbuf this geometry collection's data buffer in GEOMETRY format.
3279  */
Gis_geometry_collection(Geometry * geo,String * gcbuf)3280 Gis_geometry_collection::Gis_geometry_collection(Geometry *geo, String *gcbuf)
3281     : Geometry(nullptr, 0, Flags_t(wkb_geometrycollection, 0),
3282                geo->get_srid()) {
3283   DBUG_ASSERT(geo != nullptr && geo->get_ptr() != nullptr);
3284   uint32 geo_len = geo->get_data_size(), total_len = 0;
3285   DBUG_ASSERT(geo_len != GET_SIZE_ERROR);
3286   total_len =
3287       geo_len + sizeof(uint32) /*NUM-objs*/ + SRID_SIZE + WKB_HEADER_SIZE * 2;
3288 
3289   // Reserve 512 bytes extra space for geometries to be appended later,
3290   // to avoid some reallocations.
3291   if (gcbuf->reserve(total_len + 512, 1024))
3292     my_error(ER_OUTOFMEMORY, total_len + 512);
3293 
3294   char *ptr = gcbuf->ptr();
3295   const char *start = ptr + GEOM_HEADER_SIZE;
3296 
3297   ptr = write_geometry_header(ptr, geo->get_srid(),
3298                               Geometry::wkb_geometrycollection, 1);
3299   ptr = write_wkb_header(ptr, geo->get_type());
3300 
3301   memcpy(ptr, geo->get_data_ptr(), geo_len);
3302   gcbuf->length(total_len);
3303   set_data_ptr(start, total_len - GEOM_HEADER_SIZE);
3304   set_srid(geo->get_srid());
3305   has_geom_header_space(true);
3306 }
3307 
get_data_size() const3308 uint32 Gis_geometry_collection::get_data_size() const {
3309   if (check_stack_overrun(current_thd, STACK_MIN_SIZE, nullptr))
3310     return GET_SIZE_ERROR;
3311 
3312   uint32 n_objects = 0;
3313   uint32 len;
3314   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
3315   Geometry_buffer buffer;
3316   Geometry *geom;
3317 
3318   if (is_length_verified()) return get_nbytes();
3319   /*
3320     We allow a geometry collection of 0 components, because this is how we
3321     define an 'empty collection', which is used as the result of set operation
3322     that returns an empty result, it's different from NULL value just in the
3323     same way an empty string is different from a NULL.
3324    */
3325   if (wkb.scan_non_zero_uint4(&n_objects) && n_objects != 0)
3326     return GET_SIZE_ERROR;
3327 
3328   while (n_objects--) {
3329     if (!(geom = scan_header_and_create(&wkb, &buffer))) return GET_SIZE_ERROR;
3330 
3331     uint32 object_size;
3332     /*
3333       'geom' is a temporary object whose length may be wrongly specified by
3334       scan_header_and_create() function, so here we don't require
3335       object_size + GEOM_HEADER_SIZE == wkb->length()
3336     */
3337     if ((object_size = geom->get_data_size()) == GET_SIZE_ERROR)
3338       return GET_SIZE_ERROR;
3339 
3340     /*
3341       Use 'skip()' instead of 'skip_unsafe()' in case the object size is
3342       incorrect
3343     */
3344     if (wkb.skip(object_size)) {
3345       DBUG_ASSERT(false);  // geom-get_data_size() did something wrong.
3346       return GET_SIZE_ERROR;
3347     }
3348   }
3349   len = static_cast<uint32>(wkb.data() - (const char *)get_data_ptr());
3350   if (len != get_nbytes()) set_nbytes(len);
3351   set_length_verified(true);
3352   return len;
3353 }
3354 
init_from_wkt(Gis_read_stream * trs,String * wkb)3355 bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb) {
3356   if (check_stack_overrun(trs->thd(), STACK_MIN_SIZE, nullptr)) return true;
3357 
3358   uint32 n_objects = 0;
3359   uint32 no_pos = wkb->length();
3360   Geometry_buffer buffer;
3361   Geometry *g;
3362 
3363   if (wkb->reserve(4, 512)) return true;
3364   wkb->length(wkb->length() + 4);  // Reserve space for points
3365 
3366   if (trs->get_next_toc_type() == Gis_read_stream::word) {
3367     LEX_CSTRING empty;
3368     if (trs->get_next_word(&empty) || empty.length != 5 ||
3369         native_strncasecmp("EMPTY", empty.str, 5))
3370       return true;
3371   } else {
3372     if (trs->check_next_symbol('(')) return true;
3373     for (;;) {
3374       /*
3375         Allow specifying an empty geometry collection in this form:
3376         'geometrycollection()'.
3377       */
3378       if (n_objects == 0 && trs->get_next_toc_type() == Gis_read_stream::r_bra)
3379         break;
3380       if (!(g = create_from_wkt(&buffer, trs, wkb, true,
3381                                 false /* Allow trailing bytes. */)))
3382         return true;
3383       /*
3384         Allow g to be a nested geometry collection, nested ones are flatterned
3385         in BG_geometry_collection before sending to new BG based GIS algorithms.
3386       */
3387       n_objects++;
3388       if (trs->skip_char(','))  // Didn't find ','
3389         break;
3390     }
3391     if (trs->check_next_symbol(')')) return true;
3392   }
3393 
3394   write_at_position(no_pos, n_objects, wkb);
3395   return false;
3396 }
3397 
init_from_wkb(THD * thd,const char * wkb,uint len,wkbByteOrder bo,String * res)3398 uint Gis_geometry_collection::init_from_wkb(THD *thd, const char *wkb, uint len,
3399                                             wkbByteOrder bo, String *res) {
3400   if (check_stack_overrun(thd, STACK_MIN_SIZE, nullptr)) return 0;
3401 
3402   uint32 n_geom = 0;
3403   const char *wkb_orig = wkb;
3404 
3405   if (len < 4) return 0;
3406   n_geom = wkb_get_uint(wkb, bo);
3407 
3408   if (res->reserve(4, 512)) return 0;
3409   q_append(n_geom, res);
3410 
3411   wkb += 4;
3412   len -= 4;
3413 
3414   /* Allow 0 components as an empty collection. */
3415   while (n_geom--) {
3416     Geometry_buffer buffer;
3417     Geometry *geom;
3418     uint g_len = 0;
3419     uint32 wkb_type;
3420 
3421     if (len < WKB_HEADER_SIZE || (*wkb != wkb_xdr && *wkb != wkb_ndr) ||
3422         res->reserve(WKB_HEADER_SIZE, 512))
3423       return 0;
3424 
3425     wkb_type = wkb_get_uint(wkb + 1, (wkbByteOrder)wkb[0]);
3426     write_wkb_header(res, static_cast<wkbType>(wkb_type));
3427 
3428     if (!(geom = create_by_typeid(&buffer, wkb_type)) ||
3429         !(g_len = geom->init_from_wkb(thd, wkb + WKB_HEADER_SIZE,
3430                                       len - WKB_HEADER_SIZE,
3431                                       (wkbByteOrder)wkb[0], res)))
3432       return 0;
3433     g_len += WKB_HEADER_SIZE;
3434     wkb += g_len;
3435     DBUG_ASSERT(len >= g_len);
3436     len -= g_len;
3437   }
3438   return (uint)(wkb - wkb_orig);
3439 }
3440 
get_data_as_wkt(String * txt,wkb_parser * wkb) const3441 bool Gis_geometry_collection::get_data_as_wkt(String *txt,
3442                                               wkb_parser *wkb) const {
3443   uint32 n_objects = 0;
3444   Geometry_buffer buffer;
3445   Geometry *geom;
3446   size_t nback = 1;
3447 
3448   /* Allow 0 components as an empty collection. */
3449   if (wkb->scan_non_zero_uint4(&n_objects) && n_objects != 0) return true;
3450 
3451   if (n_objects == 0) {
3452     txt->append(STRING_WITH_LEN(" EMPTY"));
3453   } else {
3454     txt->append('(');
3455     while (n_objects--) {
3456       if (!(geom = scan_header_and_create(wkb, &buffer)) ||
3457           geom->as_wkt(txt, wkb) || txt->append(STRING_WITH_LEN(","), 512))
3458         return true;
3459     }
3460     txt->length(txt->length() - nback);
3461     txt->append(')');
3462   }
3463   return false;
3464 }
3465 
get_mbr(MBR * mbr,wkb_parser * wkb) const3466 bool Gis_geometry_collection::get_mbr(MBR *mbr, wkb_parser *wkb) const {
3467   uint32 n_objects;
3468   Geometry_buffer buffer;
3469   Geometry *geom;
3470 
3471   /* An empty collection's MBR is NULL. */
3472   if (wkb->scan_non_zero_uint4(&n_objects)) return true;
3473 
3474   bool found_one = false;
3475   while (n_objects--) {
3476     if (!(geom = scan_header_and_create(wkb, &buffer)) ||
3477         geom->get_mbr(mbr, wkb)) {
3478       /*
3479         An empty collection should be simply skipped, it may contain a tree
3480         of empty collections which is still empty.
3481       */
3482       if (geom != nullptr && geom->get_type() == wkb_geometrycollection)
3483         continue;
3484       return true;
3485     }
3486 
3487     // Now we've found a solid component and updated the mbr.
3488     found_one = true;
3489   }
3490 
3491   /* An collection containing only a few empty collections, the MBR is NULL. */
3492   if (!found_one) return true;
3493   return false;
3494 }
3495 
num_geometries(uint32 * num) const3496 int Gis_geometry_collection::num_geometries(uint32 *num) const {
3497   *num = 0;
3498   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
3499   /* Should return 0 and *num=0 if called with an empty collection. */
3500   return (wkb.scan_non_zero_uint4(num) && *num != 0) ? 1 : 0;
3501 }
3502 
geometry_n(uint32 num,String * result) const3503 int Gis_geometry_collection::geometry_n(uint32 num, String *result) const {
3504   uint32 n_objects, length;
3505   wkb_parser wkb(get_cptr(), get_cptr() + get_nbytes());
3506   Geometry_buffer buffer;
3507   Geometry *geom;
3508 
3509   /* It's an error to call this with an empty collection. */
3510   if (wkb.scan_non_zero_uint4(&n_objects)) return 1;
3511 
3512   if (num > n_objects || num < 1) return 1;
3513 
3514   wkb_header header;
3515   do {
3516     if (wkb.scan_wkb_header(&header) ||
3517         !(geom = create_by_typeid(&buffer, header.wkb_type)))
3518       return 1;
3519 
3520     // Must set precise length for points even for a temporary/intermediate one.
3521     if (geom->get_type() == wkb_point)
3522       geom->set_data_ptr(wkb.data(), POINT_DATA_SIZE);
3523     else
3524       geom->set_data_ptr(&wkb);
3525 
3526     if ((length = geom->get_data_size()) == GET_SIZE_ERROR) return 1;
3527     wkb.skip_unsafe(length);
3528   } while (--num);
3529 
3530   /* Copy found object to result */
3531   if (result->reserve(1 + 4 + length, 512)) return 1;
3532   q_append((char)wkb_ndr, result);
3533   q_append(header.wkb_type, result);
3534   q_append(wkb.data() - length, length, result);  // data-length= start_of_data
3535   return 0;
3536 }
3537 
3538 /*
3539   Return dimension for object
3540 
3541   SYNOPSIS
3542     dimension()
3543     res_dim		Result dimension
3544     end			End of object will be stored here. May be 0 for
3545                         simple objects!
3546   RETURN
3547     0	ok
3548     1	error
3549 */
3550 
dimension(uint32 * res_dim,wkb_parser * wkb) const3551 bool Gis_geometry_collection::dimension(uint32 *res_dim,
3552                                         wkb_parser *wkb) const {
3553   uint32 n_objects;
3554   Geometry_buffer buffer;
3555   Geometry *geom;
3556 
3557   if (wkb->scan_non_zero_uint4(&n_objects)) return true;
3558 
3559   *res_dim = 0;
3560   while (n_objects--) {
3561     uint32 dim;
3562     if (!(geom = scan_header_and_create(wkb, &buffer)) ||
3563         geom->dimension(&dim, wkb))
3564       return true;
3565     *res_dim = std::max(*res_dim, dim);
3566   }
3567   return false;
3568 }
3569 
reverse_coordinates()3570 bool Gis_geometry_collection::reverse_coordinates() {
3571   uint32 num_of_geometries;
3572   size_t current_data_offset =
3573       4;  // Add num_of_geometries header size to offset.
3574 
3575   String str(get_cptr(), get_nbytes(), &my_charset_bin);
3576 
3577   if (num_geometries(&num_of_geometries)) {
3578     return true;
3579   }
3580 
3581   for (uint32 i = 1; i <= num_of_geometries; i++) {
3582     String result;
3583 
3584     if (geometry_n(i, &result)) {
3585       return true;
3586     }
3587 
3588     Geometry *g;
3589     Geometry_buffer buffer;
3590     if (!(g = Geometry::construct(&buffer, &result, false))) {
3591       return true;
3592     }
3593 
3594     if (g->reverse_coordinates()) {
3595       return true;
3596     }
3597 
3598     if (str.replace(current_data_offset, result.length(), result.ptr(),
3599                     result.length())) {
3600       return true;
3601     }
3602 
3603     current_data_offset += result.length();
3604   }
3605 
3606   return false;
3607 }
3608 
validate_coordinate_range(double srs_angular_unit,bool * long_out_of_range,bool * lat_out_of_range,double * out_of_range_value)3609 bool Gis_geometry_collection::validate_coordinate_range(
3610     double srs_angular_unit, bool *long_out_of_range, bool *lat_out_of_range,
3611     double *out_of_range_value) {
3612   uint32 num_of_geometries;
3613   *long_out_of_range = false;
3614   *lat_out_of_range = false;
3615 
3616   if (num_geometries(&num_of_geometries)) {
3617     return true; /* purecov: inspected */
3618   }
3619 
3620   for (uint32 i = 1; i <= num_of_geometries; i++) {
3621     String result;
3622 
3623     if (geometry_n(i, &result)) {
3624       return true; /* purecov: inspected */
3625     }
3626 
3627     Geometry *g;
3628     Geometry_buffer buffer;
3629     if (!(g = Geometry::construct(&buffer, &result, false))) {
3630       return true; /* purecov: inspected */
3631     }
3632 
3633     if (g->validate_coordinate_range(srs_angular_unit, long_out_of_range,
3634                                      lat_out_of_range, out_of_range_value)) {
3635       return true;
3636     }
3637   }
3638 
3639   return false;
3640 }
3641 
get_class_info() const3642 const Geometry::Class_info *Gis_geometry_collection::get_class_info() const {
3643   return &geometrycollection_class;
3644 }
3645 
3646 /************************* Stepper classes  ****************************/
3647 
3648 /**
3649    Base class of all WKB parsers, which parse different types of geometries
3650    properly. All these classes assume the WKB input is valid and complete.
3651   */
3652 class Stepper_base {
3653  public:
3654   /**
3655     Constructor.
3656     @param dim dimension of points in the geometry to be stepped
3657          over(i.e. current geometry).
3658     @param bo current geometry's byte order
3659     @param has_wkb_hdr true for stepping through geometries within multiXXX and
3660         geometrycollection, false for other geometries.
3661     @param geotype current geometry's type
3662   */
Stepper_base(char dim,Geometry::wkbByteOrder bo,bool has_wkb_hdr,Geometry::wkbType geotype)3663   Stepper_base(char dim, Geometry::wkbByteOrder bo, bool has_wkb_hdr,
3664                Geometry::wkbType geotype) {
3665     m_dim = dim;
3666     DBUG_ASSERT(bo == Geometry::wkb_ndr);
3667     m_bo = bo;
3668     m_has_wkb_hdr = has_wkb_hdr;
3669     m_geotype = geotype;
3670   }
3671 
get_current_byte_order() const3672   Geometry::wkbByteOrder get_current_byte_order() const {
3673     DBUG_ASSERT((m_bo == Geometry::wkb_xdr || m_bo == Geometry::wkb_ndr));
3674     return m_bo;
3675   }
3676 
get_current_geotype() const3677   Geometry::wkbType get_current_geotype() const {
3678     DBUG_ASSERT(Geometry::is_valid_geotype(m_geotype));
3679     return m_geotype;
3680   }
3681 
3682  protected:
3683   /// Current geometry dimension.
3684   char m_dim;
3685   /// Current geometry has a WKB header or not.
3686   bool m_has_wkb_hdr;
3687   /// Current geometry's byte order.
3688   Geometry::wkbByteOrder m_bo;
3689   /// Current geometry's type, e.g. polygon, linestring, etc.
3690   Geometry::wkbType m_geotype;
3691 };
3692 
3693 /**
3694   For iterating points inside multipoint and linestring.
3695   Expected multipoint format: NUM-pts|WKB-HDR1 pt1|WKB-HDR2 pt2|...|WKB-HDRn ptn
3696   Expected linestring format doesn't have the WKB headers.
3697  */
3698 class Point_stepper : public Stepper_base {
3699  public:
Point_stepper(char dim,Geometry::wkbByteOrder bo,bool has_wkb_hdr)3700   Point_stepper(char dim, Geometry::wkbByteOrder bo, bool has_wkb_hdr)
3701       : Stepper_base(dim, bo, has_wkb_hdr, Geometry::wkb_point) {}
3702 
3703   const char *operator()(const char *p);
3704 };
3705 
3706 /**
3707   For iterating linestrings inside multilinestring and polygon.
3708   Expected multilinestring format: NUM-ls|WKB-HDR1 ls1|WKB-HDR2 ls2|....
3709   Expected polygon format doesn't have the WKB headers, and the 1st one is
3710   exterior ring, following if any are interior rings.
3711 
3712   In both cases, the linestrX is of linestring format, with no WKB header
3713   in its each point.
3714 */
3715 class Linestring_stepper : public Stepper_base {
3716  public:
Linestring_stepper(char dim,Geometry::wkbByteOrder bo,bool has_wkb_hdr)3717   Linestring_stepper(char dim, Geometry::wkbByteOrder bo, bool has_wkb_hdr)
3718       : Stepper_base(dim, bo, has_wkb_hdr, Geometry::wkb_linestring) {}
3719 
3720   const char *operator()(const char *p);
3721 };
3722 
3723 /**
3724   For iterating polygons inside multipolygon or geometry collection.
3725   Expected multipolygon format: NUM-plgns|WKB-HDR1 plgn1|WKB-HDR2 plgn2|...
3726   This is also expected format for geometry collection.
3727   In both cases inside polygonX there is no more WKB headers.
3728  */
3729 class Polygon_stepper : public Stepper_base {
3730  public:
Polygon_stepper(char dim,Geometry::wkbByteOrder bo,bool has_wkb_hdr)3731   Polygon_stepper(char dim, Geometry::wkbByteOrder bo, bool has_wkb_hdr)
3732       : Stepper_base(dim, bo, has_wkb_hdr, Geometry::wkb_polygon) {}
3733 
3734   const char *operator()(const char *p);
3735 };
3736 
3737 /// Parsing operator. Note that the returned pointer may point past end of
3738 /// WKB string, and caller is responsible for stoping reading after last
3739 /// geometry is read, this is true for all parsing operator of all stepper
3740 /// classes.
3741 /// @param p points to the 1st byte of a point's wkb data, right after its
3742 /// wkb header if any; returns the next point's wkb data's 1st byte pointer,
3743 /// skipping its wkb header if any.
operator ()(const char * p)3744 const char *Point_stepper::operator()(const char *p) {
3745   p += SIZEOF_STORED_DOUBLE * m_dim;
3746 
3747   // m_bo is latest byte order, which allows mixed byte orders in the same
3748   // wkb byte string.
3749   if (m_has_wkb_hdr) {
3750     Geometry::wkbByteOrder bo = get_byte_order(p);
3751 
3752     // The next one can be other geo types, in a geometry collection.
3753     m_geotype = get_wkb_geotype(p + 1);
3754 
3755     if (m_bo != bo) m_bo = bo;
3756     p += WKB_HEADER_SIZE;
3757   }
3758 
3759   return p;
3760 }
3761 
3762 /// Parsing operator.
3763 /// @param p points to the 1st byte of a linestring's wkb data, right after
3764 /// its wkb header if any;
3765 /// @return the next linestring's wkb data's 1st
3766 /// byte pointer, skipping its wkb header if any.
operator ()(const char * p)3767 const char *Linestring_stepper::operator()(const char *p) {
3768   uint32 npts = 0;
3769 
3770   npts = uint4korr(p);
3771   p += sizeof(uint32);
3772   p += npts * SIZEOF_STORED_DOUBLE * m_dim;
3773 
3774   // The m_bo is latest byte order, which allows mixed byte orders in the same
3775   // wkb byte string.
3776   if (m_has_wkb_hdr) {
3777     Geometry::wkbByteOrder bo = get_byte_order(p);
3778 
3779     // The next one can be other geo types, in a geometry collection.
3780     m_geotype = get_wkb_geotype(p + 1);
3781 
3782     if (m_bo != bo) m_bo = bo;
3783     p += WKB_HEADER_SIZE;  // skip the wkb header if any
3784   }
3785 
3786   return p;
3787 }
3788 
3789 /// Parsing operator.
3790 /// @param p points to the 1st byte of a polygon's wkb data, right after its
3791 /// wkb header if any;
3792 /// @return the next polygon's wkb data's 1st byte pointer,
3793 /// skipping its wkb header if any.
operator ()(const char * p)3794 const char *Polygon_stepper::operator()(const char *p) {
3795   uint32 nls = 0;
3796 
3797   // We pass false because a multilinestring's points don't have
3798   // wkb headers(5 bytes).
3799   Linestring_stepper lsstepper(m_dim, m_bo, false);
3800 
3801   nls = uint4korr(p);
3802   p += sizeof(uint32);
3803 
3804   for (uint32 i = 0; i < nls; i++) p = lsstepper(p);
3805 
3806   // m_bo is latest byte order, which allows mixed byte orders in the same
3807   // wkb byte string.
3808   DBUG_ASSERT(m_has_wkb_hdr);
3809   Geometry::wkbByteOrder bo = get_byte_order(p);
3810 
3811   // The next one can be other geo types, in a geometry collection.
3812   m_geotype = get_wkb_geotype(p + 1);
3813 
3814   if (m_bo != bo) m_bo = bo;
3815   p += WKB_HEADER_SIZE;  // skip the wkb header if any
3816 
3817   return p;
3818 }
3819 
3820 /**
3821   Get inner rings object from a geometry. Internally check that the argument
3822   is a polygon. This function is intended as a helper function and is called
3823   where we don't convert to a polygon pointer although it is a polygon.
3824 
3825   @param g a geometry that must be a polygon.
3826   @return the polygon's inner rings object.
3827  */
3828 // SUPPRESS_UBSAN Wrong downcast. FIXME
3829 static inline Gis_polygon::inner_container_type *inner_rings(const Geometry *g)
3830     SUPPRESS_UBSAN;
inner_rings(const Geometry * g)3831 static inline Gis_polygon::inner_container_type *inner_rings(
3832     const Geometry *g) {
3833   DBUG_ASSERT(g->get_geotype() == Geometry::wkb_polygon);
3834   const Gis_polygon *p = static_cast<const Gis_polygon *>(g);
3835   return p->inner_rings();
3836 }
3837 
3838 /**
3839   Set inner rings object to a geometry. Internally check that the argument
3840   is a polygon. This function is intended as a helper function and is called
3841   where we don't convert to a polygon pointer although it is a polygon.
3842 
3843   @param g a geometry that must be a polygon.
3844   @param inns The interior rings
3845  */
3846 // SUPPRESS_UBSAN Wrong downcast. FIXME
3847 static inline void set_inner_rings(
3848     Geometry *g, Gis_polygon::inner_container_type *inns) SUPPRESS_UBSAN;
set_inner_rings(Geometry * g,Gis_polygon::inner_container_type * inns)3849 static inline void set_inner_rings(Geometry *g,
3850                                    Gis_polygon::inner_container_type *inns) {
3851   DBUG_ASSERT(g->get_geotype() == Geometry::wkb_polygon);
3852   Gis_polygon *p = static_cast<Gis_polygon *>(g);
3853   p->set_inner_rings(inns);
3854 }
3855 
3856 /// Parse the wkb buffer to build the component vector m_geo_vect for geom.
3857 /// Set each geometry's wkb pointer into the Geometry objects inside m_geo_vect.
3858 /// Make it a standalone function in order to be able to access classes defined
3859 /// after class template Gis_wkb_vector.
3860 /// @param geom the geometry to analyze and parse.
3861 /// @param p points to the geometry's wkb data's 1st byte, right after its
3862 /// wkb header if any.
3863 /// @param num_geoms number of following geometries, to be used only when
3864 /// parsing the WKB of a polygon's inner rings because there is no WKB header
3865 /// for the inner rings only.
parse_wkb_data(Geometry * geom,const char * p,size_t num_geoms)3866 void parse_wkb_data(Geometry *geom, const char *p, size_t num_geoms) {
3867   const char *q = nullptr;
3868   size_t nbytes = 0;
3869   Geometry::wkbType geotype = geom->get_geotype();
3870   Geometry::wkbByteOrder mybo = geom->get_byte_order();
3871   char dim = geom->get_dimension();
3872 
3873   DBUG_ASSERT(geotype != Geometry::wkb_polygon_inner_rings ||
3874               (geotype == Geometry::wkb_polygon_inner_rings && num_geoms != 0));
3875   geom->set_bg_adapter(true);
3876   if (p == nullptr) return;
3877 
3878   switch (geotype) {
3879     case Geometry::wkb_point:
3880       // Point doesn't need this vector.
3881       DBUG_ASSERT(false);
3882       break;
3883     case Geometry::wkb_linestring: {
3884       uint32 npts = uint4korr(p);
3885       p += sizeof(uint32);
3886       Point_stepper ptstep(dim, mybo, false);
3887       const char *first = nullptr, *last = nullptr;
3888 
3889       for (uint32 i = 0; i < npts; i++) {
3890         q = p;
3891         if (i == 0) first = p;
3892         if (i < npts - 1) {
3893           p = ptstep(p);
3894           nbytes = p - q;
3895         } else {
3896           nbytes = geom->get_cptr() + geom->get_nbytes() - p;
3897           last = p;
3898         }
3899 
3900         DBUG_ASSERT(nbytes == dim * SIZEOF_STORED_DOUBLE);
3901         // Construct the geometry object as below to avoid unncesarrily
3902         // parsing its WKB data. Parsing will be done in shallow_copy.
3903         Gis_point ent;
3904         ent.Geometry::set_ptr(q);
3905         ent.set_nbytes(nbytes);
3906         ent.set_owner(geom);
3907         geom->shallow_push(&ent);
3908       }
3909 
3910       /*
3911         Historically MySQL GIS require closed polygon rings from user input,
3912         and from now (5.7.4) on we close a polygon ring if it's open before
3913         storing/using it. So we should never see any open rings here.
3914 
3915         However we can't compare memory because the two points may have tiny
3916         differences due to computing deviations.
3917        */
3918 
3919       // Fix compiler warnings.
3920       first = last;
3921       last = first;
3922       break;
3923     }
3924     case Geometry::wkb_multipoint: {
3925       uint32 npts = uint4korr(p);
3926       p += sizeof(uint32);
3927 
3928       Geometry::wkbByteOrder bo = ::get_byte_order(p);
3929       DBUG_ASSERT(get_wkb_geotype(p + 1) == Geometry::wkb_point);
3930       p += WKB_HEADER_SIZE;
3931 
3932       Point_stepper ptstep(dim, bo, true);
3933 
3934       for (uint32 i = 0; i < npts; i++) {
3935         q = p;
3936         if (i < npts - 1) {
3937           p = ptstep(p);
3938           nbytes = p - q - WKB_HEADER_SIZE;
3939         } else
3940           nbytes = geom->get_cptr() + geom->get_nbytes() - p;
3941 
3942         // Construct the geometry object as below to avoid unncesarrily
3943         // parsing its WKB data. Parsing will be done in shallow_copy.
3944         Gis_point ent;
3945         ent.Geometry::set_ptr(q);
3946         ent.set_nbytes(nbytes);
3947         ent.set_owner(geom);
3948         geom->shallow_push(&ent);
3949         bo = ptstep.get_current_byte_order();
3950         DBUG_ASSERT(ptstep.get_current_geotype() == Geometry::wkb_point);
3951       }
3952 
3953       break;
3954     }
3955     case Geometry::wkb_multilinestring: {
3956       uint32 nls = uint4korr(p);
3957       p += sizeof(uint32);
3958 
3959       Geometry::wkbByteOrder bo = ::get_byte_order(p);
3960       DBUG_ASSERT(get_wkb_geotype(p + 1) == Geometry::wkb_linestring);
3961       p += WKB_HEADER_SIZE;
3962       Linestring_stepper lsstep(dim, bo, true);
3963 
3964       for (uint32 i = 0; i < nls; i++) {
3965         q = p;
3966         if (i < nls - 1) {
3967           p = lsstep(p);
3968           nbytes = p - q - WKB_HEADER_SIZE;
3969         } else
3970           nbytes = geom->get_cptr() + geom->get_nbytes() - p;
3971 
3972         // Construct the geometry object as below to avoid unncesarrily
3973         // parsing its WKB data. Parsing will be done in shallow_copy.
3974         Gis_line_string ent;
3975         ent.Geometry::set_ptr(q);
3976         ent.set_nbytes(nbytes);
3977         ent.set_owner(geom);
3978         geom->shallow_push(&ent);
3979         bo = lsstep.get_current_byte_order();
3980         DBUG_ASSERT(lsstep.get_current_geotype() == Geometry::wkb_linestring);
3981       }
3982 
3983       break;
3984     }
3985     case Geometry::wkb_polygon_inner_rings: {
3986       /*
3987         There is no independent WKT for inner rings to parse. Inner rings is
3988         a component of a polygon thus can't have number of rings in its WKB.
3989         When inner rings are parsed here, it must already have been filled,
3990         and we are calling this in methods like push_back, etc,
3991         thus m_geo_vect has the right number of rings.
3992        */
3993       size_t nls = num_geoms;
3994       Linestring_stepper lsstep(dim, mybo, false);
3995 
3996       for (size_t i = 0; i < nls; i++) {
3997         q = p;
3998         if (i < nls - 1) {
3999           p = lsstep(p);
4000           nbytes = p - q;
4001         } else
4002           nbytes = geom->get_cptr() + geom->get_nbytes() - p;
4003 
4004         // Construct the geometry object as below to avoid unncesarrily
4005         // parsing its WKB data. Parsing will be done in shallow_copy.
4006         Gis_polygon_ring ent;
4007         ent.Geometry::set_ptr(q);
4008         ent.set_nbytes(nbytes);
4009         ent.set_owner(geom);
4010         geom->shallow_push(&ent);
4011       }
4012 
4013       break;
4014     }
4015     case Geometry::wkb_polygon: {
4016       uint32 nls = uint4korr(p);
4017       const char *start = p;
4018 
4019       p += sizeof(uint32);
4020 
4021       Linestring_stepper lsstep(dim, mybo, false);
4022 
4023       for (uint32 i = 0; i < nls; i++) {
4024         q = p;
4025         if (i < nls - 1) {
4026           p = lsstep(p);
4027           nbytes = p - q;
4028         } else
4029           nbytes = start + geom->get_nbytes() - p;
4030 
4031         if (i == 0) {
4032           // Parse outer ring.
4033           Gis_polygon_ring *outer = outer_ring(geom);
4034           if (geom->get_ptr() == nullptr) {
4035             outer = new Gis_polygon_ring(
4036                 q, nbytes, Geometry::Flags_t(Geometry::wkb_linestring, 0),
4037                 geom->get_srid());
4038             outer->set_props(Geometry::POLYGON_OUTER_RING);
4039             geom->Geometry::set_ptr(outer);
4040           } else {
4041             outer->set_ptr(const_cast<char *>(q), nbytes);
4042             outer->set_byte_order(mybo);
4043             outer->set_dimension(dim);
4044             outer->set_geotype(Geometry::wkb_linestring);
4045           }
4046 
4047           outer->set_owner(geom);
4048           /*
4049             When parsing data to get polygon, the memory is a continuous chunk
4050             belonging to the owner, or it's an existing WKB buffer. Also true
4051             for below inner rings.
4052           */
4053           outer->set_ownmem(false);
4054         } else {
4055           Gis_polygon::inner_container_type *inners = inner_rings(geom);
4056 
4057           if (inners == nullptr) {
4058             inners = new Gis_polygon::inner_container_type();
4059             set_inner_rings(geom, inners);
4060             inners->set_byte_order(mybo);
4061             inners->set_dimension(dim);
4062             inners->set_geotype(Geometry::wkb_polygon_inner_rings);
4063             inners->set_owner(geom);
4064             inners->set_geo_vect(new Geometry_vector<Gis_polygon_ring>());
4065             inners->set_ptr(const_cast<char *>(q), 0 /* Accumulated below. */);
4066             inners->set_ownmem(false);
4067           }
4068 
4069           // Construct the geometry object as below to avoid unncesarrily
4070           // parsing its WKB data. Parsing will be done in shallow_push.
4071           Gis_polygon_ring ent;
4072           ent.Geometry::set_ptr(q);
4073           ent.set_nbytes(nbytes);
4074           ent.set_owner(inners);
4075           ent.set_props(Geometry::POLYGON_INNER_RING);
4076           inners->shallow_push(&ent);
4077           inners->set_nbytes(inners->get_nbytes() + nbytes);
4078         }
4079       }
4080       geom->polygon_is_wkb_form(false);
4081 
4082       break;
4083     }
4084     case Geometry::wkb_multipolygon: {
4085       uint32 nplgns = uint4korr(p);
4086       p += sizeof(uint32);
4087 
4088       Geometry::wkbByteOrder bo = ::get_byte_order(p);
4089       DBUG_ASSERT(get_wkb_geotype(p + 1) == Geometry::wkb_polygon);
4090       p += WKB_HEADER_SIZE;
4091       Polygon_stepper plgn_step(dim, bo, true);
4092 
4093       for (uint32 i = 0; i < nplgns; i++) {
4094         q = p;
4095         if (i < nplgns - 1) {
4096           p = plgn_step(p);
4097           nbytes = p - q - WKB_HEADER_SIZE;
4098         } else
4099           nbytes = geom->get_cptr() + geom->get_nbytes() - p;
4100 
4101         /*
4102           Construct the geometry object as below to avoid unncesarrily
4103           parsing its WKB data. Parsing will be done in shallow_copy.
4104          */
4105         Gis_polygon ent;
4106         ent.Geometry::set_ptr(q);
4107         ent.set_nbytes(nbytes);
4108         ent.set_owner(geom);
4109         geom->shallow_push(&ent);
4110         // The object 'ent' doesn't have any data of its own.
4111         ent.donate_data();
4112         bo = plgn_step.get_current_byte_order();
4113         DBUG_ASSERT(plgn_step.get_current_geotype() == Geometry::wkb_polygon);
4114       }
4115 
4116       break;
4117     }
4118     case Geometry::wkb_geometrycollection:
4119       /*
4120         We never create a Gis_wkb_vector using a geometry collection, because
4121         BG never uses such a type.
4122        */
4123       DBUG_ASSERT(false);
4124       break;
4125     default:
4126       DBUG_ASSERT(false);
4127       break;
4128   }
4129 }
4130 
4131 /**
4132   In place normalize polygons' rings, making outer ring CCW and inner rings CW
4133   by reversing the ring's points in the WKB buffer inplace. This function can
4134   not be made a virtual function since BG adapter geometry objects may also
4135   need it.
4136 
4137   @return the WKB buffer address of the geometry which contains the
4138           converted WKB data. If geometry data is invalid, returns NULL.
4139  */
normalize_ring_order()4140 const void *Geometry::normalize_ring_order() {
4141   Geometry *geo = this;
4142   bool inval = false;
4143 
4144   if (geo->get_type() == Geometry::wkb_polygon) {
4145     Gis_polygon bgeo(geo->get_data_ptr(), geo->get_data_size(),
4146                      geo->get_flags(), geo->get_srid());
4147     if (bgeo.set_polygon_ring_order()) inval = true;
4148   } else if (geo->get_type() == Geometry::wkb_multipolygon) {
4149     Gis_multi_polygon bgeo(geo->get_data_ptr(), geo->get_data_size(),
4150                            geo->get_flags(), geo->get_srid());
4151 
4152     for (size_t i = 0; i < bgeo.size(); i++)
4153       if (bgeo[i].set_polygon_ring_order()) {
4154         inval = true;
4155         break;
4156       }
4157   } else if (geo->get_type() == Geometry::wkb_geometrycollection) {
4158     /*
4159       This is impossible because BG doesn't use a geometry collection, and
4160       we can't create a Gis_wkb_vector<T> with a geometry collection.
4161     */
4162     DBUG_ASSERT(false);
4163   }
4164 
4165   if (inval) return nullptr;
4166   return geo->get_data_ptr();
4167 }
4168 
4169 /**
4170    Because of resize, a geometry's components may reside not in one chunk,
4171    some may in the m_ptr's chunk; others have their own memory and only exist
4172    in m_geo_vect vector, not in ptr's chunk. Also, a constructed polygon's
4173    data is always not in a chunk and needs to be so when it's pushed into a
4174    multipolygon/geometry collection.
4175    Thus in mysql before using the returned geometry, also inside the
4176    container classes before using the wkb data or clearing m_geo_vect,
4177    we need to make them inline, i.e. reside in one chunk of memory.
4178    Can only resize a topmost geometry, thus no recursive reassemling
4179    to do for now.
4180 
4181    Algorithm:
4182 
4183    Step 1. Structure analysis
4184 
4185    Scan this geometry's components, see whether each of them has its own
4186    memory, if so it's 'out of line', otherwise it's 'inline'. Note down
4187    those owning memory in a map M1, for each entry X in the map M1, the
4188    component's index in the component vector m_geo_vect is used as key;
4189    The inline chunk of memory right before it which may have any number
4190    of inline components, and the inline chunk's start and end address pair
4191    is used as value of the inserted item X. If there is no inline chunk
4192    before the component, X's pointer range is (0, 0). The inline chunk's
4193    starting address is well maintained during the scan.
4194 
4195 
4196    Step 2. Reassembling
4197 
4198    Allocate enough memory space (the length is accumulated in step 1) as WKB
4199    buffer and call it GBuf here, then copy the WKB of inline and out-of-line
4200    geometries into GBuf in original order:
4201    Go through the map by index order, for each item, copy the WKB chunk
4202    before it into the WKB buffer, then copy this out-of-line geometry's WKB
4203    into GBuf.
4204 
4205    Special treatment of polygon: we have to pack its value and store their
4206    WKB separately into a map GP in step 1, and in step 2 for a polygon,
4207    get its WKB from GP, and at the end release WKB memory buffers held by
4208    items of GP.
4209  */
4210 template <typename T>
reassemble()4211 void Gis_wkb_vector<T>::reassemble() {
4212   set_bg_adapter(true);
4213   Geometry::wkbType geotype = get_geotype();
4214   if (geotype == Geometry::wkb_point || geotype == Geometry::wkb_polygon ||
4215       geotype == Geometry::wkb_multipoint || m_geo_vect == nullptr ||
4216       geotype == Geometry::wkb_linestring || m_geo_vect->size() == 0 ||
4217       !has_out_of_line_components())
4218     return;
4219 
4220   if (m_geo_vect == nullptr) m_geo_vect = new Geo_vector;
4221   typedef std::map<size_t, std::pair<const char *, const char *>> segs_t;
4222   segs_t segs;
4223   size_t hdrsz = 0, num = m_geo_vect->size(), prev_in = 0, totlen = 0,
4224          segsz = 0;
4225   Geo_vector &vec = *m_geo_vect;
4226   const char *start = get_cptr(), *end = nullptr, *prev_start = get_cptr();
4227   std::map<size_t, std::pair<void *, size_t>> plgn_data;
4228   std::map<size_t, std::pair<void *, size_t>>::iterator plgn_data_itr;
4229   bool is_inns = (geotype == Geometry::wkb_polygon_inner_rings);
4230 
4231   // True if just passed by a geometry having its own memory and not stored
4232   // inside owner's memory during the scan.
4233   bool out = false;
4234   if (geotype != Geometry::wkb_polygon_inner_rings) hdrsz = WKB_HEADER_SIZE;
4235 
4236   uint32 none = 0;  // Used when all components are out of line.
4237 
4238   // Starting step one of the algorithm --- Structure Analysis.
4239   for (size_t i = 0; i < num; i++) {
4240     T *veci = &(vec[i]);
4241     // Polygons are always(almost) out of line. One with its own memory is
4242     // always out of line.
4243     if (veci->get_geotype() == Geometry::wkb_polygon || veci->get_ownmem()) {
4244       // In case of a polygon, see if it's already inline in a different
4245       // way from other types of geometries.
4246       if (veci->get_geotype() == Geometry::wkb_polygon &&
4247           polygon_is_packed(veci, this)) {
4248         if (out) {
4249           out = false;
4250           DBUG_ASSERT(prev_start == veci->get_ptr());
4251         }
4252         prev_in = i;
4253         continue;
4254       }
4255 
4256       // Record the bytes before 1st geometry component.
4257       if (i == 0) {
4258         if (m_ptr) {
4259           start = get_cptr();
4260           end = start + sizeof(uint32) /* num geometrys*/;
4261         } else if (!is_inns) {
4262           start = reinterpret_cast<char *>(&none);
4263           end = start + sizeof(none);
4264         } else
4265           start = end = nullptr;
4266       }
4267       // The previous geometry is already out of line, or no m_ptr allocated.
4268       else if (out || !prev_start) {
4269         start = nullptr;
4270         end = nullptr;
4271       } else  // The previous geometry is inline, note down the inline range.
4272       {
4273         start = prev_start;
4274         if (veci->get_geotype() == Geometry::wkb_polygon)
4275           end = get_packed_ptr(&(vec[prev_in])) + vec[prev_in].get_nbytes();
4276         else
4277           end = vec[prev_in].get_cptr() + vec[prev_in].get_nbytes();
4278         prev_start = end;
4279         // The 'end' points to the 1st byte of next geometry stored in its
4280         // owner's memory.
4281       }
4282 
4283       if (veci->get_geotype() != Geometry::wkb_polygon) {
4284         // When this geometry is a geometry collection, we need to make its
4285         // components in one chunk first. Not gonna implement this yet since
4286         // BG doesn't use geometry collection yet, and consequently no
4287         // component can be a multipoint/multilinestring/multipolygon or a
4288         // geometrycollection. And multipoint components are already supported
4289         // so not forbidding them here.
4290 #if !defined(DBUG_OFF)
4291         Geometry::wkbType veci_gt = veci->get_geotype();
4292 #endif
4293         DBUG_ASSERT(veci_gt != wkb_geometrycollection &&
4294                     veci_gt != wkb_multilinestring &&
4295                     veci_gt != wkb_multipolygon);
4296         /* A point/multipoint/linestring is always in one memory chunk. */
4297         totlen += veci->get_nbytes() + hdrsz;
4298       } else {
4299         // Must be a polygon out of line.
4300         size_t nbytes = 0;
4301         void *plgn_base = get_packed_ptr(veci, &nbytes);
4302         DBUG_ASSERT(veci->get_nbytes() == 0 || veci->get_nbytes() == nbytes);
4303         veci->set_nbytes(nbytes);
4304         plgn_data.insert(std::make_pair(i, std::make_pair(plgn_base, nbytes)));
4305         totlen += nbytes + hdrsz;
4306       }
4307 
4308       segs.insert(std::make_pair(i, std::make_pair(start, end)));
4309       out = true;
4310     } else {
4311       if (out) {
4312         out = false;
4313         DBUG_ASSERT(prev_start == veci->get_ptr());
4314       }
4315       prev_in = i;
4316     }
4317   }
4318 
4319   segsz = segs.size();
4320   if (segsz == 0) {
4321     has_out_of_line_components(false);
4322     return;
4323   }
4324 
4325   size_t nbytes = get_nbytes();
4326   DBUG_ASSERT((nbytes == 0 && m_ptr == nullptr && num == segsz) ||
4327               (nbytes > 0 && num >= segsz));
4328 
4329   // If all are out of line, m_ptr is 0 and no room for ring count, otherwise
4330   // the space for ring count is already counted above.
4331   totlen += (nbytes ? nbytes : (is_inns ? 0 : sizeof(uint32)));
4332 
4333   size_t len = 0, total_len = 0, last_i = 0, numgeoms = 0;
4334   // Allocate extra space as free space for the WKB buffer, and write it as
4335   // defined pattern.
4336   const size_t extra_wkb_free_space = 32;
4337   char *ptr = static_cast<char *>(gis_wkb_alloc(totlen + extra_wkb_free_space));
4338   // The header(object count) is already copied.
4339   char *q = ptr;
4340 
4341   if (ptr == nullptr) {
4342     clear_wkb_data();
4343     m_ptr = nullptr;
4344     set_nbytes(0);
4345     set_ownmem(false);
4346     goto exit;
4347   }
4348   memset(ptr + totlen, 0xff, extra_wkb_free_space - 1);
4349   ptr[totlen + extra_wkb_free_space - 1] = '\0';
4350 
4351   // Starting step two of the algorithm --- Reassembling.
4352   // Assemble the ins and outs into a single chunk.
4353   for (segs_t::iterator itr = segs.begin(); itr != segs.end(); ++itr) {
4354     size_t i = itr->first;
4355     start = itr->second.first;
4356     end = itr->second.second;
4357     const Geometry *veci = &(vec[i]);
4358     last_i = i;
4359 
4360     // Copy the inline geometries before veci into buffer.
4361     if (start) {
4362       memcpy(q, start, len = end - start);
4363       q += len;
4364       total_len += len;
4365     }
4366 
4367     // Set WKB header. This geometry must be one of multilinestring,
4368     // multipolygon or a polygon's inner rings.
4369     if (get_geotype() != Geometry::wkb_polygon_inner_rings) {
4370       q = write_wkb_header(q, veci->get_geotype());
4371       total_len += hdrsz;
4372     }
4373 
4374     // Copy the out of line geometry into buffer. A polygon's data isn't
4375     // packed inside itself, we've packed it and recorded it in plgn_data.
4376     plgn_data_itr = plgn_data.find(i);
4377     if (veci->get_geotype() != Geometry::wkb_polygon) {
4378       DBUG_ASSERT(plgn_data_itr == plgn_data.end());
4379       len = veci->get_nbytes();
4380       memcpy(q, veci->get_ptr(), len);
4381     } else {
4382       DBUG_ASSERT(plgn_data_itr != plgn_data.end());
4383       len = plgn_data_itr->second.second;
4384       memcpy(q, plgn_data_itr->second.first, len);
4385     }
4386     q += len;
4387     total_len += len;
4388   }
4389 
4390   // There may be trailing inline geometries to copy at old tail.
4391   if (last_i < vec.size() - 1) {
4392     len = get_cptr() + get_nbytes() - prev_start;
4393     memcpy(q, prev_start, len);
4394     total_len += len;
4395   }
4396   DBUG_ASSERT(total_len == totlen);
4397 
4398   // Inner rings doesn't have ring count.
4399   if (!is_inns) {
4400     DBUG_ASSERT(segsz + uint4korr(ptr) <= 0xFFFFFFFF);
4401     int4store(reinterpret_cast<uchar *>(ptr),
4402               uint4korr(ptr) + static_cast<uint32>(segsz));
4403   }
4404 
4405   numgeoms = m_geo_vect->size();
4406   clear_wkb_data();
4407   set_ptr(ptr, totlen);
4408   // An inner ring isn't parsed in set_ptr, has to parse separately since
4409   // we don't know its number of rings.
4410   if (is_inns) parse_wkb_data(this, get_cptr(), numgeoms);
4411   set_ownmem(true);
4412 exit:
4413   for (plgn_data_itr = plgn_data.begin(); plgn_data_itr != plgn_data.end();
4414        ++plgn_data_itr)
4415     gis_wkb_free(plgn_data_itr->second.first);
4416 
4417   has_out_of_line_components(false);
4418 }
4419 
4420 /// @brief Constructor.
4421 /// @param ptr points to the geometry's wkb data's 1st byte, right after its
4422 /// wkb header if any.
4423 /// @param nbytes the byte order indicated by @p ptr's wkb header.
4424 /// @param flags The geometry's flags
4425 /// @param srid The geometry's SRID
4426 /// @param is_bg_adapter Whether this object is created to be used by
4427 ///        Boost Geometry, or to be only used in MySQL code.
4428 template <typename T>
Gis_wkb_vector(const void * ptr,size_t nbytes,const Flags_t & flags,gis::srid_t srid,bool is_bg_adapter)4429 Gis_wkb_vector<T>::Gis_wkb_vector(const void *ptr, size_t nbytes,
4430                                   const Flags_t &flags, gis::srid_t srid,
4431                                   bool is_bg_adapter)
4432     : Geometry(ptr, nbytes, flags, srid) {
4433   DBUG_ASSERT((ptr != nullptr && nbytes > 0) ||
4434               (ptr == nullptr && nbytes == 0));
4435   set_ownmem(false);  // We use existing WKB data and don't own that memory.
4436   set_bg_adapter(is_bg_adapter);
4437   m_geo_vect = nullptr;
4438 
4439   if (!is_bg_adapter) return;
4440 
4441   std::unique_ptr<Geo_vector> guard;
4442 
4443   wkbType geotype = get_geotype();
4444   // Points don't need it, polygon creates it when parsing.
4445   if (geotype != Geometry::wkb_point && geotype != Geometry::wkb_polygon &&
4446       ptr != nullptr)
4447     guard.reset(m_geo_vect = new Geo_vector());
4448   // For polygon parsing to work
4449   if (geotype == Geometry::wkb_polygon) m_ptr = nullptr;
4450 
4451   // Why: wkb_polygon_inner_rings should parse in polygon as a whole.
4452   // Don't call get_cptr() here, it returns NULL.
4453   if (geotype != Geometry::wkb_polygon_inner_rings && ptr != nullptr)
4454     parse_wkb_data(this, static_cast<const char *>(ptr));
4455 
4456   guard.release();
4457 }
4458 
4459 template <typename T>
Gis_wkb_vector(const Gis_wkb_vector<T> & v)4460 Gis_wkb_vector<T>::Gis_wkb_vector(const Gis_wkb_vector<T> &v)
4461     : Geometry(v), m_geo_vect(nullptr) {
4462   DBUG_ASSERT(
4463       (v.get_ptr() != nullptr && v.get_nbytes() > 0) ||
4464       (v.get_ptr() == nullptr && !v.get_ownmem() && v.get_nbytes() == 0));
4465   if (!v.is_bg_adapter() || (v.get_ptr() == nullptr && v.m_geo_vect == nullptr))
4466     return;
4467   m_geo_vect = new Geo_vector();
4468   std::unique_ptr<Geo_vector> guard(m_geo_vect);
4469 
4470   const_cast<self &>(v).reassemble();
4471   set_flags(v.get_flags());
4472   set_nbytes(v.get_nbytes());
4473   if (get_nbytes() > 0) {
4474     m_ptr = gis_wkb_alloc(v.get_nbytes() + 2);
4475     if (m_ptr == nullptr) {
4476       m_geo_vect = nullptr;
4477       set_ownmem(false);
4478       set_nbytes(0);
4479       return;
4480     }
4481     memcpy(m_ptr, v.get_ptr(), v.get_nbytes());
4482     /*
4483       The extra 2 bytes makes the buffer usable by get_nbytes_free.
4484       It's hard to know how many more space will be needed so let's
4485       allocate more later.
4486     */
4487     get_cptr()[get_nbytes()] = '\xff';
4488     get_cptr()[get_nbytes() + 1] = '\0';
4489     parse_wkb_data(this, get_cptr(), v.get_geo_vect()->size());
4490     set_ownmem(true);
4491   }
4492   guard.release();
4493 }
4494 
4495 /**
4496   Deep assignment from vector 'rhs' to this object.
4497   @param rhs the Gis_wkb_vector<T> instance to duplicate from.
4498 */
4499 template <typename T>
operator =(const Gis_wkb_vector<T> & rhs)4500 Gis_wkb_vector<T> &Gis_wkb_vector<T>::operator=(const Gis_wkb_vector<T> &rhs) {
4501   if (this == &rhs) return *this;
4502   Geometry::operator=(rhs);
4503 
4504   DBUG_ASSERT((m_ptr != nullptr && get_ownmem() && get_nbytes() > 0) ||
4505               (m_ptr == nullptr && !get_ownmem() && get_nbytes() == 0));
4506   DBUG_ASSERT(
4507       (rhs.get_ptr() != nullptr && rhs.get_nbytes() > 0) ||
4508       (rhs.get_ptr() == nullptr && !rhs.get_ownmem() && rhs.get_nbytes() == 0));
4509 
4510   if (m_owner == nullptr) m_owner = rhs.get_owner();
4511 
4512   size_t nbytes_free = get_nbytes_free();
4513   clear_wkb_data();
4514 
4515   if (rhs.get_ptr() == nullptr) {
4516     if (m_ptr != nullptr) gis_wkb_free(m_ptr);
4517     m_ptr = nullptr;
4518     set_flags(rhs.get_flags());
4519     return *this;
4520   }
4521 
4522   /*
4523     Geometry v may have out of line components, need to reassemble first.
4524    */
4525   const_cast<self &>(rhs).reassemble();
4526 
4527   /*
4528     If have no enough space, reallocate with extra space padded with required
4529     bytes;
4530    */
4531   if (m_ptr == nullptr || get_nbytes() + nbytes_free < rhs.get_nbytes()) {
4532     gis_wkb_free(m_ptr);
4533     m_ptr = gis_wkb_alloc(rhs.get_nbytes() + 32 /* some extra space. */);
4534     if (m_ptr == nullptr) {
4535       /*
4536         This object in this case is valid although it doesn't have any data.
4537        */
4538       set_nbytes(0);
4539       set_ownmem(false);
4540       return *this;
4541     }
4542 
4543     // Fill extra space with pattern defined by
4544     // Gis_wkb_vector<>::get_nbytes_free().
4545     char *cp = get_cptr();
4546     memset(cp + rhs.get_nbytes(), 0xFF, 32);
4547     cp[rhs.get_nbytes() + 31] = '\0';
4548   }
4549 
4550   /*
4551     If need less space than before, set remaining bytes to 0xFF as requred
4552     by Gis_wkb_vector<>::get_nbytes_free.
4553    */
4554   if (get_nbytes() > rhs.get_nbytes())
4555     memset(get_cptr() + rhs.get_nbytes(), 0xFF,
4556            get_nbytes() - rhs.get_nbytes());
4557 
4558   memcpy(m_ptr, rhs.get_ptr(), rhs.get_nbytes());
4559 
4560   set_flags(rhs.get_flags());
4561   set_ownmem(true);
4562 
4563   m_geo_vect = new Geo_vector();
4564   parse_wkb_data(this, get_cptr());
4565   return *this;
4566 }
4567 
4568 /**
4569   The copy constructors of Geometry classes always do deep copy, but when
4570   pushing a Geometry object into its owner's geo.m_geo_vect, we want to do
4571   shallow copy because we want all elements in geo.m_geo_vect vector point
4572   into locations in the geo.m_ptr buffer. In such situations call this
4573   function.
4574   @param g   The Geometry object to push into vec.
4575  */
4576 template <typename T>
shallow_push(const Geometry * g)4577 void Gis_wkb_vector<T>::shallow_push(const Geometry *g) {
4578   const T &geo = *(static_cast<const T *>(g));
4579   T *pgeo = nullptr;
4580 
4581   if (m_geo_vect == nullptr) m_geo_vect = new Geo_vector();
4582   // Allocate space and create an object with its default constructor.
4583   pgeo = static_cast<T *>(m_geo_vect->append_object());
4584   DBUG_ASSERT(pgeo != nullptr);
4585   if (pgeo == nullptr) return;
4586 
4587   pgeo->set_flags(geo.get_flags());
4588   pgeo->set_srid(geo.get_srid());
4589   pgeo->set_bg_adapter(true);
4590   // Such a shallow copied object never has its own memory regardless of geo.
4591   pgeo->set_ownmem(false);
4592 
4593   // This will parse and set up pgeo->m_geo_vect properly.
4594   // Do not copy elements from geo.m_geo_vect into that of pgeo
4595   // otherwise STL does deep copy using the Geometry copy constructor.
4596   pgeo->set_ptr(geo.get_ptr(), geo.get_nbytes());
4597   pgeo->set_owner(geo.get_owner());
4598 }
4599 
4600 template <typename T>
set_ptr(void * ptr,size_t len)4601 void Gis_wkb_vector<T>::set_ptr(void *ptr, size_t len) {
4602   DBUG_ASSERT(!(ptr == nullptr && len > 0));
4603   set_bg_adapter(true);
4604   if (get_geotype() != Geometry::wkb_polygon) {
4605     if (get_ownmem() && m_ptr != nullptr) gis_wkb_free(m_ptr);
4606     m_ptr = ptr;
4607     if (m_geo_vect) clear_wkb_data();
4608   }
4609   set_nbytes(len);
4610   /* When invoked, this object may or may not have its own memory. */
4611   if (get_geotype() != Geometry::wkb_polygon_inner_rings && m_ptr != nullptr) {
4612     if (m_geo_vect == nullptr) m_geo_vect = new Geo_vector();
4613     parse_wkb_data(this, get_cptr());
4614   }
4615 }
4616 
4617 /**
4618   Update support
4619   We suppose updating a geometry can happen in the following ways:
4620   1. create an empty geo, then append components into it, the geo must
4621      be a topmost one; a complex geometry such as a multilinestring can be
4622      seen as a tree of geometry components, and the mlstr is the topmost
4623      geometry, i.e. the root of the tree, its lstrs are next layer of nodes,
4624      their points are the 3rd layer of tree nodes. Only the root owns the
4625      wkb buffer, other components point somewhere into the buffer, and can
4626      only read the data.
4627 
4628      Polygons are only used by getting its exterior ring or inner rings and
4629      then work on that/those rings, never used as a whole.
4630 
4631   2. *itr=value, each geo::m_owner can be used to track the topmost
4632      memory owner, and do reallocation to accormodate the value. This is
4633      for now not supported, will be if needed.
4634 
4635      So far geometry assignment are only used for point objects in boost
4636      geometry, thus only Geometry and Gis_point have operator=, no other
4637      classes need so, and thus there is no need for reallocation.
4638   3. call resize() to append some objects at the end, then assign/append
4639      values to the added objects using push_back. Objects added this way
4640      are out of line(unless the object is a point), and user need to call
4641      reassemble() to make them inline, i.e. stored in its owner's memory.
4642 */
4643 
4644 /// Clear geometry data of this object.
4645 template <typename T>
clear()4646 void Gis_wkb_vector<T>::clear() {
4647   if (!m_geo_vect) {
4648     DBUG_ASSERT(m_ptr == nullptr);
4649     return;
4650   }
4651 
4652   DBUG_ASSERT(m_geo_vect && get_geotype() != Geometry::wkb_polygon);
4653 
4654   // Keep the component vector because this object can be reused again.
4655   const void *ptr = get_ptr();
4656   set_bg_adapter(true);
4657 
4658   if (ptr && get_ownmem()) {
4659     gis_wkb_free(const_cast<void *>(ptr));
4660     set_ownmem(false);
4661   }
4662 
4663   m_ptr = nullptr;
4664   clear_wkb_data();
4665   set_nbytes(0);
4666 }
4667 
4668 /// Returns payload number of bytes of the topmost geometry holding this
4669 /// geometry, i.e. the memory owner.
4670 template <typename T>
current_size() const4671 size_t Gis_wkb_vector<T>::current_size() const {
4672   // Polygon's data may not stay in a continuous chunk, and we update
4673   // its data using the outer/inner rings.
4674   DBUG_ASSERT(get_geotype() != Geometry::wkb_polygon);
4675   set_bg_adapter(true);
4676   if (m_geo_vect == nullptr || m_geo_vect->empty()) return 0;
4677 
4678   return get_nbytes();
4679 }
4680 
4681 /// Get number of free bytes in the buffer held by m_ptr. this object must be
4682 /// an topmost geometry which owns memory.
4683 template <typename T>
get_nbytes_free() const4684 size_t Gis_wkb_vector<T>::get_nbytes_free() const {
4685   DBUG_ASSERT((this->get_ownmem() && m_ptr) || (!get_ownmem() && !m_ptr));
4686 
4687   size_t cap = current_size();
4688   if (cap == 0) {
4689     DBUG_ASSERT(m_ptr == nullptr);
4690     return 0;
4691   }
4692 
4693   const char *p = nullptr, *ptr = get_cptr();
4694   DBUG_ASSERT(ptr != nullptr);
4695 
4696   /*
4697     There will always be remaining free space because in push_back, when
4698     number of free bytes equals needed bytes we will do a realloc.
4699    */
4700   for (p = ptr + cap; *p != 0; p++)
4701     ;
4702 
4703   return p - ptr - cap + 1;
4704 }
4705 
4706 template <typename T>
push_back(const T & val)4707 void Gis_wkb_vector<T>::push_back(const T &val) {
4708   Geometry::wkbType geotype = get_geotype();
4709 
4710   DBUG_ASSERT(geotype != Geometry::wkb_polygon &&
4711               ((m_ptr && get_ownmem()) || (!m_ptr && !get_ownmem())));
4712 
4713   // Only three possible types of geometries for val, thus no need to
4714   // do val.reassemble().
4715   DBUG_ASSERT(val.get_geotype() == wkb_point ||
4716               val.get_geotype() == wkb_polygon ||
4717               val.get_geotype() == wkb_linestring);
4718 
4719   DBUG_ASSERT(val.get_ptr() != nullptr);
4720 
4721   size_t cap = 0, nalloc = 0;
4722   size_t vallen, needed;
4723   void *src_val = val.get_ptr();
4724 
4725   if (m_geo_vect == nullptr) m_geo_vect = new Geo_vector;
4726   set_bg_adapter(true);
4727   vallen = val.get_nbytes();
4728   /*
4729     Often inside bg, a polygon is created with no data, then append points
4730     into outer ring and inner rings, such a polygon is a 'constructed'
4731     polygon, and in this case we need to assemble
4732     its data into a continuous chunk.
4733    */
4734   if (val.get_geotype() == Geometry::wkb_polygon)
4735     src_val = get_packed_ptr(&val, &vallen);
4736 
4737   // The 4 types can be resized and have out-of-line components,
4738   // reassemble first in case we lose them when doing m_geo_vect->clear().
4739   if (geotype == Geometry::wkb_multilinestring ||
4740       geotype == Geometry::wkb_geometrycollection ||
4741       geotype == Geometry::wkb_polygon_inner_rings ||
4742       geotype == Geometry::wkb_multipolygon)
4743     reassemble();
4744 
4745   // Get cap only after reassemble().
4746   cap = current_size();
4747 
4748   needed = vallen + WKB_HEADER_SIZE;
4749   // Use >= instead of > because we always want to have trailing free bytes.
4750   if (needed >= this->get_nbytes_free()) {
4751     nalloc = cap + ((needed * 2 > 256) ? needed * 2 : 256);
4752     void *ptr = get_ptr();
4753     m_ptr = gis_wkb_realloc(m_ptr, nalloc);
4754     if (m_ptr == nullptr) {
4755       set_nbytes(0);
4756       set_ownmem(0);
4757       clear_wkb_data();
4758       return;
4759     }
4760 
4761     // Set unused space to -1, and last unused byte to 0.
4762     // Function get_nbytes_free relies on this format.
4763     memset(get_cptr() + cap, 0xff, nalloc - cap);
4764     get_cptr()[nalloc - 1] = '\0';
4765     memset(get_cptr() + cap, 0, sizeof(uint32));
4766 
4767     bool replaced = (ptr != m_ptr);
4768     set_ownmem(true);
4769     if (m_owner && m_owner->get_geotype() == Geometry::wkb_polygon)
4770       m_owner->set_ownmem(true);
4771 
4772     // After reallocation we need to parse again.
4773     if (cap > 0 && replaced) {
4774       size_t ngeos = 0;
4775       if (geotype == Geometry::wkb_polygon_inner_rings) ngeos = size();
4776       clear_wkb_data();
4777       parse_wkb_data(this, get_cptr(), ngeos);
4778     }
4779   }
4780 
4781   size_t wkb_header_size = 0;
4782   /* Offset for obj count, if needed. */
4783   size_t obj_count_len =
4784       ((cap == 0 && geotype != Geometry::wkb_polygon_inner_rings)
4785            ? sizeof(uint32)
4786            : 0);
4787   char *val_ptr = get_cptr() + cap + obj_count_len;
4788 
4789   // Append WKB header first, if needed.
4790   if (geotype == Geometry::wkb_multipoint ||
4791       geotype == Geometry::wkb_multipolygon ||
4792       geotype == Geometry::wkb_multilinestring ||
4793       geotype == Geometry::wkb_geometrycollection) {
4794     Geometry::wkbType vgt = val.get_geotype();
4795     DBUG_ASSERT(
4796         (geotype == Geometry::wkb_multipoint && vgt == Geometry::wkb_point) ||
4797         (geotype == Geometry::wkb_multipolygon &&
4798          vgt == Geometry::wkb_polygon) ||
4799         (geotype == Geometry::wkb_multilinestring &&
4800          vgt == Geometry::wkb_linestring) ||
4801         geotype == Geometry::wkb_geometrycollection);
4802 
4803     val_ptr = write_wkb_header(val_ptr, vgt);
4804     wkb_header_size = WKB_HEADER_SIZE;
4805   }
4806 
4807   // Copy val's data into buffer, then parse it.
4808   memcpy(val_ptr, src_val, vallen);
4809   set_nbytes(get_nbytes() + wkb_header_size + obj_count_len + vallen);
4810 
4811   // Append geometry component into m_geo_vect vector. Try to avoid
4812   // unnecessary parse by calling the right version of set_ptr. And do
4813   // shallow push so that the element in m_geo_vect point to WKB buffer
4814   // rather than have its own copy of the same WKB data.
4815   T val2;
4816   val2.set_flags(val.get_flags());
4817   val2.set_srid(val.get_srid());
4818   val2.Geometry::set_ptr(val_ptr);
4819   val2.set_nbytes(vallen);
4820   val2.set_owner(this);
4821   val2.set_ownmem(false);
4822 
4823   shallow_push(&val2);
4824   val2.Geometry::set_ptr(nullptr);
4825 
4826   if (val2.get_geotype() == Geometry::wkb_polygon)
4827     own_rings(&(m_geo_vect->back()));
4828   if (geotype != Geometry::wkb_polygon_inner_rings) {
4829     int4store(get_ucptr(), uint4korr(get_ucptr()) + 1);
4830     DBUG_ASSERT(uint4korr(get_ucptr()) == this->m_geo_vect->size());
4831   }
4832 
4833   if (val.get_geotype() == Geometry::wkb_polygon) gis_wkb_free(src_val);
4834 }
4835 
4836 /*
4837   Resize as in std::vector<>::resize().
4838 
4839   Because resize can be called to append an empty geometry into its owner,
4840   we have to allow pushing into an empty geo and its memory will not
4841   be in the same chunk as its owner, which is OK for bg since the
4842   Boost Range concept doesn't forbid so. But inside MySQL we should
4843   reassemble the geometries into one chunk before using the WKB buffer
4844   directly, by calling reassemble().
4845 */
4846 template <typename T>
resize(size_t sz)4847 void Gis_wkb_vector<T>::resize(size_t sz) {
4848   if (m_geo_vect == nullptr) m_geo_vect = new Geo_vector;
4849   Geometry::wkbType geotype = get_geotype();
4850   size_t ngeo = m_geo_vect->size();
4851   size_t dim = GEOM_DIM;
4852   size_t ptsz = SIZEOF_STORED_DOUBLE * dim;
4853   bool is_mpt = (geotype == Geometry::wkb_multipoint);
4854 
4855   // Can resize a topmost geometry or a out of line geometry which has
4856   // or will have its own memory(i.e. one that's not using others' memory).
4857   // Points are fixed size, polygon doesn't hold data directly.
4858   DBUG_ASSERT(!(m_ptr != nullptr && !get_ownmem()) &&
4859               geotype != Geometry::wkb_point &&
4860               geotype != Geometry::wkb_polygon);
4861   set_bg_adapter(true);
4862   if (sz == ngeo) return;
4863   // Shrinking the vector.
4864   if (sz < ngeo) {
4865     // Some elements may be out of line, must do so otherwise we don't
4866     // know how much to shrink in m_ptr.
4867     reassemble();
4868     size_t sublen = 0;
4869     for (size_t i = ngeo; i > sz; i--)
4870       sublen += (*m_geo_vect)[i - 1].get_nbytes();
4871 
4872     // '\0' not allowed in middle and no need for ending '\0' because it's
4873     // at the end of the original free chunk which is right after this chunk.
4874     memset((get_cptr() + get_nbytes() - sublen), 0xff, sublen);
4875     set_nbytes(get_nbytes() - sublen);
4876 
4877 #if !defined(DBUG_OFF)
4878     bool rsz_ret = m_geo_vect->resize(sz);
4879     DBUG_ASSERT(rsz_ret == false);
4880 #else
4881     m_geo_vect->resize(sz);
4882 #endif
4883     if (get_geotype() != Geometry::wkb_polygon_inner_rings) {
4884       DBUG_ASSERT(uint4korr(get_ucptr()) == ngeo);
4885       int4store(get_ucptr(), static_cast<uint32>(sz));
4886     }
4887     return;
4888   }
4889 
4890   char *ptr = nullptr, *ptr2 = nullptr;
4891 
4892   // We can store points directly into its owner, points are fixed length,
4893   // thus don't need its own memory.
4894   if (geotype == Geometry::wkb_linestring ||
4895       geotype == Geometry::wkb_multipoint) {
4896     size_t left = get_nbytes_free(),
4897            needed = (sz - ngeo) * (ptsz + (is_mpt ? WKB_HEADER_SIZE : 0)),
4898            nalloc, cap = get_nbytes();
4899 
4900     if (left <= needed) {
4901       nalloc = cap + 32 * (left + needed);
4902       ptr = get_cptr();
4903       m_ptr = gis_wkb_realloc(m_ptr, nalloc);
4904       if (m_ptr == nullptr) {
4905         set_nbytes(0);
4906         set_ownmem(0);
4907         clear_wkb_data();
4908         return;
4909       }
4910       ptr2 = get_cptr();
4911       memset((ptr2 + cap), 0xff, nalloc - cap);
4912       ptr2[nalloc - 1] = '\0';
4913       /*
4914         Only set when cap is 0, otherwise after this call get_nbytes_free()
4915         will work wrong, this is different from push_back because push_back
4916         always put data here more than 4 bytes inside itself.
4917       */
4918       if (cap == 0) int4store(get_ucptr(), 0);  // obj count
4919       set_ownmem(true);
4920 
4921       if (cap > 0 && ptr != m_ptr) {
4922         clear_wkb_data();
4923         // Note: flags_.nbytes doesn't change.
4924         parse_wkb_data(this, get_cptr());
4925       }
4926     }
4927     ptr2 = get_cptr();
4928     ptr = ptr2 + (cap ? cap : sizeof(uint32) /* obj count */);
4929     if (cap == 0) set_nbytes(sizeof(uint32));
4930   } else
4931     has_out_of_line_components(true);
4932 
4933   /*
4934     Because the pushed objects have their own memory, here we won't modify
4935     m_ptr memory at all.
4936   */
4937   for (size_t cnt = sz - ngeo; cnt; cnt--) {
4938     T tmp;
4939     tmp.set_owner(this);
4940     tmp.set_ownmem(false);
4941     // Points are directly put into owner's buffer, no need for own memory.
4942     if (tmp.get_geotype() == Geometry::wkb_point) {
4943       if (is_mpt) {
4944         ptr = write_wkb_header(ptr, Geometry::wkb_point);
4945         set_nbytes(get_nbytes() + WKB_HEADER_SIZE);
4946       }
4947       tmp.set_ptr(ptr, ptsz);
4948       set_nbytes(get_nbytes() + ptsz);
4949       ptr += ptsz;
4950       int4store(get_ucptr(), uint4korr(get_ucptr()) + 1);
4951       DBUG_ASSERT(uint4korr(get_ucptr()) == m_geo_vect->size() + 1);
4952     } else
4953       DBUG_ASSERT(ptr == nullptr && ptr2 == nullptr);
4954 
4955     shallow_push(&tmp);
4956     if (tmp.get_geotype() == Geometry::wkb_polygon)
4957       own_rings(&(m_geo_vect->back()));
4958 
4959     // tmp will be filled by push_back after this call, which will make
4960     // tmp own its own memory, different from other geos in m_geo_vect,
4961     // this is OK, users should call reassemble() to put them into
4962     // a single chunk of memory.
4963   }
4964 }
4965 
4966 // Explicit template instantiation
4967 /// @cond
4968 template void Gis_wkb_vector<Gis_line_string>::clear();
4969 template void Gis_wkb_vector<Gis_point>::clear();
4970 template void Gis_wkb_vector<Gis_polygon>::clear();
4971 template void Gis_wkb_vector<Gis_polygon_ring>::clear();
4972 
4973 template void Gis_wkb_vector<Gis_line_string>::push_back(
4974     Gis_line_string const &);
4975 template void Gis_wkb_vector<Gis_point>::push_back(Gis_point const &);
4976 template void Gis_wkb_vector<Gis_polygon>::push_back(Gis_polygon const &);
4977 template void Gis_wkb_vector<Gis_polygon_ring>::push_back(
4978     Gis_polygon_ring const &);
4979 
4980 template void Gis_wkb_vector<Gis_line_string>::reassemble();
4981 template void Gis_wkb_vector<Gis_polygon>::reassemble();
4982 
4983 template void Gis_wkb_vector<Gis_line_string>::resize(size_t);
4984 template void Gis_wkb_vector<Gis_point>::resize(size_t);
4985 template void Gis_wkb_vector<Gis_polygon>::resize(size_t);
4986 template void Gis_wkb_vector<Gis_polygon_ring>::resize(size_t);
4987 
4988 template Gis_wkb_vector<Gis_line_string>::Gis_wkb_vector(
4989     const void *, size_t, const Geometry::Flags_t &, gis::srid_t, bool);
4990 template Gis_wkb_vector<Gis_polygon>::Gis_wkb_vector(const void *, size_t,
4991                                                      const Geometry::Flags_t &,
4992                                                      gis::srid_t, bool);
4993 template Gis_wkb_vector<Gis_point>::Gis_wkb_vector(const void *, size_t,
4994                                                    const Geometry::Flags_t &,
4995                                                    gis::srid_t, bool);
4996 
4997 template Gis_wkb_vector<Gis_point> &Gis_wkb_vector<Gis_point>::operator=(
4998     Gis_wkb_vector<Gis_point> const &);
4999 
5000 template Gis_wkb_vector<Gis_point>::Gis_wkb_vector(
5001     Gis_wkb_vector<Gis_point> const &);
5002 template Gis_wkb_vector<Gis_polygon>::Gis_wkb_vector(
5003     const Gis_wkb_vector<Gis_polygon> &);
5004 /// @endcond
5005