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