1 #ifndef ITEM_GEOFUNC_INCLUDED
2 #define ITEM_GEOFUNC_INCLUDED
3 
4 /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License, version 2.0,
8    as published by the Free Software Foundation.
9 
10    This program is also distributed with certain software (including
11    but not limited to OpenSSL) that is licensed under separate terms,
12    as designated in a particular file or component or in included license
13    documentation.  The authors of MySQL hereby grant you an additional
14    permission to link the program and your derivative works with the
15    separately licensed software that they have included with MySQL.
16 
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License, version 2.0, for more details.
21 
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software Foundation,
24    51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
25 
26 
27 /* This file defines all spatial functions */
28 #include "inplace_vector.h"
29 #include "item_cmpfunc.h"      // Item_bool_func2
30 #include "prealloced_array.h"
31 #include "spatial.h"           // gis_wkb_raw_free
32 #include "item_strfunc.h"      // Item_str_func
33 #include "item_json_func.h"    // Item_json_func
34 
35 #include <vector>
36 
37 
38 /**
39    We have to hold result buffers in functions that return a GEOMETRY string,
40    because such a function's result geometry's buffer is directly used and
41    set to String result object. We have to release them properly manually
42    since they won't be released when the String result is destroyed.
43 */
44 class BG_result_buf_mgr
45 {
46   typedef Prealloced_array<void *, 64> Prealloced_buffers;
47 public:
BG_result_buf_mgr()48   BG_result_buf_mgr() :bg_result_buf(NULL), bg_results(PSI_INSTRUMENT_ME)
49   {
50   }
51 
~BG_result_buf_mgr()52   ~BG_result_buf_mgr()
53   {
54     free_intermediate_result_buffers();
55     free_result_buffer();
56   }
57 
add_buffer(void * buf)58   void add_buffer(void *buf)
59   {
60     bg_results.insert_unique(buf);
61   }
62 
63 
forget_buffer(void * buf)64   void forget_buffer(void *buf)
65   {
66     if (bg_result_buf == buf)
67       bg_result_buf= NULL;
68     bg_results.erase_unique(buf);
69   }
70 
71 
72   /* Free intermediate result buffers accumulated during GIS calculation. */
free_intermediate_result_buffers()73   void free_intermediate_result_buffers()
74   {
75     bg_results.erase_unique(bg_result_buf);
76     for (Prealloced_buffers::iterator itr= bg_results.begin();
77          itr != bg_results.end(); ++itr)
78       gis_wkb_raw_free(*itr);
79     bg_results.clear();
80   }
81 
82 
83   // Free the final result buffer, should be called after the result used.
free_result_buffer()84   void free_result_buffer()
85   {
86     gis_wkb_raw_free(bg_result_buf);
87     bg_result_buf= NULL;
88   }
89 
90 
set_result_buffer(void * buf)91   void set_result_buffer(void *buf)
92   {
93     bg_result_buf= buf;
94     bg_results.erase_unique(bg_result_buf);
95   }
96 
97 private:
98   /*
99     Hold data buffer of this set operation's final result geometry which is
100     freed next time val_str is called since it can be used by upper Item nodes.
101   */
102   void *bg_result_buf;
103 
104   /*
105     Result buffers for intermediate set operation results, which are freed
106     before val_str returns.
107   */
108   Prealloced_buffers bg_results;
109 };
110 
111 
112 class Item_func_spatial_operation;
113 
114 /**
115   A utility class to flatten any hierarchy of geometry collection into one
116   with no nested geometry collections. All components are stored separately
117   and all their data stored in this class, in order to easily manipulate them.
118  */
119 class BG_geometry_collection
120 {
121   bool comp_no_overlapped;
122   Geometry::srid_t m_srid;
123   size_t m_num_isolated;
124   std::vector<Geometry*> m_geos;
125   Inplace_vector<Geometry_buffer> m_geobufs;
126   Inplace_vector<String> m_geosdata;
127 public:
128   typedef std::vector<Geometry *> Geometry_list;
129 
BG_geometry_collection()130   BG_geometry_collection()
131     :comp_no_overlapped(false), m_srid(0), m_num_isolated(0),
132     m_geobufs(key_memory_Geometry_objects_data),
133     m_geosdata(key_memory_Geometry_objects_data)
134   {}
135 
is_comp_no_overlapped()136   bool is_comp_no_overlapped() const
137   {
138     return comp_no_overlapped;
139   }
140 
set_comp_no_overlapped(bool b)141   void set_comp_no_overlapped(bool b)
142   {
143     comp_no_overlapped= b;
144   }
145 
get_srid()146   Geometry::srid_t get_srid() const
147   {
148     return m_srid;
149   }
150 
set_srid(Geometry::srid_t srid)151   void set_srid(Geometry::srid_t srid)
152   {
153     m_srid= srid;
154   }
155 
156   bool fill(const Geometry *geo, bool break_multi_geom= false)
157   {
158     return store_geometry(geo, break_multi_geom);
159   }
160 
get_geometries()161   const Geometry_list &get_geometries() const
162   {
163     return m_geos;
164   }
165 
get_geometries()166   Geometry_list &get_geometries()
167   {
168     return m_geos;
169   }
170 
all_isolated()171   bool all_isolated() const
172   {
173     return m_num_isolated == m_geos.size();
174   }
175 
num_isolated()176   size_t num_isolated() const
177   {
178     return m_num_isolated;
179   }
180 
181   Gis_geometry_collection *as_geometry_collection(String *geodata) const;
182   template<typename Coordsys>
183   void merge_components(my_bool *pnull_value);
184 private:
185   template<typename Coordsys>
186   bool merge_one_run(Item_func_spatial_operation *ifso,
187                      my_bool *pnull_value);
188   bool store_geometry(const Geometry *geo, bool break_multi_geom);
189   Geometry *store(const Geometry *geo);
190 };
191 
192 
193 class Item_geometry_func: public Item_str_func
194 {
195 public:
Item_geometry_func()196   Item_geometry_func() :Item_str_func() {}
197 
Item_geometry_func(Item * a)198   Item_geometry_func(Item *a) :Item_str_func(a) {}
Item_geometry_func(const POS & pos,Item * a)199   Item_geometry_func(const POS &pos, Item *a) :Item_str_func(pos, a) {}
200 
Item_geometry_func(Item * a,Item * b)201   Item_geometry_func(Item *a,Item *b) :Item_str_func(a,b) {}
Item_geometry_func(const POS & pos,Item * a,Item * b)202   Item_geometry_func(const POS &pos, Item *a,Item *b) :Item_str_func(pos, a,b) {}
203 
Item_geometry_func(Item * a,Item * b,Item * c)204   Item_geometry_func(Item *a,Item *b,Item *c) :Item_str_func(a,b,c) {}
Item_geometry_func(const POS & pos,Item * a,Item * b,Item * c)205   Item_geometry_func(const POS &pos, Item *a, Item *b, Item *c)
206     :Item_str_func(pos, a, b, c)
207   {}
208   Item_geometry_func(const POS &pos, PT_item_list *list);
209 
210   void fix_length_and_dec();
field_type()211   enum_field_types field_type() const  { return MYSQL_TYPE_GEOMETRY; }
212   Field *tmp_table_field(TABLE *t_arg);
is_null()213   bool is_null() { (void) val_int(); return null_value; }
214 };
215 
216 class Item_func_geometry_from_text: public Item_geometry_func
217 {
218   typedef Item_geometry_func super;
219 public:
Item_func_geometry_from_text(const POS & pos,Item * a)220   Item_func_geometry_from_text(const POS &pos, Item *a)
221     :Item_geometry_func(pos, a)
222   {}
Item_func_geometry_from_text(const POS & pos,Item * a,Item * srid)223   Item_func_geometry_from_text(const POS &pos, Item *a, Item *srid)
224     :Item_geometry_func(pos, a, srid)
225   {}
226 
227   virtual bool itemize(Parse_context *pc, Item **res);
func_name()228   const char *func_name() const { return "st_geometryfromtext"; }
229   String *val_str(String *);
230 };
231 
232 class Item_func_geometry_from_wkb: public Item_geometry_func
233 {
234   typedef Item_geometry_func super;
235   String tmp_value;
236 public:
Item_func_geometry_from_wkb(const POS & pos,Item * a)237   Item_func_geometry_from_wkb(const POS &pos, Item *a)
238     : Item_geometry_func(pos, a)
239   {}
Item_func_geometry_from_wkb(const POS & pos,Item * a,Item * srid)240   Item_func_geometry_from_wkb(const POS &pos, Item *a, Item *srid):
241     Item_geometry_func(pos, a, srid)
242   {}
243 
244   virtual bool itemize(Parse_context *pc, Item **res);
func_name()245   const char *func_name() const { return "st_geometryfromwkb"; }
246   String *val_str(String *);
247 };
248 
249 class Item_func_as_wkt: public Item_str_ascii_func
250 {
251 public:
Item_func_as_wkt(const POS & pos,Item * a)252   Item_func_as_wkt(const POS &pos, Item *a): Item_str_ascii_func(pos, a) {}
func_name()253   const char *func_name() const { return "st_astext"; }
254   String *val_str_ascii(String *);
255   void fix_length_and_dec();
256 };
257 
258 class Item_func_as_wkb: public Item_geometry_func
259 {
260 public:
Item_func_as_wkb(const POS & pos,Item * a)261   Item_func_as_wkb(const POS &pos, Item *a): Item_geometry_func(pos, a) {}
func_name()262   const char *func_name() const { return "st_aswkb"; }
263   String *val_str(String *);
field_type()264   enum_field_types field_type() const  { return MYSQL_TYPE_BLOB; }
265 };
266 
267 class Item_func_geometry_type: public Item_str_ascii_func
268 {
269 public:
Item_func_geometry_type(const POS & pos,Item * a)270   Item_func_geometry_type(const POS &pos, Item *a): Item_str_ascii_func(pos, a)
271   {}
272   String *val_str_ascii(String *);
func_name()273   const char *func_name() const { return "st_geometrytype"; }
fix_length_and_dec()274   void fix_length_and_dec()
275   {
276     // "GeometryCollection" is the longest
277     fix_length_and_charset(20, default_charset());
278     maybe_null= 1;
279   };
280 };
281 
282 
283 /**
284   This handles one function:
285 
286     <geometry> = ST_GEOMFROMGEOJSON(<string>[, <options>[, <srid>]])
287 
288   Options is an integer argument which determines how positions with higher
289   coordinate dimension than MySQL support should be handled. The function will
290   accept both single objects, geometry collections and feature objects and
291   collections. All "properties" members of GeoJSON feature objects is ignored.
292 
293   The implementation conforms with GeoJSON revision 1.0 described at
294   http://geojson.org/geojson-spec.html.
295 */
296 class Item_func_geomfromgeojson : public Item_geometry_func
297 {
298 public:
299   /**
300     Describing how coordinate dimensions higher than supported in MySQL
301     should be handled.
302   */
303   enum enum_handle_coordinate_dimension
304   {
305     reject_document, strip_now_accept_future, strip_now_reject_future,
306     strip_now_strip_future
307   };
Item_func_geomfromgeojson(const POS & pos,Item * json_string)308   Item_func_geomfromgeojson(const POS &pos, Item *json_string)
309     :Item_geometry_func(pos, json_string),
310     m_handle_coordinate_dimension(reject_document), m_user_provided_srid(false),
311     m_srid_found_in_document(-1)
312   {}
Item_func_geomfromgeojson(const POS & pos,Item * json_string,Item * options)313   Item_func_geomfromgeojson(const POS &pos, Item *json_string, Item *options)
314     :Item_geometry_func(pos, json_string, options), m_user_provided_srid(false),
315     m_srid_found_in_document(-1)
316   {}
Item_func_geomfromgeojson(const POS & pos,Item * json_string,Item * options,Item * srid)317   Item_func_geomfromgeojson(const POS &pos, Item *json_string, Item *options,
318                             Item *srid)
319     :Item_geometry_func(pos, json_string, options, srid),
320     m_srid_found_in_document(-1)
321   {}
322   String *val_str(String *);
323   void fix_length_and_dec();
324   bool fix_fields(THD *, Item **ref);
func_name()325   const char *func_name() const { return "st_geomfromgeojson"; }
326   Geometry::wkbType get_wkbtype(const char *typestring);
327   bool get_positions(const Json_array *coordinates, Gis_point *point);
328   bool get_linestring(const Json_array *data_array,
329                       Gis_line_string *linestring);
330   bool get_polygon(const Json_array *data_array, Gis_polygon *polygon);
331   bool parse_object(const Json_object *object, bool *rollback,
332                     String *buffer, bool is_parent_featurecollection,
333                     Geometry **geometry);
334   bool parse_object_array(const Json_array *points,
335                           Geometry::wkbType type, bool *rollback,
336                           String *buffer, bool is_parent_featurecollection,
337                           Geometry **geometry);
338   static bool check_argument_valid_integer(Item *argument);
339   bool parse_crs_object(const Json_object *crs_object);
340   bool is_member_valid(const Json_dom *member, const char *member_name,
341                        Json_dom::enum_json_type expected_type, bool allow_null,
342                        bool *was_null);
343   const Json_dom *
344   my_find_member_ncase(const Json_object *object, const char *member_name);
345 
346   static const char *TYPE_MEMBER;
347   static const char *CRS_MEMBER;
348   static const char *GEOMETRY_MEMBER;
349   static const char *PROPERTIES_MEMBER;
350   static const char *FEATURES_MEMBER;
351   static const char *GEOMETRIES_MEMBER;
352   static const char *COORDINATES_MEMBER;
353   static const char *CRS_NAME_MEMBER;
354   static const char *NAMED_CRS;
355   static const char *SHORT_EPSG_PREFIX;
356   static const char *LONG_EPSG_PREFIX;
357   static const char *CRS84_URN;
358   static const char *POINT_TYPE;
359   static const char *MULTIPOINT_TYPE;
360   static const char *LINESTRING_TYPE;
361   static const char *MULTILINESTRING_TYPE;
362   static const char *POLYGON_TYPE;
363   static const char *MULTIPOLYGON_TYPE;
364   static const char *GEOMETRYCOLLECTION_TYPE;
365   static const char *FEATURE_TYPE;
366   static const char *FEATURECOLLECTION_TYPE;
367 private:
368   /**
369     How higher coordinate dimensions than currently supported should be handled.
370   */
371   enum_handle_coordinate_dimension m_handle_coordinate_dimension;
372   /// Is set to true if user provided a SRID as an argument.
373   bool m_user_provided_srid;
374   /// The SRID user provided as an argument.
375   Geometry::srid_t m_user_srid;
376   /**
377     The SRID value of the document CRS, if one is found. Otherwise, this value
378     defaults to -1.
379   */
380   longlong m_srid_found_in_document;
381 };
382 
383 
384 /// Max width of long CRS URN supported + max width of SRID + '\0'.
385 static const int MAX_CRS_WIDTH= (22 + MAX_INT_WIDTH + 1);
386 
387 /**
388   This class handles the following function:
389 
390   <json> = ST_ASGEOJSON(<geometry>[, <maxdecimaldigits>[, <options>]])
391 
392   It converts a GEOMETRY into a valid GeoJSON string. If maxdecimaldigits is
393   specified, the coordinates written are rounded to the number of decimals
394   specified (e.g with decimaldigits = 3: 10.12399 => 10.124).
395 
396   Options is a bitmask with the following flags:
397   0  No options (default values).
398   1  Add a bounding box to the output.
399   2  Add a short CRS URN to the output. The default format is a
400      short format ("EPSG:<srid>").
401   4  Add a long format CRS URN ("urn:ogc:def:crs:EPSG::<srid>"). This
402      implies 2. This means that, e.g., bitmask 5 and 7 mean the
403      same: add a bounding box and a long format CRS URN.
404 */
405 class Item_func_as_geojson :public Item_json_func
406 {
407 private:
408   /// Maximum number of decimal digits in printed coordinates.
409   int m_max_decimal_digits;
410   /// If true, the output GeoJSON has a bounding box for each GEOMETRY.
411   bool m_add_bounding_box;
412   /**
413     If true, the output GeoJSON has a CRS object in the short
414     form (e.g "EPSG:4326").
415   */
416   bool m_add_short_crs_urn;
417   /**
418     If true, the output GeoJSON has a CRS object in the long
419     form (e.g "urn:ogc:def:crs:EPSG::4326").
420   */
421   bool m_add_long_crs_urn;
422   /// The SRID found in the input GEOMETRY.
423   uint32 m_geometry_srid;
424 public:
Item_func_as_geojson(THD * thd,const POS & pos,Item * geometry)425   Item_func_as_geojson(THD *thd, const POS &pos, Item *geometry)
426     :Item_json_func(thd, pos, geometry), m_add_bounding_box(false),
427     m_add_short_crs_urn(false), m_add_long_crs_urn(false)
428   {}
Item_func_as_geojson(THD * thd,const POS & pos,Item * geometry,Item * maxdecimaldigits)429   Item_func_as_geojson(THD *thd, const POS &pos, Item *geometry, Item *maxdecimaldigits)
430     :Item_json_func(thd, pos, geometry, maxdecimaldigits),
431     m_add_bounding_box(false), m_add_short_crs_urn(false),
432     m_add_long_crs_urn(false)
433   {}
Item_func_as_geojson(THD * thd,const POS & pos,Item * geometry,Item * maxdecimaldigits,Item * options)434   Item_func_as_geojson(THD *thd, const POS &pos, Item *geometry, Item *maxdecimaldigits,
435                        Item *options)
436     :Item_json_func(thd, pos, geometry, maxdecimaldigits, options),
437     m_add_bounding_box(false), m_add_short_crs_urn(false),
438     m_add_long_crs_urn(false)
439   {}
440   bool fix_fields(THD *thd, Item **ref);
441   bool val_json(Json_wrapper *wr);
func_name()442   const char *func_name() const { return "st_asgeojson"; }
443   bool parse_options_argument();
444   bool parse_maxdecimaldigits_argument();
445 };
446 
447 
448 class Item_func_centroid: public Item_geometry_func
449 {
450   BG_result_buf_mgr bg_resbuf_mgr;
451 
452   template <typename Coordsys>
453   bool bg_centroid(const Geometry *geom, String *ptwkb);
454 public:
Item_func_centroid(const POS & pos,Item * a)455   Item_func_centroid(const POS &pos, Item *a): Item_geometry_func(pos, a) {}
func_name()456   const char *func_name() const { return "st_centroid"; }
457   String *val_str(String *);
458   Field::geometry_type get_geometry_type() const;
459 };
460 
461 class Item_func_convex_hull: public Item_geometry_func
462 {
463   BG_result_buf_mgr bg_resbuf_mgr;
464 
465   template <typename Coordsys>
466   bool bg_convex_hull(const Geometry *geom, String *wkb);
467 public:
Item_func_convex_hull(const POS & pos,Item * a)468   Item_func_convex_hull(const POS &pos, Item *a): Item_geometry_func(pos, a) {}
func_name()469   const char *func_name() const { return "st_convexhull"; }
470   String *val_str(String *);
471   Field::geometry_type get_geometry_type() const;
472 };
473 
474 class Item_func_envelope: public Item_geometry_func
475 {
476 public:
Item_func_envelope(const POS & pos,Item * a)477   Item_func_envelope(const POS &pos, Item *a): Item_geometry_func(pos, a) {}
func_name()478   const char *func_name() const { return "st_envelope"; }
479   String *val_str(String *);
480   Field::geometry_type get_geometry_type() const;
481 };
482 
483 class Item_func_make_envelope: public Item_geometry_func
484 {
485 public:
Item_func_make_envelope(const POS & pos,Item * a,Item * b)486   Item_func_make_envelope(const POS &pos, Item *a, Item *b)
487     : Item_geometry_func(pos, a, b) {}
func_name()488   const char *func_name() const { return "st_makeenvelope"; }
489   String *val_str(String *);
490   Field::geometry_type get_geometry_type() const;
491 };
492 
493 class Item_func_validate: public Item_geometry_func
494 {
495   String arg_val;
496 public:
Item_func_validate(const POS & pos,Item * a)497   Item_func_validate(const POS &pos, Item *a): Item_geometry_func(pos, a) {}
func_name()498   const char *func_name() const { return "st_validate"; }
499   String *val_str(String *);
500 };
501 
502 class Item_func_simplify: public Item_geometry_func
503 {
504   BG_result_buf_mgr bg_resbuf_mgr;
505   String arg_val;
506   template <typename Coordsys>
507   int simplify_basic(Geometry *geom, double max_dist, String *str,
508                      Gis_geometry_collection *gc= NULL,
509                      String *gcbuf= NULL);
510 public:
Item_func_simplify(const POS & pos,Item * a,Item * b)511   Item_func_simplify(const POS &pos, Item *a, Item *b)
512     : Item_geometry_func(pos, a, b) {}
func_name()513   const char *func_name() const { return "st_simplify"; }
514   String *val_str(String *);
515 };
516 
517 class Item_func_point: public Item_geometry_func
518 {
519 public:
Item_func_point(const POS & pos,Item * a,Item * b)520   Item_func_point(const POS &pos, Item *a, Item *b)
521     : Item_geometry_func(pos, a, b)
522   {}
func_name()523   const char *func_name() const { return "point"; }
524   String *val_str(String *);
525   Field::geometry_type get_geometry_type() const;
526 };
527 
528 
529 /**
530   This handles the <point> = ST_POINTFROMGEOHASH(<string>, <srid>) funtion.
531 
532   It returns a point containing the decoded geohash value, where X is the
533   longitude in the range of [-180, 180] and Y is the latitude in the range
534   of [-90, 90].
535 
536   At the moment, SRID can be any 32 bit unsigned integer.
537 */
538 class Item_func_pointfromgeohash : public Item_geometry_func
539 {
540 private:
541   /// The maximum output latitude value when decoding the geohash value.
542   const double upper_latitude;
543 
544   /// The minimum output latitude value when decoding the geohash value.
545   const double lower_latitude;
546 
547   /// The maximum output longitude value when decoding the geohash value.
548   const double upper_longitude;
549 
550   /// The minimum output longitude value when decoding the geohash value.
551   const double lower_longitude;
552 public:
Item_func_pointfromgeohash(const POS & pos,Item * a,Item * b)553   Item_func_pointfromgeohash(const POS &pos, Item *a, Item *b)
554     : Item_geometry_func(pos, a, b),
555     upper_latitude(90.0), lower_latitude(-90.0),
556     upper_longitude(180.0), lower_longitude(-180.0)
557   {}
func_name()558   const char *func_name() const { return "st_pointfromgeohash"; }
559   String *val_str(String *);
560   bool fix_fields(THD *thd, Item **ref);
get_geometry_type()561   Field::geometry_type get_geometry_type() const
562   {
563     return Field::GEOM_POINT;
564   };
565 };
566 
567 
568 class Item_func_spatial_decomp: public Item_geometry_func
569 {
570   enum Functype decomp_func;
571 public:
Item_func_spatial_decomp(const POS & pos,Item * a,Item_func::Functype ft)572   Item_func_spatial_decomp(const POS &pos, Item *a, Item_func::Functype ft) :
573     Item_geometry_func(pos, a)
574   { decomp_func = ft; }
func_name()575   const char *func_name() const
576   {
577     switch (decomp_func)
578     {
579       case SP_STARTPOINT:
580         return "st_startpoint";
581       case SP_ENDPOINT:
582         return "st_endpoint";
583       case SP_EXTERIORRING:
584         return "st_exteriorring";
585       default:
586 	DBUG_ASSERT(0);  // Should never happened
587         return "spatial_decomp_unknown";
588     }
589   }
590   String *val_str(String *);
591 };
592 
593 class Item_func_spatial_decomp_n: public Item_geometry_func
594 {
595   enum Functype decomp_func_n;
596 public:
Item_func_spatial_decomp_n(const POS & pos,Item * a,Item * b,Item_func::Functype ft)597   Item_func_spatial_decomp_n(const POS &pos, Item *a, Item *b, Item_func::Functype ft):
598     Item_geometry_func(pos, a, b)
599   { decomp_func_n = ft; }
func_name()600   const char *func_name() const
601   {
602     switch (decomp_func_n)
603     {
604       case SP_POINTN:
605         return "st_pointn";
606       case SP_GEOMETRYN:
607         return "st_geometryn";
608       case SP_INTERIORRINGN:
609         return "st_interiorringn";
610       default:
611 	DBUG_ASSERT(0);  // Should never happened
612         return "spatial_decomp_n_unknown";
613     }
614   }
615   String *val_str(String *);
616 };
617 
618 class Item_func_spatial_collection: public Item_geometry_func
619 {
620   String tmp_value;
621   enum Geometry::wkbType coll_type;
622   enum Geometry::wkbType item_type;
623 public:
Item_func_spatial_collection(const POS & pos,PT_item_list * list,enum Geometry::wkbType ct,enum Geometry::wkbType it)624   Item_func_spatial_collection(const POS &pos,
625      PT_item_list *list, enum Geometry::wkbType ct, enum Geometry::wkbType it):
626   Item_geometry_func(pos, list)
627   {
628     coll_type=ct;
629     item_type=it;
630   }
631   String *val_str(String *);
fix_length_and_dec()632   void fix_length_and_dec()
633   {
634     Item_geometry_func::fix_length_and_dec();
635     for (unsigned int i= 0; i < arg_count; ++i)
636     {
637       if (args[i]->fixed && args[i]->field_type() != MYSQL_TYPE_GEOMETRY)
638       {
639         String str;
640         args[i]->print(&str, QT_NO_DATA_EXPANSION);
641         str.append('\0');
642         my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "non geometric",
643                  str.ptr());
644       }
645     }
646   }
647 
648   const char *func_name() const;
649 };
650 
651 
652 /*
653   Spatial relations
654 */
655 
656 class Item_func_spatial_mbr_rel: public Item_bool_func2
657 {
658   enum Functype spatial_rel;
659 public:
Item_func_spatial_mbr_rel(Item * a,Item * b,enum Functype sp_rel)660   Item_func_spatial_mbr_rel(Item *a, Item *b, enum Functype sp_rel) :
661     Item_bool_func2(a, b) { spatial_rel = sp_rel; }
Item_func_spatial_mbr_rel(const POS & pos,Item * a,Item * b,enum Functype sp_rel)662   Item_func_spatial_mbr_rel(const POS &pos, Item *a, Item *b,
663                             enum Functype sp_rel)
664   : Item_bool_func2(pos, a, b) { spatial_rel = sp_rel; }
665   longlong val_int();
functype()666   enum Functype functype() const
667   {
668     return spatial_rel;
669   }
rev_functype()670   enum Functype rev_functype() const
671   {
672     switch (spatial_rel)
673     {
674       case SP_CONTAINS_FUNC:
675         return SP_WITHIN_FUNC;
676       case SP_WITHIN_FUNC:
677         return SP_CONTAINS_FUNC;
678       default:
679         return spatial_rel;
680     }
681   }
682 
683   const char *func_name() const;
print(String * str,enum_query_type query_type)684   virtual inline void print(String *str, enum_query_type query_type)
685   {
686     Item_func::print(str, query_type);
687   }
fix_length_and_dec()688   void fix_length_and_dec() { maybe_null= 1; }
is_null()689   bool is_null() { (void) val_int(); return null_value; }
690 };
691 
692 
693 class Item_func_spatial_rel: public Item_bool_func2
694 {
695   enum Functype spatial_rel;
696   String tmp_value1,tmp_value2;
697 public:
698   Item_func_spatial_rel(const POS &pos, Item *a,Item *b, enum Functype sp_rel);
699   virtual ~Item_func_spatial_rel();
700   longlong val_int();
functype()701   enum Functype functype() const
702   {
703     return spatial_rel;
704   }
rev_functype()705   enum Functype rev_functype() const
706   {
707     switch (spatial_rel)
708     {
709       case SP_CONTAINS_FUNC:
710         return SP_WITHIN_FUNC;
711       case SP_WITHIN_FUNC:
712         return SP_CONTAINS_FUNC;
713       default:
714         return spatial_rel;
715     }
716   }
717 
718   const char *func_name() const;
print(String * str,enum_query_type query_type)719   virtual inline void print(String *str, enum_query_type query_type)
720   {
721     Item_func::print(str, query_type);
722   }
723 
fix_length_and_dec()724   void fix_length_and_dec() { maybe_null= 1; }
is_null()725   bool is_null() { (void) val_int(); return null_value; }
726 
727   template<typename CoordinateSystemType>
728   static int bg_geo_relation_check(Geometry *g1, Geometry *g2,
729                                    Functype relchk_type, my_bool *);
730 
731 protected:
732 
733   template<typename Geom_types>
734   friend class BG_wrap;
735 
736   template<typename Geotypes>
737   static int within_check(Geometry *g1, Geometry *g2,
738                           my_bool *pnull_value);
739   template<typename Geotypes>
740   static int equals_check(Geometry *g1, Geometry *g2,
741                           my_bool *pnull_value);
742   template<typename Geotypes>
743   static int disjoint_check(Geometry *g1, Geometry *g2,
744                             my_bool *pnull_value);
745   template<typename Geotypes>
746   static int intersects_check(Geometry *g1, Geometry *g2,
747                               my_bool *pnull_value);
748   template<typename Geotypes>
749   static int overlaps_check(Geometry *g1, Geometry *g2,
750                             my_bool *pnull_value);
751   template<typename Geotypes>
752   static int touches_check(Geometry *g1, Geometry *g2,
753                            my_bool *pnull_value);
754   template<typename Geotypes>
755   static int crosses_check(Geometry *g1, Geometry *g2,
756                            my_bool *pnull_value);
757 
758   template<typename Coordsys>
759   int multipoint_within_geometry_collection(Gis_multi_point *mpts,
760                                             const typename
761                                             BG_geometry_collection::
762                                             Geometry_list *gv2,
763                                             const void *prtree);
764 
765   template<typename Coordsys>
766   int geocol_relation_check(Geometry *g1, Geometry *g2);
767   template<typename Coordsys>
768   int geocol_relcheck_intersect_disjoint(const typename BG_geometry_collection::
769                                          Geometry_list *gv1,
770                                          const typename BG_geometry_collection::
771                                          Geometry_list *gv2);
772   template<typename Coordsys>
773   int geocol_relcheck_within(const typename BG_geometry_collection::
774                              Geometry_list *gv1,
775                              const typename BG_geometry_collection::
776                              Geometry_list *gv2);
777   template<typename Coordsys>
778   int geocol_equals_check(const typename BG_geometry_collection::
779                           Geometry_list *gv1,
780                           const typename BG_geometry_collection::
781                           Geometry_list *gv2);
782 };
783 
784 
785 /*
786   Spatial operations
787 */
788 
789 class Item_func_spatial_operation: public Item_geometry_func
790 {
791 protected:
792   // It will call the protected member functions in this class,
793   // no data member accessed directly.
794   template<typename Geotypes>
795   friend class BG_setop_wrapper;
796 
797   // Calls bg_geo_set_op.
798   friend class BG_geometry_collection;
799 
800   template<typename Coordsys>
801   Geometry *bg_geo_set_op(Geometry *g1, Geometry *g2, String *result);
802 
803   template<typename Coordsys>
804   Geometry *combine_sub_results(Geometry *g1, Geometry *g2, String *result);
805   Geometry *simplify_multilinestring(Gis_multi_line_string *mls,
806                                      String *result);
807 
808   template<typename Coordsys>
809   Geometry *geometry_collection_set_operation(Geometry *g1, Geometry *g2,
810                                               String *result);
811 
812   Geometry *empty_result(String *str, uint32 srid);
813 
814   String tmp_value1,tmp_value2;
815   BG_result_buf_mgr bg_resbuf_mgr;
816 
817   bool assign_result(Geometry *geo, String *result);
818 
819   template <typename Geotypes>
820   Geometry *intersection_operation(Geometry *g1, Geometry *g2, String *result);
821   template <typename Geotypes>
822   Geometry *union_operation(Geometry *g1, Geometry *g2, String *result);
823   template <typename Geotypes>
824   Geometry *difference_operation(Geometry *g1, Geometry *g2, String *result);
825   template <typename Geotypes>
826   Geometry *symdifference_operation(Geometry *g1, Geometry *g2, String *result);
827   template<typename Coordsys>
828   Geometry *geocol_symdifference(const BG_geometry_collection &bggc1,
829                                  const BG_geometry_collection &bggc2,
830                                  String *result);
831   template<typename Coordsys>
832   Geometry *geocol_difference(const BG_geometry_collection &bggc1,
833                               const BG_geometry_collection &bggc2,
834                               String *result);
835   template<typename Coordsys>
836   Geometry *geocol_intersection(const BG_geometry_collection &bggc1,
837                                 const BG_geometry_collection &bggc2,
838                                 String *result);
839   template<typename Coordsys>
840   Geometry *geocol_union(const BG_geometry_collection &bggc1,
841                          const BG_geometry_collection &bggc2,
842                          String *result);
843 public:
844   enum op_type
845   {
846     op_shape= 0,
847     op_not= 0x80000000,
848     op_union= 0x10000000,
849     op_intersection= 0x20000000,
850     op_symdifference= 0x30000000,
851     op_difference= 0x40000000,
852     op_backdifference= 0x50000000,
853     op_any= 0x70000000
854   };
855 
Item_func_spatial_operation(const POS & pos,Item * a,Item * b,Item_func_spatial_operation::op_type sp_op)856   Item_func_spatial_operation(const POS &pos, Item *a, Item *b,
857                               Item_func_spatial_operation::op_type sp_op) :
858     Item_geometry_func(pos, a, b), spatial_op(sp_op)
859   {
860   }
861   virtual ~Item_func_spatial_operation();
862   String *val_str(String *);
863   const char *func_name() const;
print(String * str,enum_query_type query_type)864   virtual inline void print(String *str, enum_query_type query_type)
865   {
866     Item_func::print(str, query_type);
867   }
868 private:
869   op_type spatial_op;
870   String m_result_buffer;
871 };
872 
873 
874 class Item_func_buffer: public Item_geometry_func
875 {
876 public:
877   /*
878     There are five types of buffer strategies, this is an enumeration of them.
879    */
880   enum enum_buffer_strategy_types
881   {
882     invalid_strategy_type= 0,
883     end_strategy,
884     join_strategy,
885     point_strategy,
886     // The two below are not parameterized.
887     distance_strategy,
888     side_strategy
889   };
890 
891   /*
892     For each type of strategy listed above, there are several options/values
893     for it, this is an enumeration of all such options/values for all types of
894     strategies.
895    */
896   enum enum_buffer_strategies
897   {
898     invalid_strategy= 0,
899     end_round,
900     end_flat,
901     join_round,
902     join_miter,
903     point_circle,
904     point_square,
905     max_strategy= point_square
906 
907     // Distance and side strategies are fixed, so no need to implement
908     // parameterization for them.
909   };
910 
911   /*
912     A piece of strategy setting. User can specify 0 to 3 different strategy
913     settings in any order to ST_Buffer(), which must be of different
914     strategy types. Default strategies are used if not explicitly specified.
915    */
916   struct Strategy_setting
917   {
918     enum_buffer_strategies strategy;
919     // This field is only effective for end_round, join_round, join_mit,
920     // and point_circle.
921     double value;
922   };
923 
924 private:
925   BG_result_buf_mgr bg_resbuf_mgr;
926   int num_strats;
927   String *strategies[side_strategy + 1];
928   /*
929     end_xxx stored in settings[end_strategy];
930     join_xxx stored in settings[join_strategy];
931     point_xxx stored in settings[point_strategy].
932   */
933   Strategy_setting settings[side_strategy + 1];
934   String tmp_value;                             // Stores current buffer result.
935   String m_tmp_geombuf;
936   void set_strategies();
937 public:
938   Item_func_buffer(const POS &pos, PT_item_list *ilist);
func_name()939   const char *func_name() const { return "st_buffer"; }
940   String *val_str(String *);
941 };
942 
943 
944 class Item_func_buffer_strategy: public Item_str_func
945 {
946 private:
947   friend class Item_func_buffer;
948   String tmp_value;
949   char tmp_buffer[16];                          // The buffer for tmp_value.
950 public:
951   Item_func_buffer_strategy(const POS &pos, PT_item_list *ilist);
func_name()952   const char *func_name() const { return "st_buffer_strategy"; }
953   String *val_str(String *);
954   void fix_length_and_dec();
955 };
956 
957 
958 class Item_func_isempty: public Item_bool_func
959 {
960 public:
Item_func_isempty(const POS & pos,Item * a)961   Item_func_isempty(const POS &pos, Item *a): Item_bool_func(pos, a) {}
962   longlong val_int();
select_optimize()963   optimize_type select_optimize() const { return OPTIMIZE_NONE; }
func_name()964   const char *func_name() const { return "st_isempty"; }
fix_length_and_dec()965   void fix_length_and_dec() { maybe_null= 1; }
966 };
967 
968 class Item_func_issimple: public Item_bool_func
969 {
970   String tmp;
971 public:
Item_func_issimple(const POS & pos,Item * a)972   Item_func_issimple(const POS &pos, Item *a): Item_bool_func(pos, a) {}
973   longlong val_int();
974   bool issimple(Geometry *g);
select_optimize()975   optimize_type select_optimize() const { return OPTIMIZE_NONE; }
func_name()976   const char *func_name() const { return "st_issimple"; }
fix_length_and_dec()977   void fix_length_and_dec() { maybe_null= 1; }
978 };
979 
980 class Item_func_isclosed: public Item_bool_func
981 {
982 public:
Item_func_isclosed(const POS & pos,Item * a)983   Item_func_isclosed(const POS &pos, Item *a): Item_bool_func(pos, a) {}
984   longlong val_int();
select_optimize()985   optimize_type select_optimize() const { return OPTIMIZE_NONE; }
func_name()986   const char *func_name() const { return "st_isclosed"; }
fix_length_and_dec()987   void fix_length_and_dec() { maybe_null= 1; }
988 };
989 
990 class Item_func_isvalid: public Item_bool_func
991 {
992 public:
Item_func_isvalid(const POS & pos,Item * a)993   Item_func_isvalid(const POS &pos, Item *a): Item_bool_func(pos, a) {}
994   longlong val_int();
select_optimize()995   optimize_type select_optimize() const { return OPTIMIZE_NONE; }
func_name()996   const char *func_name() const { return "st_isvalid"; }
997 };
998 
999 class Item_func_dimension: public Item_int_func
1000 {
1001   String value;
1002 public:
Item_func_dimension(const POS & pos,Item * a)1003   Item_func_dimension(const POS &pos, Item *a): Item_int_func(pos, a) {}
1004   longlong val_int();
func_name()1005   const char *func_name() const { return "st_dimension"; }
fix_length_and_dec()1006   void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
1007 };
1008 
1009 class Item_func_x: public Item_real_func
1010 {
1011   String value;
1012 public:
Item_func_x(const POS & pos,Item * a)1013   Item_func_x(const POS &pos, Item *a): Item_real_func(pos, a) {}
1014   double val_real();
func_name()1015   const char *func_name() const { return "st_x"; }
fix_length_and_dec()1016   void fix_length_and_dec()
1017   {
1018     Item_real_func::fix_length_and_dec();
1019     maybe_null= 1;
1020   }
1021 };
1022 
1023 
1024 class Item_func_y: public Item_real_func
1025 {
1026   String value;
1027 public:
Item_func_y(const POS & pos,Item * a)1028   Item_func_y(const POS &pos, Item *a): Item_real_func(pos, a) {}
1029   double val_real();
func_name()1030   const char *func_name() const { return "st_y"; }
fix_length_and_dec()1031   void fix_length_and_dec()
1032   {
1033     Item_real_func::fix_length_and_dec();
1034     maybe_null= 1;
1035   }
1036 };
1037 
1038 
1039 class Item_func_numgeometries: public Item_int_func
1040 {
1041   String value;
1042 public:
Item_func_numgeometries(const POS & pos,Item * a)1043   Item_func_numgeometries(const POS &pos, Item *a): Item_int_func(pos, a) {}
1044   longlong val_int();
func_name()1045   const char *func_name() const { return "st_numgeometries"; }
fix_length_and_dec()1046   void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
1047 };
1048 
1049 
1050 class Item_func_numinteriorring: public Item_int_func
1051 {
1052   String value;
1053 public:
Item_func_numinteriorring(const POS & pos,Item * a)1054   Item_func_numinteriorring(const POS &pos, Item *a): Item_int_func(pos, a) {}
1055   longlong val_int();
func_name()1056   const char *func_name() const { return "st_numinteriorrings"; }
fix_length_and_dec()1057   void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
1058 };
1059 
1060 
1061 class Item_func_numpoints: public Item_int_func
1062 {
1063   String value;
1064 public:
Item_func_numpoints(const POS & pos,Item * a)1065   Item_func_numpoints(const POS &pos, Item *a): Item_int_func(pos, a) {}
1066   longlong val_int();
func_name()1067   const char *func_name() const { return "st_numpoints"; }
fix_length_and_dec()1068   void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
1069 };
1070 
1071 
1072 class Item_func_area: public Item_real_func
1073 {
1074   String value;
1075 
1076   template <typename Coordsys>
1077   double bg_area(const Geometry *geom);
1078 public:
Item_func_area(const POS & pos,Item * a)1079   Item_func_area(const POS &pos, Item *a): Item_real_func(pos, a) {}
1080   double val_real();
func_name()1081   const char *func_name() const { return "st_area"; }
fix_length_and_dec()1082   void fix_length_and_dec()
1083   {
1084     Item_real_func::fix_length_and_dec();
1085     maybe_null= 1;
1086   }
1087 };
1088 
1089 
1090 class Item_func_glength: public Item_real_func
1091 {
1092   String value;
1093 public:
Item_func_glength(const POS & pos,Item * a)1094   Item_func_glength(const POS &pos, Item *a): Item_real_func(pos, a) {}
1095   double val_real();
func_name()1096   const char *func_name() const { return "st_length"; }
fix_length_and_dec()1097   void fix_length_and_dec()
1098   {
1099     Item_real_func::fix_length_and_dec();
1100     maybe_null= 1;
1101   }
1102 };
1103 
1104 
1105 class Item_func_srid: public Item_int_func
1106 {
1107   String value;
1108 public:
Item_func_srid(const POS & pos,Item * a)1109   Item_func_srid(const POS &pos, Item *a): Item_int_func(pos, a) {}
1110   longlong val_int();
func_name()1111   const char *func_name() const { return "st_srid"; }
fix_length_and_dec()1112   void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
1113 };
1114 
1115 
1116 class Item_func_distance: public Item_real_func
1117 {
1118   // Default earth radius in meters.
1119   bool is_spherical_equatorial;
1120   double earth_radius;
1121   String tmp_value1;
1122   String tmp_value2;
1123 
1124   double geometry_collection_distance(const Geometry *g1, const Geometry *g2);
1125 
1126   template <typename Coordsys, typename BG_geometry>
1127   double distance_dispatch_second_geometry(const BG_geometry& bg1,
1128                                            const Geometry* g2);
1129 
1130   double distance_point_geometry_spherical(const Geometry *g1,
1131                                            const Geometry *g2);
1132   double distance_multipoint_geometry_spherical(const Geometry *g1,
1133                                                 const Geometry *g2);
1134 public:
1135   double bg_distance_spherical(const Geometry *g1, const Geometry *g2);
1136   template <typename Coordsys>
1137   double bg_distance(const Geometry *g1, const Geometry *g2);
1138 
Item_func_distance(const POS & pos,PT_item_list * ilist,bool isspherical)1139   Item_func_distance(const POS &pos, PT_item_list *ilist, bool isspherical)
1140     : Item_real_func(pos, ilist), is_spherical_equatorial(isspherical),
1141       earth_radius(6370986.0)                   /* Default earth radius. */
1142   {
1143     /*
1144       Either operand can be an empty geometry collection, and it's meaningless
1145       for a distance between them.
1146     */
1147     maybe_null= true;
1148   }
1149 
fix_length_and_dec()1150   void fix_length_and_dec()
1151   {
1152     Item_real_func::fix_length_and_dec();
1153     maybe_null= true;
1154   }
1155 
1156   double val_real();
func_name()1157   const char *func_name() const
1158   {
1159     return is_spherical_equatorial ? "st_distance_sphere" : "st_distance";
1160   }
1161 };
1162 
1163 
1164 #endif /*ITEM_GEOFUNC_INCLUDED*/
1165