1 /* Copyright (c) 2003, 2016, Oracle and/or its affiliates.
2 Copyright (c) 2011, 2020, MariaDB
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 as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
16
17
18 /**
19 @file
20
21 @brief
22 This file defines all spatial functions
23 */
24
25 #ifdef USE_PRAGMA_IMPLEMENTATION
26 #pragma implementation // gcc: Class implementation
27 #endif
28
29 #include "mariadb.h"
30 #include "sql_priv.h"
31 /*
32 It is necessary to include set_var.h instead of item.h because there
33 are dependencies on include order for set_var.h and item.h. This
34 will be resolved later.
35 */
36 #include "sql_class.h" // THD, set_var.h: THD
37 #include "set_var.h"
38 #ifdef HAVE_SPATIAL
39 #include <m_ctype.h>
40 #include "opt_range.h"
41
42
fix_length_and_dec()43 bool Item_geometry_func::fix_length_and_dec()
44 {
45 collation.set(&my_charset_bin);
46 decimals=0;
47 max_length= (uint32) UINT_MAX32;
48 maybe_null= 1;
49 return FALSE;
50 }
51
52
val_str(String * str)53 String *Item_func_geometry_from_text::val_str(String *str)
54 {
55 DBUG_ASSERT(fixed == 1);
56 Geometry_buffer buffer;
57 String arg_val;
58 String *wkt= args[0]->val_str_ascii(&arg_val);
59
60 if ((null_value= args[0]->null_value))
61 return 0;
62
63 Gis_read_stream trs(wkt->charset(), wkt->ptr(), wkt->length());
64 uint32 srid= 0;
65
66 if ((arg_count == 2) && !args[1]->null_value)
67 srid= (uint32)args[1]->val_int();
68
69 str->set_charset(&my_charset_bin);
70 str->length(0);
71 if (str->reserve(SRID_SIZE, 512))
72 return 0;
73 str->q_append(srid);
74 if ((null_value= !Geometry::create_from_wkt(&buffer, &trs, str, 0)))
75 return 0;
76 return str;
77 }
78
79
val_str(String * str)80 String *Item_func_geometry_from_wkb::val_str(String *str)
81 {
82 DBUG_ASSERT(fixed == 1);
83 String arg_val;
84 String *wkb;
85 Geometry_buffer buffer;
86 uint32 srid= 0;
87
88 if (args[0]->field_type() == MYSQL_TYPE_GEOMETRY)
89 {
90 String *str_ret= args[0]->val_str(str);
91 null_value= args[0]->null_value;
92 return str_ret;
93 }
94
95 wkb= args[0]->val_str(&arg_val);
96
97 if ((arg_count == 2) && !args[1]->null_value)
98 srid= (uint32)args[1]->val_int();
99
100 str->set_charset(&my_charset_bin);
101 if (str->reserve(SRID_SIZE, 512))
102 {
103 null_value= TRUE; /* purecov: inspected */
104 return 0; /* purecov: inspected */
105 }
106 str->length(0);
107 str->q_append(srid);
108 if ((null_value=
109 (args[0]->null_value ||
110 !Geometry::create_from_wkb(&buffer, wkb->ptr(), wkb->length(), str))))
111 return 0;
112 return str;
113 }
114
115
116 void report_json_error_ex(String *js, json_engine_t *je,
117 const char *fname, int n_param,
118 Sql_condition::enum_warning_level lv);
119
val_str(String * str)120 String *Item_func_geometry_from_json::val_str(String *str)
121 {
122 DBUG_ASSERT(fixed == 1);
123 Geometry_buffer buffer;
124 String *js= args[0]->val_str_ascii(&tmp_js);
125 uint32 srid= 0;
126 longlong options= 0;
127 json_engine_t je;
128
129 if ((null_value= args[0]->null_value))
130 return 0;
131
132 if (arg_count > 1 && !args[1]->null_value)
133 {
134 options= args[1]->val_int();
135 if (options > 4 || options < 1)
136 {
137 String *sv= args[1]->val_str(&tmp_js);
138 my_error(ER_WRONG_VALUE_FOR_TYPE, MYF(0),
139 "option", sv->c_ptr_safe(), "ST_GeomFromGeoJSON");
140 null_value= 1;
141 return 0;
142 }
143 }
144
145 if ((arg_count == 3) && !args[2]->null_value)
146 srid= (uint32)args[2]->val_int();
147
148 str->set_charset(&my_charset_bin);
149 if (str->reserve(SRID_SIZE, 512))
150 return 0;
151 str->length(0);
152 str->q_append(srid);
153
154 json_scan_start(&je, js->charset(), (const uchar *) js->ptr(),
155 (const uchar *) js->end());
156
157 if ((null_value= !Geometry::create_from_json(&buffer, &je, options==1, str)))
158 {
159 int code= 0;
160
161 switch (je.s.error)
162 {
163 case Geometry::GEOJ_INCORRECT_GEOJSON:
164 code= ER_GEOJSON_INCORRECT;
165 break;
166 case Geometry::GEOJ_TOO_FEW_POINTS:
167 code= ER_GEOJSON_TOO_FEW_POINTS;
168 break;
169 case Geometry::GEOJ_EMPTY_COORDINATES:
170 code= ER_GEOJSON_EMPTY_COORDINATES;
171 break;
172 case Geometry::GEOJ_POLYGON_NOT_CLOSED:
173 code= ER_GEOJSON_NOT_CLOSED;
174 break;
175 case Geometry::GEOJ_DIMENSION_NOT_SUPPORTED:
176 my_error(ER_GIS_INVALID_DATA, MYF(0), "ST_GeomFromGeoJSON");
177 break;
178 default:
179 report_json_error_ex(js, &je, func_name(), 0, Sql_condition::WARN_LEVEL_WARN);
180 return NULL;
181 }
182
183 if (code)
184 {
185 THD *thd= current_thd;
186 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, code,
187 ER_THD(thd, code));
188 }
189 return 0;
190 }
191 return str;
192 }
193
194
val_str_ascii(String * str)195 String *Item_func_as_wkt::val_str_ascii(String *str)
196 {
197 DBUG_ASSERT(fixed == 1);
198 String arg_val;
199 String *swkb= args[0]->val_str(&arg_val);
200 Geometry_buffer buffer;
201 Geometry *geom= NULL;
202 const char *dummy;
203
204 if ((null_value=
205 (args[0]->null_value ||
206 !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
207 return 0;
208
209 str->length(0);
210 str->set_charset(&my_charset_latin1);
211 if ((null_value= geom->as_wkt(str, &dummy)))
212 return 0;
213
214 return str;
215 }
216
217
fix_length_and_dec()218 bool Item_func_as_wkt::fix_length_and_dec()
219 {
220 collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
221 max_length= (uint32) UINT_MAX32;
222 maybe_null= 1;
223 return FALSE;
224 }
225
226
val_str(String * str)227 String *Item_func_as_wkb::val_str(String *str)
228 {
229 DBUG_ASSERT(fixed == 1);
230 String arg_val;
231 String *swkb= args[0]->val_str(&arg_val);
232 Geometry_buffer buffer;
233
234 if ((null_value=
235 (args[0]->null_value ||
236 !(Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
237 return 0;
238
239 str->copy(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE,
240 &my_charset_bin);
241 return str;
242 }
243
244
fix_length_and_dec()245 bool Item_func_as_geojson::fix_length_and_dec()
246 {
247 collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
248 max_length=MAX_BLOB_WIDTH;
249 maybe_null= 1;
250 return FALSE;
251 }
252
253
val_str_ascii(String * str)254 String *Item_func_as_geojson::val_str_ascii(String *str)
255 {
256 DBUG_ASSERT(fixed == 1);
257 String arg_val;
258 String *swkb= args[0]->val_str(&arg_val);
259 uint max_dec= FLOATING_POINT_DECIMALS;
260 longlong options= 0;
261 Geometry_buffer buffer;
262 Geometry *geom= NULL;
263 const char *dummy;
264
265 if ((null_value=
266 (args[0]->null_value ||
267 !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
268 return 0;
269
270 if (arg_count > 1)
271 {
272 max_dec= (uint) args[1]->val_int();
273 if (args[1]->null_value)
274 max_dec= FLOATING_POINT_DECIMALS;
275 if (arg_count > 2)
276 {
277 options= args[2]->val_int();
278 if (args[2]->null_value)
279 options= 0;
280 }
281 }
282
283 str->length(0);
284 str->set_charset(&my_charset_latin1);
285
286 if (str->reserve(1, 512))
287 return 0;
288
289 str->qs_append('{');
290
291 if (options & 1)
292 {
293 if (geom->bbox_as_json(str) || str->append(", ", 2))
294 goto error;
295 }
296
297 if ((geom->as_json(str, max_dec, &dummy) || str->append("}", 1)))
298 goto error;
299
300 return str;
301
302 error:
303 null_value= 1;
304 return 0;
305 }
306
307
val_str_ascii(String * str)308 String *Item_func_geometry_type::val_str_ascii(String *str)
309 {
310 DBUG_ASSERT(fixed == 1);
311 String *swkb= args[0]->val_str(str);
312 Geometry_buffer buffer;
313 Geometry *geom= NULL;
314
315 if ((null_value=
316 (args[0]->null_value ||
317 !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
318 return 0;
319 /* String will not move */
320 str->copy(geom->get_class_info()->m_name.str,
321 geom->get_class_info()->m_name.length,
322 &my_charset_latin1);
323 return str;
324 }
325
326
get_geometry_type() const327 Field::geometry_type Item_func_envelope::get_geometry_type() const
328 {
329 return Field::GEOM_POLYGON;
330 }
331
332
val_str(String * str)333 String *Item_func_envelope::val_str(String *str)
334 {
335 DBUG_ASSERT(fixed == 1);
336 String arg_val;
337 String *swkb= args[0]->val_str(&arg_val);
338 Geometry_buffer buffer;
339 Geometry *geom= NULL;
340 uint32 srid;
341
342 if ((null_value=
343 args[0]->null_value ||
344 !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
345 return 0;
346
347 srid= uint4korr(swkb->ptr());
348 str->set_charset(&my_charset_bin);
349 str->length(0);
350 if (str->reserve(SRID_SIZE, 512))
351 return 0;
352 str->q_append(srid);
353 return (null_value= geom->envelope(str)) ? 0 : str;
354 }
355
356
single_point(double x,double y)357 int Item_func_boundary::Transporter::single_point(double x, double y)
358 {
359 return 0;
360 }
361
362
start_line()363 int Item_func_boundary::Transporter::start_line()
364 {
365 n_points= 0;
366 current_type= Gcalc_function::shape_line;
367 return 0;
368 }
369
370
complete_line()371 int Item_func_boundary::Transporter::complete_line()
372 {
373 current_type= (Gcalc_function::shape_type) 0;
374 if (n_points > 1)
375 return m_receiver->single_point(last_x, last_y);
376 return 0;
377 }
378
379
start_poly()380 int Item_func_boundary::Transporter::start_poly()
381 {
382 current_type= Gcalc_function::shape_polygon;
383 return 0;
384 }
385
386
complete_poly()387 int Item_func_boundary::Transporter::complete_poly()
388 {
389 current_type= (Gcalc_function::shape_type) 0;
390 return 0;
391 }
392
393
start_ring()394 int Item_func_boundary::Transporter::start_ring()
395 {
396 n_points= 0;
397 return m_receiver->start_shape(Gcalc_function::shape_line);
398 }
399
400
complete_ring()401 int Item_func_boundary::Transporter::complete_ring()
402 {
403 if (n_points > 1)
404 {
405 m_receiver->add_point(last_x, last_y);
406 }
407 m_receiver->complete_shape();
408 return 0;
409 }
410
411
add_point(double x,double y)412 int Item_func_boundary::Transporter::add_point(double x, double y)
413 {
414 ++n_points;
415 if (current_type== Gcalc_function::shape_polygon)
416 {
417 /* Polygon's ring case */
418 if (n_points == 1)
419 {
420 last_x= x;
421 last_y= y;
422 }
423 return m_receiver->add_point(x, y);
424 }
425
426 if (current_type== Gcalc_function::shape_line)
427 {
428 /* Line's case */
429 last_x= x;
430 last_y= y;
431 if (n_points == 1)
432 return m_receiver->single_point(x, y);
433 }
434 return 0;
435 }
436
437
start_collection(int n_objects)438 int Item_func_boundary::Transporter::start_collection(int n_objects)
439 {
440 return 0;
441 }
442
443
val_str(String * str_value)444 String *Item_func_boundary::val_str(String *str_value)
445 {
446 DBUG_ENTER("Item_func_boundary::val_str");
447 DBUG_ASSERT(fixed == 1);
448 String arg_val;
449 String *swkb= args[0]->val_str(&arg_val);
450
451 if ((null_value= args[0]->null_value))
452 DBUG_RETURN(0);
453
454 Geometry_buffer buffer;
455 uint32 srid= 0;
456 Transporter trn(&res_receiver);
457
458 Geometry *g= Geometry::construct(&buffer, swkb->ptr(), swkb->length());
459 if (!g)
460 DBUG_RETURN(0);
461
462 if (g->store_shapes(&trn))
463 goto mem_error;
464
465 str_value->set_charset(&my_charset_bin);
466 if (str_value->reserve(SRID_SIZE, 512))
467 goto mem_error;
468 str_value->length(0);
469 str_value->q_append(srid);
470
471 if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
472 goto mem_error;
473
474 res_receiver.reset();
475 DBUG_RETURN(str_value);
476
477 mem_error:
478 null_value= 1;
479 DBUG_RETURN(0);
480 }
481
482
get_geometry_type() const483 Field::geometry_type Item_func_centroid::get_geometry_type() const
484 {
485 return Field::GEOM_POINT;
486 }
487
488
val_str(String * str)489 String *Item_func_centroid::val_str(String *str)
490 {
491 DBUG_ASSERT(fixed == 1);
492 String arg_val;
493 String *swkb= args[0]->val_str(&arg_val);
494 Geometry_buffer buffer;
495 Geometry *geom= NULL;
496 uint32 srid;
497
498 if ((null_value= args[0]->null_value ||
499 !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
500 return 0;
501
502 str->set_charset(&my_charset_bin);
503 if (str->reserve(SRID_SIZE, 512))
504 return 0;
505 str->length(0);
506 srid= uint4korr(swkb->ptr());
507 str->q_append(srid);
508
509 return (null_value= MY_TEST(geom->centroid(str))) ? 0 : str;
510 }
511
512
add_node_to_line(ch_node ** p_cur,int dir,const Gcalc_heap::Info * pi)513 int Item_func_convexhull::add_node_to_line(ch_node **p_cur, int dir,
514 const Gcalc_heap::Info *pi)
515 {
516 ch_node *new_node;
517 ch_node *cur= *p_cur;
518
519 while (cur->prev)
520 {
521 int v_sign= Gcalc_scan_iterator::point::cmp_dx_dy(
522 cur->prev->pi, cur->pi, cur->pi, pi);
523 if (v_sign*dir <0)
524 break;
525 new_node= cur;
526 cur= cur->prev;
527 res_heap.free_item(new_node);
528 }
529 if (!(new_node= new_ch_node()))
530 return 1;
531 cur->next= new_node;
532 new_node->prev= cur;
533 new_node->pi= pi;
534 *p_cur= new_node;
535 return 0;
536 }
537
538
539 #ifndef HEAVY_CONVEX_HULL
val_str(String * str_value)540 String *Item_func_convexhull::val_str(String *str_value)
541 {
542 Geometry_buffer buffer;
543 Geometry *geom= NULL;
544 MBR mbr;
545 const char *c_end;
546 Gcalc_operation_transporter trn(&func, &collector);
547 uint32 srid= 0;
548 ch_node *left_first, *left_cur, *right_first, *right_cur;
549 Gcalc_heap::Info *cur_pi;
550
551 DBUG_ENTER("Item_func_convexhull::val_str");
552 DBUG_ASSERT(fixed == 1);
553 String *swkb= args[0]->val_str(&tmp_value);
554
555 if ((null_value=
556 args[0]->null_value ||
557 !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
558 DBUG_RETURN(0);
559
560 geom->get_mbr(&mbr, &c_end);
561 collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax);
562 if ((null_value= geom->store_shapes(&trn)))
563 {
564 str_value= 0;
565 goto mem_error;
566 }
567
568 collector.prepare_operation();
569 if (!(cur_pi= collector.get_first()))
570 goto build_result; /* An EMPTY GEOMETRY */
571
572 if (!cur_pi->get_next())
573 {
574 /* Single point. */
575 if (res_receiver.single_point(cur_pi->node.shape.x, cur_pi->node.shape.y))
576 goto mem_error;
577 goto build_result;
578 }
579
580 left_cur= left_first= new_ch_node();
581 right_cur= right_first= new_ch_node();
582 right_first->prev= left_first->prev= 0;
583 right_first->pi= left_first->pi= cur_pi;
584
585 while ((cur_pi= cur_pi->get_next()))
586 {
587 /* Handle left part of the hull, then the right part. */
588 if (add_node_to_line(&left_cur, 1, cur_pi))
589 goto mem_error;
590 if (add_node_to_line(&right_cur, -1, cur_pi))
591 goto mem_error;
592 }
593
594 left_cur->next= 0;
595 if (left_first->get_next()->get_next() == NULL &&
596 right_cur->prev->prev == NULL)
597 {
598 /* We only have 2 nodes in the result, so we create a polyline. */
599 if (res_receiver.start_shape(Gcalc_function::shape_line) ||
600 res_receiver.add_point(left_first->pi->node.shape.x, left_first->pi->node.shape.y) ||
601 res_receiver.add_point(left_cur->pi->node.shape.x, left_cur->pi->node.shape.y) ||
602 res_receiver.complete_shape())
603
604 goto mem_error;
605
606 goto build_result;
607 }
608
609 if (res_receiver.start_shape(Gcalc_function::shape_polygon))
610 goto mem_error;
611
612 while (left_first)
613 {
614 if (res_receiver.add_point(left_first->pi->node.shape.x, left_first->pi->node.shape.y))
615 goto mem_error;
616 left_first= left_first->get_next();
617 }
618
619 /* Skip last point in the right part as it coincides */
620 /* with the last one in the left. */
621 right_cur= right_cur->prev;
622 while (right_cur->prev)
623 {
624 if (res_receiver.add_point(right_cur->pi->node.shape.x, right_cur->pi->node.shape.y))
625 goto mem_error;
626 right_cur= right_cur->prev;
627 }
628 res_receiver.complete_shape();
629
630 build_result:
631 str_value->set_charset(&my_charset_bin);
632 if (str_value->reserve(SRID_SIZE, 512))
633 goto mem_error;
634 str_value->length(0);
635 str_value->q_append(srid);
636
637 if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
638 goto mem_error;
639
640 mem_error:
641 collector.reset();
642 func.reset();
643 res_receiver.reset();
644 res_heap.reset();
645 DBUG_RETURN(str_value);
646 }
647
648 #else /*HEAVY_CONVEX_HULL*/
val_str(String * str_value)649 String *Item_func_convexhull::val_str(String *str_value)
650 {
651 Geometry_buffer buffer;
652 Geometry *geom= NULL;
653 MBR mbr;
654 const char *c_end;
655 Gcalc_operation_transporter trn(&func, &collector);
656 const Gcalc_scan_iterator::event_point *ev;
657 uint32 srid= 0;
658 ch_node *left_first, *left_cur, *right_first, *right_cur;
659
660 DBUG_ENTER("Item_func_convexhull::val_str");
661 DBUG_ASSERT(fixed == 1);
662 String *swkb= args[0]->val_str(&tmp_value);
663
664 if ((null_value=
665 args[0]->null_value ||
666 !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
667 DBUG_RETURN(0);
668
669 geom->get_mbr(&mbr, &c_end);
670 collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax);
671 if ((null_value= geom->store_shapes(&trn)))
672 {
673 str_value= 0;
674 goto mem_error;
675 }
676
677 collector.prepare_operation();
678 scan_it.init(&collector);
679 scan_it.killed= (int *) &(current_thd->killed);
680
681 if (!scan_it.more_points())
682 goto build_result; /* An EMPTY GEOMETRY */
683
684 if (scan_it.step())
685 goto mem_error;
686
687 if (!scan_it.more_points())
688 {
689 /* Single point. */
690 if (res_receiver.single_point(scan_it.get_events()->pi->x,
691 scan_it.get_events()->pi->y))
692 goto mem_error;
693 goto build_result;
694 }
695
696 left_cur= left_first= new_ch_node();
697 right_cur= right_first= new_ch_node();
698 right_first->prev= left_first->prev= 0;
699 right_first->pi= left_first->pi= scan_it.get_events()->pi;
700
701 while (scan_it.more_points())
702 {
703 if (scan_it.step())
704 goto mem_error;
705 ev= scan_it.get_events();
706
707 /* Skip the intersections-only events. */
708 while (ev->event == scev_intersection)
709 {
710 ev= ev->get_next();
711 if (!ev)
712 goto skip_point;
713 }
714
715 {
716 Gcalc_point_iterator pit(&scan_it);
717 if (!pit.point() || scan_it.get_event_position() == pit.point())
718 {
719 /* Handle left part of the hull. */
720 if (add_node_to_line(&left_cur, 1, ev->pi))
721 goto mem_error;
722 }
723 if (pit.point())
724 {
725 /* Check the rightmost point */
726 for(; pit.point()->c_get_next(); ++pit)
727 ;
728 }
729 if (!pit.point() || pit.point()->event ||
730 scan_it.get_event_position() == pit.point()->c_get_next())
731 {
732 /* Handle right part of the hull. */
733 if (add_node_to_line(&right_cur, -1, ev->pi))
734 goto mem_error;
735 }
736 }
737 skip_point:;
738 }
739
740 left_cur->next= 0;
741 if (left_first->get_next()->get_next() == NULL &&
742 right_cur->prev->prev == NULL)
743 {
744 /* We only have 2 nodes in the result, so we create a polyline. */
745 if (res_receiver.start_shape(Gcalc_function::shape_line) ||
746 res_receiver.add_point(left_first->pi->x, left_first->pi->y) ||
747 res_receiver.add_point(left_cur->pi->x, left_cur->pi->y) ||
748 res_receiver.complete_shape())
749
750 goto mem_error;
751
752 goto build_result;
753 }
754
755 if (res_receiver.start_shape(Gcalc_function::shape_polygon))
756 goto mem_error;
757
758 while (left_first)
759 {
760 if (res_receiver.add_point(left_first->pi->x, left_first->pi->y))
761 goto mem_error;
762 left_first= left_first->get_next();
763 }
764
765 /* Skip last point in the right part as it coincides */
766 /* with the last one in the left. */
767 right_cur= right_cur->prev;
768 while (right_cur->prev)
769 {
770 if (res_receiver.add_point(right_cur->pi->x, right_cur->pi->y))
771 goto mem_error;
772 right_cur= right_cur->prev;
773 }
774 res_receiver.complete_shape();
775
776 build_result:
777 str_value->set_charset(&my_charset_bin);
778 if (str_value->reserve(SRID_SIZE, 512))
779 goto mem_error;
780 str_value->length(0);
781 str_value->q_append(srid);
782
783 if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
784 goto mem_error;
785
786 mem_error:
787 collector.reset();
788 func.reset();
789 res_receiver.reset();
790 res_heap.reset();
791 DBUG_RETURN(str_value);
792 }
793 #endif /*HEAVY_CONVEX_HULL*/
794
795
796 /*
797 Spatial decomposition functions
798 */
799
val_str(String * str)800 String *Item_func_spatial_decomp::val_str(String *str)
801 {
802 DBUG_ASSERT(fixed == 1);
803 String arg_val;
804 String *swkb= args[0]->val_str(&arg_val);
805 Geometry_buffer buffer;
806 Geometry *geom= NULL;
807 uint32 srid;
808
809 if ((null_value=
810 (args[0]->null_value ||
811 !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
812 return 0;
813
814 srid= uint4korr(swkb->ptr());
815 str->set_charset(&my_charset_bin);
816 if (str->reserve(SRID_SIZE, 512))
817 goto err;
818 str->length(0);
819 str->q_append(srid);
820 switch (decomp_func) {
821 case SP_STARTPOINT:
822 if (geom->start_point(str))
823 goto err;
824 break;
825
826 case SP_ENDPOINT:
827 if (geom->end_point(str))
828 goto err;
829 break;
830
831 case SP_EXTERIORRING:
832 if (geom->exterior_ring(str))
833 goto err;
834 break;
835
836 default:
837 goto err;
838 }
839 return str;
840
841 err:
842 null_value= 1;
843 return 0;
844 }
845
846
val_str(String * str)847 String *Item_func_spatial_decomp_n::val_str(String *str)
848 {
849 DBUG_ASSERT(fixed == 1);
850 String arg_val;
851 String *swkb= args[0]->val_str(&arg_val);
852 long n= (long) args[1]->val_int();
853 Geometry_buffer buffer;
854 Geometry *geom= NULL;
855 uint32 srid;
856
857 if ((null_value=
858 (args[0]->null_value || args[1]->null_value ||
859 !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
860 return 0;
861
862 str->set_charset(&my_charset_bin);
863 if (str->reserve(SRID_SIZE, 512))
864 goto err;
865 srid= uint4korr(swkb->ptr());
866 str->length(0);
867 str->q_append(srid);
868 switch (decomp_func_n)
869 {
870 case SP_POINTN:
871 if (geom->point_n(n,str))
872 goto err;
873 break;
874
875 case SP_GEOMETRYN:
876 if (geom->geometry_n(n,str))
877 goto err;
878 break;
879
880 case SP_INTERIORRINGN:
881 if (geom->interior_ring_n(n,str))
882 goto err;
883 break;
884
885 default:
886 goto err;
887 }
888 return str;
889
890 err:
891 null_value=1;
892 return 0;
893 }
894
895
896 /*
897 Functions to concatenate various spatial objects
898 */
899
900
901 /*
902 * Concatenate doubles into Point
903 */
904
905
get_geometry_type() const906 Field::geometry_type Item_func_point::get_geometry_type() const
907 {
908 return Field::GEOM_POINT;
909 }
910
911
val_str(String * str)912 String *Item_func_point::val_str(String *str)
913 {
914 DBUG_ASSERT(fixed == 1);
915 double x= args[0]->val_real();
916 double y= args[1]->val_real();
917 uint32 srid= 0;
918
919 if ((null_value= (args[0]->null_value ||
920 args[1]->null_value ||
921 str->realloc(4/*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE * 2))))
922 return 0;
923
924 str->set_charset(&my_charset_bin);
925 str->length(0);
926 str->q_append(srid);
927 str->q_append((char)Geometry::wkb_ndr);
928 str->q_append((uint32)Geometry::wkb_point);
929 str->q_append(x);
930 str->q_append(y);
931 return str;
932 }
933
934
935 /**
936 Concatenates various items into various collections
937 with checkings for valid wkb type of items.
938 For example, MultiPoint can be a collection of Points only.
939 coll_type contains wkb type of target collection.
940 item_type contains a valid wkb type of items.
941 In the case when coll_type is wkbGeometryCollection,
942 we do not check wkb type of items, any is valid.
943 */
944
val_str(String * str)945 String *Item_func_spatial_collection::val_str(String *str)
946 {
947 DBUG_ASSERT(fixed == 1);
948 String arg_value;
949 uint i;
950 uint32 srid= 0;
951
952 str->set_charset(&my_charset_bin);
953 str->length(0);
954 if (str->reserve(4/*SRID*/ + 1 + 4 + 4, 512))
955 goto err;
956
957 str->q_append(srid);
958 str->q_append((char) Geometry::wkb_ndr);
959 str->q_append((uint32) coll_type);
960 str->q_append((uint32) arg_count);
961
962 for (i= 0; i < arg_count; ++i)
963 {
964 String *res= args[i]->val_str(&arg_value);
965 uint32 len;
966 if (args[i]->null_value || ((len= res->length()) < WKB_HEADER_SIZE))
967 goto err;
968
969 if (coll_type == Geometry::wkb_geometrycollection)
970 {
971 /*
972 In the case of GeometryCollection we don't need any checkings
973 for item types, so just copy them into target collection
974 */
975 if (str->append(res->ptr() + 4/*SRID*/, len - 4/*SRID*/, (uint32) 512))
976 goto err;
977 }
978 else
979 {
980 enum Geometry::wkbType wkb_type;
981 const uint data_offset= 4/*SRID*/ + 1;
982 if (res->length() < data_offset + sizeof(uint32))
983 goto err;
984 const char *data= res->ptr() + data_offset;
985
986 /*
987 In the case of named collection we must check that items
988 are of specific type, let's do this checking now
989 */
990
991 wkb_type= (Geometry::wkbType) uint4korr(data);
992 data+= 4;
993 len-= 5 + 4/*SRID*/;
994 if (wkb_type != item_type)
995 goto err;
996
997 switch (coll_type) {
998 case Geometry::wkb_multipoint:
999 case Geometry::wkb_multilinestring:
1000 case Geometry::wkb_multipolygon:
1001 if (len < WKB_HEADER_SIZE ||
1002 str->append(data-WKB_HEADER_SIZE, len+WKB_HEADER_SIZE, 512))
1003 goto err;
1004 break;
1005
1006 case Geometry::wkb_linestring:
1007 if (len < POINT_DATA_SIZE || str->append(data, POINT_DATA_SIZE, 512))
1008 goto err;
1009 break;
1010 case Geometry::wkb_polygon:
1011 {
1012 uint32 n_points;
1013 double x1, y1, x2, y2;
1014 const char *org_data= data;
1015
1016 if (len < 4)
1017 goto err;
1018
1019 n_points= uint4korr(data);
1020 data+= 4;
1021
1022 if (n_points < 2 || len < 4 + n_points * POINT_DATA_SIZE)
1023 goto err;
1024
1025 float8get(x1, data);
1026 data+= SIZEOF_STORED_DOUBLE;
1027 float8get(y1, data);
1028 data+= SIZEOF_STORED_DOUBLE;
1029
1030 data+= (n_points - 2) * POINT_DATA_SIZE;
1031
1032 float8get(x2, data);
1033 float8get(y2, data + SIZEOF_STORED_DOUBLE);
1034
1035 if ((x1 != x2) || (y1 != y2) ||
1036 str->append(org_data, len, 512))
1037 goto err;
1038 }
1039 break;
1040
1041 default:
1042 goto err;
1043 }
1044 }
1045 }
1046 if (str->length() > current_thd->variables.max_allowed_packet)
1047 {
1048 THD *thd= current_thd;
1049 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
1050 ER_WARN_ALLOWED_PACKET_OVERFLOWED,
1051 ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
1052 func_name(), thd->variables.max_allowed_packet);
1053 goto err;
1054 }
1055
1056 null_value = 0;
1057 return str;
1058
1059 err:
1060 null_value= 1;
1061 return 0;
1062 }
1063
1064
1065 /*
1066 Functions for spatial relations
1067 */
1068
1069 static SEL_ARG sel_arg_impossible(SEL_ARG::IMPOSSIBLE);
1070
1071 SEL_ARG *
get_mm_leaf(RANGE_OPT_PARAM * param,Field * field,KEY_PART * key_part,Item_func::Functype type,Item * value)1072 Item_func_spatial_rel::get_mm_leaf(RANGE_OPT_PARAM *param,
1073 Field *field, KEY_PART *key_part,
1074 Item_func::Functype type, Item *value)
1075 {
1076 DBUG_ENTER("Item_func_spatial_rel::get_mm_leaf");
1077 if (key_part->image_type != Field::itMBR)
1078 DBUG_RETURN(0);
1079 if (value->cmp_type() != STRING_RESULT)
1080 DBUG_RETURN(&sel_arg_impossible);
1081
1082 if (param->using_real_indexes &&
1083 !field->optimize_range(param->real_keynr[key_part->key],
1084 key_part->part))
1085 DBUG_RETURN(0);
1086
1087 if (value->save_in_field_no_warnings(field, 1))
1088 DBUG_RETURN(&sel_arg_impossible); // Bad GEOMETRY value
1089
1090 DBUG_ASSERT(!field->real_maybe_null()); // SPATIAL keys do not support NULL
1091
1092 uchar *str= (uchar*) alloc_root(param->mem_root, key_part->store_length + 1);
1093 if (!str)
1094 DBUG_RETURN(0); // out of memory
1095 field->get_key_image(str, key_part->length, key_part->image_type);
1096 SEL_ARG *tree;
1097 if (!(tree= new (param->mem_root) SEL_ARG(field, str, str)))
1098 DBUG_RETURN(0); // out of memory
1099
1100 switch (type) {
1101 case SP_EQUALS_FUNC:
1102 tree->min_flag= GEOM_FLAG | HA_READ_MBR_EQUAL;// NEAR_MIN;//512;
1103 tree->max_flag= NO_MAX_RANGE;
1104 break;
1105 case SP_DISJOINT_FUNC:
1106 tree->min_flag= GEOM_FLAG | HA_READ_MBR_DISJOINT;// NEAR_MIN;//512;
1107 tree->max_flag= NO_MAX_RANGE;
1108 break;
1109 case SP_INTERSECTS_FUNC:
1110 tree->min_flag= GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
1111 tree->max_flag= NO_MAX_RANGE;
1112 break;
1113 case SP_TOUCHES_FUNC:
1114 tree->min_flag= GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
1115 tree->max_flag= NO_MAX_RANGE;
1116 break;
1117 case SP_CROSSES_FUNC:
1118 tree->min_flag= GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
1119 tree->max_flag= NO_MAX_RANGE;
1120 break;
1121 case SP_WITHIN_FUNC:
1122 tree->min_flag= GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512;
1123 tree->max_flag= NO_MAX_RANGE;
1124 break;
1125 case SP_CONTAINS_FUNC:
1126 tree->min_flag= GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512;
1127 tree->max_flag= NO_MAX_RANGE;
1128 break;
1129 case SP_OVERLAPS_FUNC:
1130 tree->min_flag= GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
1131 tree->max_flag= NO_MAX_RANGE;
1132 break;
1133 default:
1134 DBUG_ASSERT(0);
1135 break;
1136 }
1137 DBUG_RETURN(tree);
1138 }
1139
1140
func_name() const1141 const char *Item_func_spatial_mbr_rel::func_name() const
1142 {
1143 switch (spatial_rel) {
1144 case SP_CONTAINS_FUNC:
1145 return "mbrcontains";
1146 case SP_WITHIN_FUNC:
1147 return "mbrwithin";
1148 case SP_EQUALS_FUNC:
1149 return "mbrequals";
1150 case SP_DISJOINT_FUNC:
1151 return "mbrdisjoint";
1152 case SP_INTERSECTS_FUNC:
1153 return "mbrintersects";
1154 case SP_TOUCHES_FUNC:
1155 return "mbrtouches";
1156 case SP_CROSSES_FUNC:
1157 return "mbrcrosses";
1158 case SP_OVERLAPS_FUNC:
1159 return "mbroverlaps";
1160 default:
1161 DBUG_ASSERT(0); // Should never happened
1162 return "mbrsp_unknown";
1163 }
1164 }
1165
1166
val_int()1167 longlong Item_func_spatial_mbr_rel::val_int()
1168 {
1169 DBUG_ASSERT(fixed == 1);
1170 String *res1= args[0]->val_str(&tmp_value1);
1171 String *res2= args[1]->val_str(&tmp_value2);
1172 Geometry_buffer buffer1, buffer2;
1173 Geometry *g1, *g2;
1174 MBR mbr1, mbr2;
1175 const char *dummy;
1176
1177 if ((null_value=
1178 (args[0]->null_value ||
1179 args[1]->null_value ||
1180 !(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) ||
1181 !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) ||
1182 g1->get_mbr(&mbr1, &dummy) || !mbr1.valid() ||
1183 g2->get_mbr(&mbr2, &dummy) || !mbr2.valid())))
1184 return 0;
1185
1186 switch (spatial_rel) {
1187 case SP_CONTAINS_FUNC:
1188 return mbr1.contains(&mbr2);
1189 case SP_WITHIN_FUNC:
1190 return mbr1.within(&mbr2);
1191 case SP_EQUALS_FUNC:
1192 return mbr1.equals(&mbr2);
1193 case SP_DISJOINT_FUNC:
1194 return mbr1.disjoint(&mbr2);
1195 case SP_INTERSECTS_FUNC:
1196 return mbr1.intersects(&mbr2);
1197 case SP_TOUCHES_FUNC:
1198 return mbr1.touches(&mbr2);
1199 case SP_OVERLAPS_FUNC:
1200 return mbr1.overlaps(&mbr2);
1201 case SP_CROSSES_FUNC:
1202 return 0;
1203 default:
1204 break;
1205 }
1206
1207 null_value=1;
1208 return 0;
1209 }
1210
1211
func_name() const1212 const char *Item_func_spatial_precise_rel::func_name() const
1213 {
1214 switch (spatial_rel) {
1215 case SP_CONTAINS_FUNC:
1216 return "st_contains";
1217 case SP_WITHIN_FUNC:
1218 return "st_within";
1219 case SP_EQUALS_FUNC:
1220 return "st_equals";
1221 case SP_DISJOINT_FUNC:
1222 return "st_disjoint";
1223 case SP_INTERSECTS_FUNC:
1224 return "st_intersects";
1225 case SP_TOUCHES_FUNC:
1226 return "st_touches";
1227 case SP_CROSSES_FUNC:
1228 return "st_crosses";
1229 case SP_OVERLAPS_FUNC:
1230 return "st_overlaps";
1231 default:
1232 DBUG_ASSERT(0); // Should never happened
1233 return "sp_unknown";
1234 }
1235 }
1236
1237
count_edge_t(const Gcalc_heap::Info * ea,const Gcalc_heap::Info * eb,const Gcalc_heap::Info * v,double & ex,double & ey,double & vx,double & vy,double & e_sqrlen)1238 static double count_edge_t(const Gcalc_heap::Info *ea,
1239 const Gcalc_heap::Info *eb,
1240 const Gcalc_heap::Info *v,
1241 double &ex, double &ey, double &vx, double &vy,
1242 double &e_sqrlen)
1243 {
1244 ex= eb->node.shape.x - ea->node.shape.x;
1245 ey= eb->node.shape.y - ea->node.shape.y;
1246 vx= v->node.shape.x - ea->node.shape.x;
1247 vy= v->node.shape.y - ea->node.shape.y;
1248 e_sqrlen= ex * ex + ey * ey;
1249 return (ex * vx + ey * vy) / e_sqrlen;
1250 }
1251
1252
distance_to_line(double ex,double ey,double vx,double vy,double e_sqrlen)1253 static double distance_to_line(double ex, double ey, double vx, double vy,
1254 double e_sqrlen)
1255 {
1256 return fabs(vx * ey - vy * ex) / sqrt(e_sqrlen);
1257 }
1258
1259
distance_points(const Gcalc_heap::Info * a,const Gcalc_heap::Info * b)1260 static double distance_points(const Gcalc_heap::Info *a,
1261 const Gcalc_heap::Info *b)
1262 {
1263 double x= a->node.shape.x - b->node.shape.x;
1264 double y= a->node.shape.y - b->node.shape.y;
1265 return sqrt(x * x + y * y);
1266 }
1267
1268
op_matrix(int n)1269 static Gcalc_function::op_type op_matrix(int n)
1270 {
1271 switch (n)
1272 {
1273 case 0:
1274 return Gcalc_function::op_internals;
1275 case 1:
1276 return Gcalc_function::op_border;
1277 case 2:
1278 return (Gcalc_function::op_type)
1279 ((int) Gcalc_function::op_not | (int) Gcalc_function::op_union);
1280 };
1281 GCALC_DBUG_ASSERT(FALSE);
1282 return Gcalc_function::op_any;
1283 }
1284
1285
setup_relate_func(Geometry * g1,Geometry * g2,Gcalc_operation_transporter * trn,Gcalc_function * func,const char * mask)1286 static int setup_relate_func(Geometry *g1, Geometry *g2,
1287 Gcalc_operation_transporter *trn, Gcalc_function *func,
1288 const char *mask)
1289 {
1290 int do_store_shapes=1;
1291 uint UNINIT_VAR(shape_a), UNINIT_VAR(shape_b);
1292 uint n_operands= 0;
1293 int last_shape_pos;
1294
1295 last_shape_pos= func->get_next_expression_pos();
1296 if (func->reserve_op_buffer(1))
1297 return 1;
1298 func->add_operation(Gcalc_function::op_intersection, 0);
1299 for (int nc=0; nc<9; nc++)
1300 {
1301 uint cur_op;
1302
1303 cur_op= Gcalc_function::op_intersection;
1304 switch (mask[nc])
1305 {
1306 case '*':
1307 continue;
1308 case 'T':
1309 case '0':
1310 case '1':
1311 case '2':
1312 cur_op|= Gcalc_function::v_find_t;
1313 break;
1314 case 'F':
1315 cur_op|= (Gcalc_function::op_not | Gcalc_function::v_find_f);
1316 break;
1317 default:
1318 return 1;
1319 };
1320 ++n_operands;
1321 if (func->reserve_op_buffer(3))
1322 return 1;
1323 func->add_operation(cur_op, 2);
1324
1325 func->add_operation(op_matrix(nc/3), 1);
1326 if (do_store_shapes)
1327 {
1328 shape_a= func->get_next_expression_pos();
1329 if (g1->store_shapes(trn))
1330 return 1;
1331 }
1332 else
1333 func->repeat_expression(shape_a);
1334 if (func->reserve_op_buffer(1))
1335 return 1;
1336 func->add_operation(op_matrix(nc%3), 1);
1337 if (do_store_shapes)
1338 {
1339 shape_b= func->get_next_expression_pos();
1340 if (g2->store_shapes(trn))
1341 return 1;
1342 do_store_shapes= 0;
1343 }
1344 else
1345 func->repeat_expression(shape_b);
1346 }
1347
1348 func->add_operands_to_op(last_shape_pos, n_operands);
1349 return 0;
1350 }
1351
1352
1353 #define GIS_ZERO 0.00000000001
1354
1355 class Geometry_ptr_with_buffer_and_mbr
1356 {
1357 public:
1358 Geometry *geom;
1359 Geometry_buffer buffer;
1360 MBR mbr;
construct(Item * item,String * tmp_value)1361 bool construct(Item *item, String *tmp_value)
1362 {
1363 const char *c_end;
1364 String *res= item->val_str(tmp_value);
1365 return
1366 item->null_value ||
1367 !(geom= Geometry::construct(&buffer, res->ptr(), res->length())) ||
1368 geom->get_mbr(&mbr, &c_end) || !mbr.valid();
1369 }
store_shapes(Gcalc_shape_transporter * trn) const1370 int store_shapes(Gcalc_shape_transporter *trn) const
1371 { return geom->store_shapes(trn); }
1372 };
1373
1374
val_int()1375 longlong Item_func_spatial_relate::val_int()
1376 {
1377 DBUG_ENTER("Item_func_spatial_relate::val_int");
1378 DBUG_ASSERT(fixed == 1);
1379 Geometry_ptr_with_buffer_and_mbr g1, g2;
1380 int result= 0;
1381
1382 if ((null_value= (g1.construct(args[0], &tmp_value1) ||
1383 g2.construct(args[1], &tmp_value2) ||
1384 func.reserve_op_buffer(1))))
1385 DBUG_RETURN(0);
1386
1387 MBR umbr(g1.mbr, g2.mbr);
1388 collector.set_extent(umbr.xmin, umbr.xmax, umbr.ymin, umbr.ymax);
1389 g1.mbr.buffer(1e-5);
1390 Gcalc_operation_transporter trn(&func, &collector);
1391
1392 String *matrix= args[2]->val_str(&tmp_matrix);
1393 if ((null_value= args[2]->null_value || matrix->length() != 9 ||
1394 setup_relate_func(g1.geom, g2.geom,
1395 &trn, &func, matrix->ptr())))
1396 goto exit;
1397
1398 collector.prepare_operation();
1399 scan_it.init(&collector);
1400 scan_it.killed= (int *) &(current_thd->killed);
1401 if (!func.alloc_states())
1402 result= func.check_function(scan_it);
1403
1404 exit:
1405 collector.reset();
1406 func.reset();
1407 scan_it.reset();
1408 DBUG_RETURN(result);
1409 }
1410
1411
val_int()1412 longlong Item_func_spatial_precise_rel::val_int()
1413 {
1414 DBUG_ENTER("Item_func_spatial_precise_rel::val_int");
1415 DBUG_ASSERT(fixed == 1);
1416 Geometry_ptr_with_buffer_and_mbr g1, g2;
1417 int result= 0;
1418 uint shape_a, shape_b;
1419
1420 if ((null_value= (g1.construct(args[0], &tmp_value1) ||
1421 g2.construct(args[1], &tmp_value2) ||
1422 func.reserve_op_buffer(1))))
1423 DBUG_RETURN(0);
1424
1425 Gcalc_operation_transporter trn(&func, &collector);
1426
1427 MBR umbr(g1.mbr, g2.mbr);
1428 collector.set_extent(umbr.xmin, umbr.xmax, umbr.ymin, umbr.ymax);
1429
1430 g1.mbr.buffer(1e-5);
1431
1432 switch (spatial_rel) {
1433 case SP_CONTAINS_FUNC:
1434 if (!g1.mbr.contains(&g2.mbr))
1435 goto exit;
1436 func.add_operation(Gcalc_function::v_find_f |
1437 Gcalc_function::op_not |
1438 Gcalc_function::op_difference, 2);
1439 /* Mind the g2 goes first. */
1440 null_value= g2.store_shapes(&trn) || g1.store_shapes(&trn);
1441 break;
1442 case SP_WITHIN_FUNC:
1443 g2.mbr.buffer(2e-5);
1444 if (!g1.mbr.within(&g2.mbr))
1445 goto exit;
1446 func.add_operation(Gcalc_function::v_find_f |
1447 Gcalc_function::op_not |
1448 Gcalc_function::op_difference, 2);
1449 null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn);
1450 break;
1451 case SP_EQUALS_FUNC:
1452 if (!g1.mbr.contains(&g2.mbr))
1453 goto exit;
1454 func.add_operation(Gcalc_function::v_find_f |
1455 Gcalc_function::op_not |
1456 Gcalc_function::op_symdifference, 2);
1457 null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn);
1458 break;
1459 case SP_DISJOINT_FUNC:
1460 func.add_operation(Gcalc_function::v_find_f |
1461 Gcalc_function::op_not |
1462 Gcalc_function::op_intersection, 2);
1463 null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn);
1464 break;
1465 case SP_INTERSECTS_FUNC:
1466 if (!g1.mbr.intersects(&g2.mbr))
1467 goto exit;
1468 func.add_operation(Gcalc_function::v_find_t |
1469 Gcalc_function::op_intersection, 2);
1470 null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn);
1471 break;
1472 case SP_OVERLAPS_FUNC:
1473 case SP_CROSSES_FUNC:
1474 func.add_operation(Gcalc_function::op_intersection, 2);
1475 if (func.reserve_op_buffer(3))
1476 break;
1477 func.add_operation(Gcalc_function::v_find_t |
1478 Gcalc_function::op_intersection, 2);
1479 shape_a= func.get_next_expression_pos();
1480 if ((null_value= g1.store_shapes(&trn)))
1481 break;
1482 shape_b= func.get_next_expression_pos();
1483 if ((null_value= g2.store_shapes(&trn)))
1484 break;
1485 if (func.reserve_op_buffer(7))
1486 break;
1487 func.add_operation(Gcalc_function::op_intersection, 2);
1488 func.add_operation(Gcalc_function::v_find_t |
1489 Gcalc_function::op_difference, 2);
1490 func.repeat_expression(shape_a);
1491 func.repeat_expression(shape_b);
1492 func.add_operation(Gcalc_function::v_find_t |
1493 Gcalc_function::op_difference, 2);
1494 func.repeat_expression(shape_b);
1495 func.repeat_expression(shape_a);
1496 break;
1497 case SP_TOUCHES_FUNC:
1498 if (func.reserve_op_buffer(5))
1499 break;
1500 func.add_operation(Gcalc_function::op_intersection, 2);
1501 func.add_operation(Gcalc_function::v_find_f |
1502 Gcalc_function::op_not |
1503 Gcalc_function::op_intersection, 2);
1504 func.add_operation(Gcalc_function::op_internals, 1);
1505 shape_a= func.get_next_expression_pos();
1506 if ((null_value= g1.store_shapes(&trn)) ||
1507 func.reserve_op_buffer(1))
1508 break;
1509 func.add_operation(Gcalc_function::op_internals, 1);
1510 shape_b= func.get_next_expression_pos();
1511 if ((null_value= g2.store_shapes(&trn)) ||
1512 func.reserve_op_buffer(1))
1513 break;
1514 func.add_operation(Gcalc_function::v_find_t |
1515 Gcalc_function::op_intersection, 2);
1516 func.repeat_expression(shape_a);
1517 func.repeat_expression(shape_b);
1518 break;
1519 default:
1520 DBUG_ASSERT(FALSE);
1521 break;
1522 }
1523
1524 if (null_value)
1525 goto exit;
1526
1527 collector.prepare_operation();
1528 scan_it.init(&collector);
1529 scan_it.killed= (int *) &(current_thd->killed);
1530
1531 if (func.alloc_states())
1532 goto exit;
1533
1534 result= func.check_function(scan_it);
1535
1536 exit:
1537 collector.reset();
1538 func.reset();
1539 scan_it.reset();
1540 DBUG_RETURN(result);
1541 }
1542
1543
~Item_func_spatial_operation()1544 Item_func_spatial_operation::~Item_func_spatial_operation()
1545 {
1546 }
1547
1548
val_str(String * str_value)1549 String *Item_func_spatial_operation::val_str(String *str_value)
1550 {
1551 DBUG_ENTER("Item_func_spatial_operation::val_str");
1552 DBUG_ASSERT(fixed == 1);
1553 Geometry_ptr_with_buffer_and_mbr g1, g2;
1554 uint32 srid= 0;
1555 Gcalc_operation_transporter trn(&func, &collector);
1556
1557 if (func.reserve_op_buffer(1))
1558 DBUG_RETURN(0);
1559 func.add_operation(spatial_op, 2);
1560
1561 if ((null_value= (g1.construct(args[0], &tmp_value1) ||
1562 g2.construct(args[1], &tmp_value2))))
1563 {
1564 str_value= 0;
1565 goto exit;
1566 }
1567
1568 g1.mbr.add_mbr(&g2.mbr);
1569 collector.set_extent(g1.mbr.xmin, g1.mbr.xmax, g1.mbr.ymin, g1.mbr.ymax);
1570
1571 if ((null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn)))
1572 {
1573 str_value= 0;
1574 goto exit;
1575 }
1576
1577 collector.prepare_operation();
1578 if (func.alloc_states())
1579 goto exit;
1580
1581 operation.init(&func);
1582
1583 if (operation.count_all(&collector) ||
1584 operation.get_result(&res_receiver))
1585 goto exit;
1586
1587
1588 str_value->set_charset(&my_charset_bin);
1589 if (str_value->reserve(SRID_SIZE, 512))
1590 goto exit;
1591 str_value->length(0);
1592 str_value->q_append(srid);
1593
1594 if (!Geometry::create_from_opresult(&g1.buffer, str_value, res_receiver))
1595 goto exit;
1596
1597 exit:
1598 collector.reset();
1599 func.reset();
1600 res_receiver.reset();
1601 DBUG_RETURN(str_value);
1602 }
1603
1604
func_name() const1605 const char *Item_func_spatial_operation::func_name() const
1606 {
1607 switch (spatial_op) {
1608 case Gcalc_function::op_intersection:
1609 return "st_intersection";
1610 case Gcalc_function::op_difference:
1611 return "st_difference";
1612 case Gcalc_function::op_union:
1613 return "st_union";
1614 case Gcalc_function::op_symdifference:
1615 return "st_symdifference";
1616 default:
1617 DBUG_ASSERT(0); // Should never happen
1618 return "sp_unknown";
1619 }
1620 }
1621
1622
1623 static const int SINUSES_CALCULATED= 32;
1624 static double n_sinus[SINUSES_CALCULATED+1]=
1625 {
1626 0,
1627 0.04906767432741802,
1628 0.0980171403295606,
1629 0.1467304744553618,
1630 0.1950903220161283,
1631 0.2429801799032639,
1632 0.2902846772544623,
1633 0.3368898533922201,
1634 0.3826834323650898,
1635 0.4275550934302821,
1636 0.4713967368259976,
1637 0.5141027441932217,
1638 0.5555702330196022,
1639 0.5956993044924334,
1640 0.6343932841636455,
1641 0.6715589548470183,
1642 0.7071067811865475,
1643 0.7409511253549591,
1644 0.773010453362737,
1645 0.8032075314806448,
1646 0.8314696123025452,
1647 0.8577286100002721,
1648 0.8819212643483549,
1649 0.9039892931234433,
1650 0.9238795325112867,
1651 0.9415440651830208,
1652 0.9569403357322089,
1653 0.970031253194544,
1654 0.9807852804032304,
1655 0.989176509964781,
1656 0.9951847266721968,
1657 0.9987954562051724,
1658 1
1659 };
1660
1661
get_n_sincos(int n,double * sinus,double * cosinus)1662 static void get_n_sincos(int n, double *sinus, double *cosinus)
1663 {
1664 DBUG_ASSERT(n > 0 && n < SINUSES_CALCULATED*2+1);
1665 if (n < (SINUSES_CALCULATED + 1))
1666 {
1667 *sinus= n_sinus[n];
1668 *cosinus= n_sinus[SINUSES_CALCULATED - n];
1669 }
1670 else
1671 {
1672 n-= SINUSES_CALCULATED;
1673 *sinus= n_sinus[SINUSES_CALCULATED - n];
1674 *cosinus= -n_sinus[n];
1675 }
1676 }
1677
1678
fill_half_circle(Gcalc_shape_transporter * trn,double x,double y,double ax,double ay)1679 static int fill_half_circle(Gcalc_shape_transporter *trn, double x, double y,
1680 double ax, double ay)
1681 {
1682 double n_sin, n_cos;
1683 double x_n, y_n;
1684 for (int n = 1; n < (SINUSES_CALCULATED * 2 - 1); n++)
1685 {
1686 get_n_sincos(n, &n_sin, &n_cos);
1687 x_n= ax * n_cos - ay * n_sin;
1688 y_n= ax * n_sin + ay * n_cos;
1689 if (trn->add_point(x_n + x, y_n + y))
1690 return 1;
1691 }
1692 return 0;
1693 }
1694
1695
fill_gap(Gcalc_shape_transporter * trn,double x,double y,double ax,double ay,double bx,double by,double d,bool * empty_gap)1696 static int fill_gap(Gcalc_shape_transporter *trn,
1697 double x, double y,
1698 double ax, double ay, double bx, double by, double d,
1699 bool *empty_gap)
1700 {
1701 double ab= ax * bx + ay * by;
1702 double cosab= ab / (d * d) + GIS_ZERO;
1703 double n_sin, n_cos;
1704 double x_n, y_n;
1705 int n=1;
1706
1707 *empty_gap= true;
1708 for (;;)
1709 {
1710 get_n_sincos(n++, &n_sin, &n_cos);
1711 if (n_cos <= cosab)
1712 break;
1713 *empty_gap= false;
1714 x_n= ax * n_cos - ay * n_sin;
1715 y_n= ax * n_sin + ay * n_cos;
1716 if (trn->add_point(x_n + x, y_n + y))
1717 return 1;
1718 }
1719 return 0;
1720 }
1721
1722
1723 /*
1724 Calculates the vector (p2,p1) and
1725 negatively orthogonal to it with the length of d.
1726 The result is (ex,ey) - the vector, (px,py) - the orthogonal.
1727 */
1728
calculate_perpendicular(double x1,double y1,double x2,double y2,double d,double * ex,double * ey,double * px,double * py)1729 static void calculate_perpendicular(
1730 double x1, double y1, double x2, double y2, double d,
1731 double *ex, double *ey,
1732 double *px, double *py)
1733 {
1734 double q;
1735 *ex= x1 - x2;
1736 *ey= y1 - y2;
1737 q= d / sqrt((*ex) * (*ex) + (*ey) * (*ey));
1738 *px= (*ey) * q;
1739 *py= -(*ex) * q;
1740 }
1741
1742
single_point(double x,double y)1743 int Item_func_buffer::Transporter::single_point(double x, double y)
1744 {
1745 if (buffer_op == Gcalc_function::op_difference)
1746 {
1747 if (m_fn->reserve_op_buffer(1))
1748 return 1;
1749 m_fn->add_operation(Gcalc_function::op_false, 0);
1750 return 0;
1751 }
1752
1753 m_nshapes= 0;
1754 return add_point_buffer(x, y);
1755 }
1756
1757
add_edge_buffer(double x3,double y3,bool round_p1,bool round_p2)1758 int Item_func_buffer::Transporter::add_edge_buffer(
1759 double x3, double y3, bool round_p1, bool round_p2)
1760 {
1761 Gcalc_operation_transporter trn(m_fn, m_heap);
1762 double e1_x, e1_y, e2_x, e2_y, p1_x, p1_y, p2_x, p2_y;
1763 double e1e2;
1764 double sin1, cos1;
1765 double x_n, y_n;
1766 bool empty_gap1, empty_gap2;
1767
1768 ++m_nshapes;
1769 if (trn.start_simple_poly())
1770 return 1;
1771
1772 calculate_perpendicular(x1, y1, x2, y2, m_d, &e1_x, &e1_y, &p1_x, &p1_y);
1773 calculate_perpendicular(x3, y3, x2, y2, m_d, &e2_x, &e2_y, &p2_x, &p2_y);
1774
1775 e1e2= e1_x * e2_y - e2_x * e1_y;
1776 sin1= n_sinus[1];
1777 cos1= n_sinus[31];
1778 if (e1e2 < 0)
1779 {
1780 empty_gap2= false;
1781 x_n= x2 + p2_x * cos1 - p2_y * sin1;
1782 y_n= y2 + p2_y * cos1 + p2_x * sin1;
1783 if (fill_gap(&trn, x2, y2, -p1_x,-p1_y, p2_x,p2_y, m_d, &empty_gap1) ||
1784 trn.add_point(x2 + p2_x, y2 + p2_y) ||
1785 trn.add_point(x_n, y_n))
1786 return 1;
1787 }
1788 else
1789 {
1790 x_n= x2 - p2_x * cos1 - p2_y * sin1;
1791 y_n= y2 - p2_y * cos1 + p2_x * sin1;
1792 if (trn.add_point(x_n, y_n) ||
1793 trn.add_point(x2 - p2_x, y2 - p2_y) ||
1794 fill_gap(&trn, x2, y2, -p2_x, -p2_y, p1_x, p1_y, m_d, &empty_gap2))
1795 return 1;
1796 empty_gap1= false;
1797 }
1798 if ((!empty_gap2 && trn.add_point(x2 + p1_x, y2 + p1_y)) ||
1799 trn.add_point(x1 + p1_x, y1 + p1_y))
1800 return 1;
1801
1802 if (round_p1 && fill_half_circle(&trn, x1, y1, p1_x, p1_y))
1803 return 1;
1804
1805 if (trn.add_point(x1 - p1_x, y1 - p1_y) ||
1806 (!empty_gap1 && trn.add_point(x2 - p1_x, y2 - p1_y)))
1807 return 1;
1808 return trn.complete_simple_poly();
1809 }
1810
1811
add_last_edge_buffer()1812 int Item_func_buffer::Transporter::add_last_edge_buffer()
1813 {
1814 Gcalc_operation_transporter trn(m_fn, m_heap);
1815 double e1_x, e1_y, p1_x, p1_y;
1816
1817 ++m_nshapes;
1818 if (trn.start_simple_poly())
1819 return 1;
1820
1821 calculate_perpendicular(x1, y1, x2, y2, m_d, &e1_x, &e1_y, &p1_x, &p1_y);
1822
1823 if (trn.add_point(x1 + p1_x, y1 + p1_y) ||
1824 trn.add_point(x1 - p1_x, y1 - p1_y) ||
1825 trn.add_point(x2 - p1_x, y2 - p1_y) ||
1826 fill_half_circle(&trn, x2, y2, -p1_x, -p1_y) ||
1827 trn.add_point(x2 + p1_x, y2 + p1_y))
1828 return 1;
1829 return trn.complete_simple_poly();
1830 }
1831
1832
add_point_buffer(double x,double y)1833 int Item_func_buffer::Transporter::add_point_buffer(double x, double y)
1834 {
1835 Gcalc_operation_transporter trn(m_fn, m_heap);
1836
1837 m_nshapes++;
1838 if (trn.start_simple_poly())
1839 return 1;
1840 if (trn.add_point(x - m_d, y) ||
1841 fill_half_circle(&trn, x, y, -m_d, 0.0) ||
1842 trn.add_point(x + m_d, y) ||
1843 fill_half_circle(&trn, x, y, m_d, 0.0))
1844 return 1;
1845 return trn.complete_simple_poly();
1846 }
1847
1848
start_line()1849 int Item_func_buffer::Transporter::start_line()
1850 {
1851 if (buffer_op == Gcalc_function::op_difference)
1852 {
1853 if (m_fn->reserve_op_buffer(1))
1854 return 1;
1855 m_fn->add_operation(Gcalc_function::op_false, 0);
1856 skip_line= TRUE;
1857 return 0;
1858 }
1859
1860 m_nshapes= 0;
1861
1862 if (m_fn->reserve_op_buffer(2))
1863 return 1;
1864 last_shape_pos= m_fn->get_next_expression_pos();
1865 m_fn->add_operation(buffer_op, 0);
1866 m_npoints= 0;
1867 int_start_line();
1868 return 0;
1869 }
1870
1871
start_poly()1872 int Item_func_buffer::Transporter::start_poly()
1873 {
1874 m_nshapes= 1;
1875
1876 if (m_fn->reserve_op_buffer(2))
1877 return 1;
1878 last_shape_pos= m_fn->get_next_expression_pos();
1879 m_fn->add_operation(buffer_op, 0);
1880 return Gcalc_operation_transporter::start_poly();
1881 }
1882
1883
complete_poly()1884 int Item_func_buffer::Transporter::complete_poly()
1885 {
1886 if (Gcalc_operation_transporter::complete_poly())
1887 return 1;
1888 m_fn->add_operands_to_op(last_shape_pos, m_nshapes);
1889 return 0;
1890 }
1891
1892
start_ring()1893 int Item_func_buffer::Transporter::start_ring()
1894 {
1895 m_npoints= 0;
1896 return Gcalc_operation_transporter::start_ring();
1897 }
1898
1899
start_collection(int n_objects)1900 int Item_func_buffer::Transporter::start_collection(int n_objects)
1901 {
1902 if (m_fn->reserve_op_buffer(1))
1903 return 1;
1904 m_fn->add_operation(Gcalc_function::op_union, n_objects);
1905 return 0;
1906 }
1907
1908
add_point(double x,double y)1909 int Item_func_buffer::Transporter::add_point(double x, double y)
1910 {
1911 if (skip_line)
1912 return 0;
1913
1914 if (m_npoints && x == x2 && y == y2)
1915 return 0;
1916
1917 ++m_npoints;
1918
1919 if (m_npoints == 1)
1920 {
1921 x00= x;
1922 y00= y;
1923 }
1924 else if (m_npoints == 2)
1925 {
1926 x01= x;
1927 y01= y;
1928 }
1929 else if (add_edge_buffer(x, y, (m_npoints == 3) && line_started(), false))
1930 return 1;
1931
1932 x1= x2;
1933 y1= y2;
1934 x2= x;
1935 y2= y;
1936
1937 return line_started() ? 0 : Gcalc_operation_transporter::add_point(x, y);
1938 }
1939
1940
complete()1941 int Item_func_buffer::Transporter::complete()
1942 {
1943 if (m_npoints)
1944 {
1945 if (m_npoints == 1)
1946 {
1947 if (add_point_buffer(x2, y2))
1948 return 1;
1949 }
1950 else if (m_npoints == 2)
1951 {
1952 if (add_edge_buffer(x1, y1, true, true))
1953 return 1;
1954 }
1955 else if (line_started())
1956 {
1957 if (add_last_edge_buffer())
1958 return 1;
1959 }
1960 else
1961 {
1962 if (x2 != x00 || y2 != y00)
1963 {
1964 if (add_edge_buffer(x00, y00, false, false))
1965 return 1;
1966 x1= x2;
1967 y1= y2;
1968 x2= x00;
1969 y2= y00;
1970 }
1971 if (add_edge_buffer(x01, y01, false, false))
1972 return 1;
1973 }
1974 }
1975
1976 return 0;
1977 }
1978
1979
complete_line()1980 int Item_func_buffer::Transporter::complete_line()
1981 {
1982 if (!skip_line)
1983 {
1984 if (complete())
1985 return 1;
1986 int_complete_line();
1987 m_fn->add_operands_to_op(last_shape_pos, m_nshapes);
1988 }
1989 skip_line= FALSE;
1990 return 0;
1991 }
1992
1993
complete_ring()1994 int Item_func_buffer::Transporter::complete_ring()
1995 {
1996 return complete() ||
1997 Gcalc_operation_transporter::complete_ring();
1998 }
1999
2000
val_str(String * str_value)2001 String *Item_func_buffer::val_str(String *str_value)
2002 {
2003 DBUG_ENTER("Item_func_buffer::val_str");
2004 DBUG_ASSERT(fixed == 1);
2005 String *obj= args[0]->val_str(str_value);
2006 double dist= args[1]->val_real();
2007 Geometry_buffer buffer;
2008 Geometry *g;
2009 uint32 srid= 0;
2010 String *str_result= NULL;
2011 Transporter trn(&func, &collector, dist);
2012 MBR mbr;
2013 const char *c_end;
2014
2015 null_value= 1;
2016 if (args[0]->null_value || args[1]->null_value ||
2017 !(g= Geometry::construct(&buffer, obj->ptr(), obj->length())) ||
2018 g->get_mbr(&mbr, &c_end))
2019 goto mem_error;
2020
2021 if (dist > 0.0)
2022 mbr.buffer(dist);
2023 else
2024 {
2025 /* This happens when dist is too far negative. */
2026 if (mbr.xmax + dist < mbr.xmin || mbr.ymax + dist < mbr.ymin)
2027 goto return_empty_result;
2028 }
2029
2030 collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax);
2031 /*
2032 If the distance given is 0, the Buffer function is in fact NOOP,
2033 so it's natural just to return the argument1.
2034 Besides, internal calculations here can't handle zero distance anyway.
2035 */
2036 if (fabs(dist) < GIS_ZERO)
2037 {
2038 null_value= 0;
2039 str_result= obj;
2040 goto mem_error;
2041 }
2042
2043 if (g->store_shapes(&trn))
2044 goto mem_error;
2045
2046 collector.prepare_operation();
2047 if (func.alloc_states())
2048 goto mem_error;
2049 operation.init(&func);
2050 operation.killed= (int *) &(current_thd->killed);
2051
2052 if (operation.count_all(&collector) ||
2053 operation.get_result(&res_receiver))
2054 goto mem_error;
2055
2056
2057 return_empty_result:
2058 str_value->set_charset(&my_charset_bin);
2059 if (str_value->reserve(SRID_SIZE, 512))
2060 goto mem_error;
2061 str_value->length(0);
2062 str_value->q_append(srid);
2063
2064 if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
2065 goto mem_error;
2066
2067 null_value= 0;
2068 str_result= str_value;
2069 mem_error:
2070 collector.reset();
2071 func.reset();
2072 res_receiver.reset();
2073 DBUG_RETURN(str_result);
2074 }
2075
2076
val_int()2077 longlong Item_func_isempty::val_int()
2078 {
2079 DBUG_ASSERT(fixed == 1);
2080 String tmp;
2081 String *swkb= args[0]->val_str(&tmp);
2082 Geometry_buffer buffer;
2083
2084 null_value= args[0]->null_value ||
2085 !(Geometry::construct(&buffer, swkb->ptr(), swkb->length()));
2086 return null_value ? 1 : 0;
2087 }
2088
2089
val_int()2090 longlong Item_func_issimple::val_int()
2091 {
2092 String *swkb= args[0]->val_str(&tmp);
2093 Geometry_buffer buffer;
2094 Gcalc_operation_transporter trn(&func, &collector);
2095 Geometry *g;
2096 int result= 1;
2097 MBR mbr;
2098 const char *c_end;
2099
2100 DBUG_ENTER("Item_func_issimple::val_int");
2101 DBUG_ASSERT(fixed == 1);
2102
2103 null_value= 0;
2104 if ((args[0]->null_value ||
2105 !(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length())) ||
2106 g->get_mbr(&mbr, &c_end)))
2107 {
2108 /* We got NULL as an argument. Have to return -1 */
2109 DBUG_RETURN(-1);
2110 }
2111
2112 collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax);
2113
2114 if (g->get_class_info()->m_type_id == Geometry::wkb_point)
2115 DBUG_RETURN(1);
2116
2117 if (g->store_shapes(&trn))
2118 goto mem_error;
2119
2120 collector.prepare_operation();
2121 scan_it.init(&collector);
2122
2123 while (scan_it.more_points())
2124 {
2125 const Gcalc_scan_iterator::event_point *ev, *next_ev;
2126
2127 if (scan_it.step())
2128 goto mem_error;
2129
2130 ev= scan_it.get_events();
2131 if (ev->simple_event())
2132 continue;
2133
2134 next_ev= ev->get_next();
2135 if ((ev->event & (scev_thread | scev_single_point)) && !next_ev)
2136 continue;
2137
2138 if ((ev->event == scev_two_threads) && !next_ev->get_next())
2139 continue;
2140
2141 /* If the first and last points of a curve coincide - that is */
2142 /* an exception to the rule and the line is considered as simple. */
2143 if ((next_ev && !next_ev->get_next()) &&
2144 (ev->event & (scev_thread | scev_end)) &&
2145 (next_ev->event & (scev_thread | scev_end)))
2146 continue;
2147
2148 result= 0;
2149 break;
2150 }
2151
2152 collector.reset();
2153 func.reset();
2154 scan_it.reset();
2155 DBUG_RETURN(result);
2156 mem_error:
2157 null_value= 1;
2158 DBUG_RETURN(0);
2159 }
2160
2161
val_int()2162 longlong Item_func_isclosed::val_int()
2163 {
2164 DBUG_ASSERT(fixed == 1);
2165 String tmp;
2166 String *swkb= args[0]->val_str(&tmp);
2167 Geometry_buffer buffer;
2168 Geometry *geom;
2169 int isclosed= 0; // In case of error
2170
2171 null_value= 0;
2172 if (!swkb ||
2173 args[0]->null_value ||
2174 !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())) ||
2175 geom->is_closed(&isclosed))
2176 {
2177 /* IsClosed(NULL) should return -1 */
2178 return -1;
2179 }
2180
2181 return (longlong) isclosed;
2182 }
2183
2184
val_int()2185 longlong Item_func_isring::val_int()
2186 {
2187 /* It's actually a combination of two functions - IsClosed and IsSimple */
2188 DBUG_ASSERT(fixed == 1);
2189 String tmp;
2190 String *swkb= args[0]->val_str(&tmp);
2191 Geometry_buffer buffer;
2192 Geometry *geom;
2193 int isclosed= 0; // In case of error
2194
2195 null_value= 0;
2196 if (!swkb ||
2197 args[0]->null_value ||
2198 !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())) ||
2199 geom->is_closed(&isclosed))
2200 {
2201 /* IsRing(NULL) should return -1 */
2202 return -1;
2203 }
2204
2205 if (!isclosed)
2206 return 0;
2207
2208 return Item_func_issimple::val_int();
2209 }
2210
2211
2212 /*
2213 Numerical functions
2214 */
2215
2216
val_int()2217 longlong Item_func_dimension::val_int()
2218 {
2219 DBUG_ASSERT(fixed == 1);
2220 uint32 dim= 0; // In case of error
2221 String *swkb= args[0]->val_str(&value);
2222 Geometry_buffer buffer;
2223 Geometry *geom;
2224 const char *dummy;
2225
2226 null_value= (!swkb ||
2227 args[0]->null_value ||
2228 !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())) ||
2229 geom->dimension(&dim, &dummy));
2230 return (longlong) dim;
2231 }
2232
2233
val_int()2234 longlong Item_func_numinteriorring::val_int()
2235 {
2236 DBUG_ASSERT(fixed == 1);
2237 uint32 num= 0; // In case of error
2238 String *swkb= args[0]->val_str(&value);
2239 Geometry_buffer buffer;
2240 Geometry *geom;
2241
2242 null_value= (!swkb ||
2243 !(geom= Geometry::construct(&buffer,
2244 swkb->ptr(), swkb->length())) ||
2245 geom->num_interior_ring(&num));
2246 return (longlong) num;
2247 }
2248
2249
val_int()2250 longlong Item_func_numgeometries::val_int()
2251 {
2252 DBUG_ASSERT(fixed == 1);
2253 uint32 num= 0; // In case of errors
2254 String *swkb= args[0]->val_str(&value);
2255 Geometry_buffer buffer;
2256 Geometry *geom;
2257
2258 null_value= (!swkb ||
2259 !(geom= Geometry::construct(&buffer,
2260 swkb->ptr(), swkb->length())) ||
2261 geom->num_geometries(&num));
2262 return (longlong) num;
2263 }
2264
2265
val_int()2266 longlong Item_func_numpoints::val_int()
2267 {
2268 DBUG_ASSERT(fixed == 1);
2269 uint32 num= 0; // In case of errors
2270 String *swkb= args[0]->val_str(&value);
2271 Geometry_buffer buffer;
2272 Geometry *geom;
2273
2274 null_value= (!swkb ||
2275 args[0]->null_value ||
2276 !(geom= Geometry::construct(&buffer,
2277 swkb->ptr(), swkb->length())) ||
2278 geom->num_points(&num));
2279 return (longlong) num;
2280 }
2281
2282
val_real()2283 double Item_func_x::val_real()
2284 {
2285 DBUG_ASSERT(fixed == 1);
2286 double res= 0.0; // In case of errors
2287 String *swkb= args[0]->val_str(&value);
2288 Geometry_buffer buffer;
2289 Geometry *geom;
2290
2291 null_value= (!swkb ||
2292 !(geom= Geometry::construct(&buffer,
2293 swkb->ptr(), swkb->length())) ||
2294 geom->get_x(&res));
2295 return res;
2296 }
2297
2298
val_real()2299 double Item_func_y::val_real()
2300 {
2301 DBUG_ASSERT(fixed == 1);
2302 double res= 0; // In case of errors
2303 String *swkb= args[0]->val_str(&value);
2304 Geometry_buffer buffer;
2305 Geometry *geom;
2306
2307 null_value= (!swkb ||
2308 !(geom= Geometry::construct(&buffer,
2309 swkb->ptr(), swkb->length())) ||
2310 geom->get_y(&res));
2311 return res;
2312 }
2313
2314
val_real()2315 double Item_func_area::val_real()
2316 {
2317 DBUG_ASSERT(fixed == 1);
2318 double res= 0; // In case of errors
2319 String *swkb= args[0]->val_str(&value);
2320 Geometry_buffer buffer;
2321 Geometry *geom;
2322 const char *dummy;
2323
2324 null_value= (!swkb ||
2325 !(geom= Geometry::construct(&buffer,
2326 swkb->ptr(), swkb->length())) ||
2327 geom->area(&res, &dummy));
2328 return res;
2329 }
2330
val_real()2331 double Item_func_glength::val_real()
2332 {
2333 DBUG_ASSERT(fixed == 1);
2334 double res= 0; // In case of errors
2335 String *swkb= args[0]->val_str(&value);
2336 Geometry_buffer buffer;
2337 Geometry *geom;
2338 const char *end;
2339
2340 null_value= (!swkb ||
2341 !(geom= Geometry::construct(&buffer,
2342 swkb->ptr(),
2343 swkb->length())) ||
2344 geom->geom_length(&res, &end));
2345 return res;
2346 }
2347
val_int()2348 longlong Item_func_srid::val_int()
2349 {
2350 DBUG_ASSERT(fixed == 1);
2351 String *swkb= args[0]->val_str(&value);
2352 Geometry_buffer buffer;
2353
2354 null_value= (!swkb ||
2355 !Geometry::construct(&buffer,
2356 swkb->ptr(), swkb->length()));
2357 if (null_value)
2358 return 0;
2359
2360 return (longlong) (uint4korr(swkb->ptr()));
2361 }
2362
2363
val_real()2364 double Item_func_distance::val_real()
2365 {
2366 bool cur_point_edge;
2367 const Gcalc_scan_iterator::point *evpos;
2368 const Gcalc_heap::Info *cur_point, *dist_point;
2369 const Gcalc_scan_iterator::event_point *ev;
2370 double t, distance, cur_distance;
2371 double x1, x2, y1, y2;
2372 double ex, ey, vx, vy, e_sqrlen;
2373 uint obj2_si;
2374 Gcalc_operation_transporter trn(&func, &collector);
2375
2376 DBUG_ENTER("Item_func_distance::val_real");
2377 DBUG_ASSERT(fixed == 1);
2378 String *res1= args[0]->val_str(&tmp_value1);
2379 String *res2= args[1]->val_str(&tmp_value2);
2380 Geometry_buffer buffer1, buffer2;
2381 Geometry *g1, *g2;
2382 MBR mbr1, mbr2;
2383 const char *c_end;
2384
2385 if (args[0]->null_value || args[1]->null_value)
2386 goto mem_error;
2387 g1= Geometry::construct(&buffer1, res1->ptr(), res1->length());
2388 if (!g1)
2389 goto mem_error;
2390 g2= Geometry::construct(&buffer2, res2->ptr(), res2->length());
2391 if (!g2)
2392 goto mem_error;
2393 if (g1->get_mbr(&mbr1, &c_end) || g2->get_mbr(&mbr2, &c_end))
2394 goto mem_error;
2395
2396 mbr1.add_mbr(&mbr2);
2397 collector.set_extent(mbr1.xmin, mbr1.xmax, mbr1.ymin, mbr1.ymax);
2398
2399 if ((g1->get_class_info()->m_type_id == Geometry::wkb_point) &&
2400 (g2->get_class_info()->m_type_id == Geometry::wkb_point))
2401 {
2402 if (((Gis_point *) g1)->get_xy(&x1, &y1) ||
2403 ((Gis_point *) g2)->get_xy(&x2, &y2))
2404 goto mem_error;
2405 ex= x2 - x1;
2406 ey= y2 - y1;
2407 DBUG_RETURN(sqrt(ex * ex + ey * ey));
2408 }
2409
2410 if (func.reserve_op_buffer(1))
2411 goto mem_error;
2412 func.add_operation(Gcalc_function::op_intersection, 2);
2413
2414 if (g1->store_shapes(&trn))
2415 goto mem_error;
2416 obj2_si= func.get_nshapes();
2417 if (g2->store_shapes(&trn) || func.alloc_states())
2418 goto mem_error;
2419
2420 if (obj2_si == 0 || func.get_nshapes() == obj2_si)
2421 {
2422 distance= 0.0;
2423 null_value= 1;
2424 goto exit;
2425 }
2426
2427
2428 collector.prepare_operation();
2429 scan_it.init(&collector);
2430
2431 distance= DBL_MAX;
2432 while (scan_it.more_points())
2433 {
2434 if (scan_it.step())
2435 goto mem_error;
2436 evpos= scan_it.get_event_position();
2437 ev= scan_it.get_events();
2438
2439 if (ev->simple_event())
2440 {
2441 cur_point= ev->pi;
2442 goto count_distance;
2443 }
2444 /*
2445 handling intersection we only need to check if it's the intersecion
2446 of objects 1 and 2. In this case distance is 0
2447 */
2448 cur_point= NULL;
2449
2450 /*
2451 having these events we need to check for possible intersection
2452 of objects
2453 scev_thread | scev_two_threads | scev_single_point
2454 */
2455 func.clear_i_states();
2456 for (Gcalc_point_iterator pit(&scan_it); pit.point() != evpos; ++pit)
2457 {
2458 gcalc_shape_info si= pit.point()->get_shape();
2459 if ((func.get_shape_kind(si) == Gcalc_function::shape_polygon))
2460 func.invert_i_state(si);
2461 }
2462
2463 func.clear_b_states();
2464 for (; ev; ev= ev->get_next())
2465 {
2466 if (ev->event != scev_intersection)
2467 cur_point= ev->pi;
2468 func.set_b_state(ev->get_shape());
2469 if (func.count())
2470 {
2471 /* Point of one object is inside the other - intersection found */
2472 distance= 0;
2473 goto exit;
2474 }
2475 }
2476
2477 if (!cur_point)
2478 continue;
2479
2480 count_distance:
2481 if (cur_point->node.shape.shape >= obj2_si)
2482 continue;
2483 cur_point_edge= !cur_point->is_bottom();
2484
2485 for (dist_point= collector.get_first(); dist_point; dist_point= dist_point->get_next())
2486 {
2487 /* We only check vertices of object 2 */
2488 if (dist_point->type != Gcalc_heap::nt_shape_node ||
2489 dist_point->node.shape.shape < obj2_si)
2490 continue;
2491
2492 /* if we have an edge to check */
2493 if (dist_point->node.shape.left)
2494 {
2495 t= count_edge_t(dist_point, dist_point->node.shape.left, cur_point,
2496 ex, ey, vx, vy, e_sqrlen);
2497 if ((t>0.0) && (t<1.0))
2498 {
2499 cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
2500 if (distance > cur_distance)
2501 distance= cur_distance;
2502 }
2503 }
2504 if (cur_point_edge)
2505 {
2506 t= count_edge_t(cur_point, cur_point->node.shape.left, dist_point,
2507 ex, ey, vx, vy, e_sqrlen);
2508 if ((t>0.0) && (t<1.0))
2509 {
2510 cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
2511 if (distance > cur_distance)
2512 distance= cur_distance;
2513 }
2514 }
2515 cur_distance= distance_points(cur_point, dist_point);
2516 if (distance > cur_distance)
2517 distance= cur_distance;
2518 }
2519 }
2520 exit:
2521 collector.reset();
2522 func.reset();
2523 scan_it.reset();
2524 DBUG_RETURN(distance);
2525 mem_error:
2526 null_value= 1;
2527 DBUG_RETURN(0);
2528 }
2529
2530
val_real()2531 double Item_func_sphere_distance::val_real()
2532 {
2533 /* To test null_value of item, first get well-known bytes as a backups */
2534 String bak1, bak2;
2535 String *arg1= args[0]->val_str(&bak1);
2536 String *arg2= args[1]->val_str(&bak2);
2537 double distance= 0.0;
2538 double sphere_radius= 6370986.0; // Default radius equals Earth radius
2539
2540 null_value= (args[0]->null_value || args[1]->null_value);
2541 if (null_value)
2542 {
2543 return 0;
2544 }
2545
2546 if (arg_count == 3)
2547 {
2548 sphere_radius= args[2]->val_real();
2549 // Radius cannot be Null
2550 if (args[2]->null_value)
2551 {
2552 null_value= true;
2553 return 0;
2554 }
2555 if (sphere_radius <= 0)
2556 {
2557 my_error(ER_INTERNAL_ERROR, MYF(0), "Radius must be greater than zero.");
2558 return 1;
2559 }
2560 }
2561 Geometry_buffer buffer1, buffer2;
2562 Geometry *g1, *g2;
2563 if (!(g1= Geometry::construct(&buffer1, arg1->ptr(), arg1->length())) ||
2564 !(g2= Geometry::construct(&buffer2, arg2->ptr(), arg2->length())))
2565 {
2566 my_error(ER_GIS_INVALID_DATA, MYF(0), "ST_Distance_Sphere");
2567 goto handle_errors;
2568 }
2569 // Method allowed for points and multipoints
2570 if (!(g1->get_class_info()->m_type_id == Geometry::wkb_point ||
2571 g1->get_class_info()->m_type_id == Geometry::wkb_multipoint) ||
2572 !(g2->get_class_info()->m_type_id == Geometry::wkb_point ||
2573 g2->get_class_info()->m_type_id == Geometry::wkb_multipoint))
2574 {
2575 // Generate error message in case different geometry is used?
2576 my_error(ER_INTERNAL_ERROR, MYF(0), func_name());
2577 return 0;
2578 }
2579 distance= spherical_distance_points(g1, g2, sphere_radius);
2580 if (distance < 0)
2581 {
2582 my_error(ER_INTERNAL_ERROR, MYF(0), "Returned distance cannot be negative.");
2583 return 1;
2584 }
2585 return distance;
2586
2587 handle_errors:
2588 return 0;
2589 }
2590
2591
spherical_distance_points(Geometry * g1,Geometry * g2,const double r)2592 double Item_func_sphere_distance::spherical_distance_points(Geometry *g1,
2593 Geometry *g2,
2594 const double r)
2595 {
2596 double res= 0.0;
2597 // Length for the single point (25 Bytes)
2598 uint32 len= SRID_SIZE + POINT_DATA_SIZE + WKB_HEADER_SIZE;
2599 int error= 0;
2600
2601 switch (g2->get_class_info()->m_type_id)
2602 {
2603 case Geometry::wkb_point:
2604 // Optimization for point-point case
2605 if (g1->get_class_info()->m_type_id == Geometry::wkb_point)
2606 {
2607 res= static_cast<Gis_point *>(g2)->calculate_haversine(g1, r, &error);
2608 }
2609 else
2610 {
2611 // Optimization for single point in Multipoint
2612 if (g1->get_data_size() == len)
2613 {
2614 res= static_cast<Gis_point *>(g2)->calculate_haversine(g1, r, &error);
2615 }
2616 else
2617 {
2618 // There are multipoints in g1
2619 // g1 is MultiPoint and calculate MP.sphericaldistance from g2 Point
2620 if (g1->get_data_size() != GET_SIZE_ERROR)
2621 static_cast<Gis_point *>(g2)->spherical_distance_multipoints(
2622 (Gis_multi_point *)g1, r, &res, &error);
2623 }
2624 }
2625 break;
2626
2627 case Geometry::wkb_multipoint:
2628 // Optimization for point-point case
2629 if (g1->get_class_info()->m_type_id == Geometry::wkb_point)
2630 {
2631 // Optimization for single point in Multipoint g2
2632 if (g2->get_data_size() == len)
2633 {
2634 res= static_cast<Gis_point *>(g1)->calculate_haversine(g2, r, &error);
2635 }
2636 else
2637 {
2638 if (g2->get_data_size() != GET_SIZE_ERROR)
2639 // g1 is a point (casted to multi_point) and g2 multipoint
2640 static_cast<Gis_point *>(g1)->spherical_distance_multipoints(
2641 (Gis_multi_point *)g2, r, &res, &error);
2642 }
2643 }
2644 else
2645 {
2646 // Multipoints in g1 and g2 - no optimization
2647 static_cast<Gis_multi_point *>(g1)->spherical_distance_multipoints(
2648 (Gis_multi_point *)g2, r, &res, &error);
2649 }
2650 break;
2651
2652 default:
2653 DBUG_ASSERT(0);
2654 break;
2655 }
2656
2657 if (res < 0)
2658 goto handle_error;
2659
2660 handle_error:
2661 if (error > 0)
2662 my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0),
2663 "Longitude should be [-180,180]", "ST_Distance_Sphere");
2664 else if(error < 0)
2665 my_error(ER_STD_OUT_OF_RANGE_ERROR, MYF(0),
2666 "Latitude should be [-90,90]", "ST_Distance_Sphere");
2667 return res;
2668 }
2669
2670
val_str(String * str)2671 String *Item_func_pointonsurface::val_str(String *str)
2672 {
2673 Gcalc_operation_transporter trn(&func, &collector);
2674
2675 DBUG_ENTER("Item_func_pointonsurface::val_str");
2676 DBUG_ASSERT(fixed == 1);
2677 String *res= args[0]->val_str(&tmp_value);
2678 Geometry_buffer buffer;
2679 Geometry *g;
2680 MBR mbr;
2681 const char *c_end;
2682 double UNINIT_VAR(px), UNINIT_VAR(py), x0, UNINIT_VAR(y0);
2683 String *result= 0;
2684 const Gcalc_scan_iterator::point *pprev= NULL;
2685 uint32 srid;
2686
2687 null_value= 1;
2688 if ((args[0]->null_value ||
2689 !(g= Geometry::construct(&buffer, res->ptr(), res->length())) ||
2690 g->get_mbr(&mbr, &c_end)))
2691 goto mem_error;
2692
2693 collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax);
2694
2695 if (g->store_shapes(&trn))
2696 goto mem_error;
2697
2698 collector.prepare_operation();
2699 scan_it.init(&collector);
2700
2701 while (scan_it.more_points())
2702 {
2703 if (scan_it.step())
2704 goto mem_error;
2705
2706 if (scan_it.get_h() > GIS_ZERO)
2707 {
2708 y0= scan_it.get_y();
2709 break;
2710 }
2711 }
2712
2713 if (!scan_it.more_points())
2714 {
2715 goto exit;
2716 }
2717
2718 if (scan_it.step())
2719 goto mem_error;
2720
2721 for (Gcalc_point_iterator pit(&scan_it); pit.point(); ++pit)
2722 {
2723 if (pprev == NULL)
2724 {
2725 pprev= pit.point();
2726 continue;
2727 }
2728 x0= scan_it.get_sp_x(pprev);
2729 px= scan_it.get_sp_x(pit.point());
2730 if (px - x0 > GIS_ZERO)
2731 {
2732 if (scan_it.get_h() > GIS_ZERO)
2733 {
2734 px= (px + x0) / 2.0;
2735 py= scan_it.get_y();
2736 }
2737 else
2738 {
2739 px= (px + x0) / 2.0;
2740 py= (y0 + scan_it.get_y()) / 2.0;
2741 }
2742 null_value= 0;
2743 break;
2744 }
2745 pprev= NULL;
2746 }
2747
2748 if (null_value)
2749 goto exit;
2750
2751 str->set_charset(&my_charset_bin);
2752 if (str->reserve(SRID_SIZE, 512))
2753 goto mem_error;
2754
2755 str->length(0);
2756 srid= uint4korr(res->ptr());
2757 str->q_append(srid);
2758
2759 if (Geometry::create_point(str, px, py))
2760 goto mem_error;
2761
2762 result= str;
2763
2764 exit:
2765 collector.reset();
2766 func.reset();
2767 scan_it.reset();
2768 DBUG_RETURN(result);
2769
2770 mem_error:
2771 collector.reset();
2772 func.reset();
2773 scan_it.reset();
2774 null_value= 1;
2775 DBUG_RETURN(0);
2776 }
2777
2778
get_geometry_type() const2779 Field::geometry_type Item_func_pointonsurface::get_geometry_type() const
2780 {
2781 return Field::GEOM_POINT;
2782 }
2783
2784
2785 #ifndef DBUG_OFF
val_int()2786 longlong Item_func_gis_debug::val_int()
2787 {
2788 /* For now this is just a stub. TODO: implement the internal GIS debuggign */
2789 return 0;
2790 }
2791 #endif
2792
2793 #endif /*HAVE_SPATIAL*/
2794