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