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