MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
item_geofunc.cc
Go to the documentation of this file.
1 /* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software Foundation,
14  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
15 
16 
24 #include "sql_priv.h"
25 /*
26  It is necessary to include set_var.h instead of item.h because there
27  are dependencies on include order for set_var.h and item.h. This
28  will be resolved later.
29 */
30 #include "sql_class.h" // THD, set_var.h: THD
31 #include "set_var.h"
32 #ifdef HAVE_SPATIAL
33 #include <m_ctype.h>
34 
35 
36 Field *Item_geometry_func::tmp_table_field(TABLE *t_arg)
37 {
38  Field *result;
39  if ((result= new Field_geom(max_length, maybe_null, item_name.ptr(), t_arg->s,
40  get_geometry_type())))
41  result->init(t_arg);
42  return result;
43 }
44 
45 void Item_geometry_func::fix_length_and_dec()
46 {
47  collation.set(&my_charset_bin);
48  decimals=0;
49  max_length= (uint32) 4294967295U;
50  maybe_null= 1;
51 }
52 
53 
54 String *Item_func_geometry_from_text::val_str(String *str)
55 {
56  DBUG_ASSERT(fixed == 1);
57  Geometry_buffer buffer;
58  String arg_val;
59  String *wkt= args[0]->val_str_ascii(&arg_val);
60 
61  if ((null_value= args[0]->null_value))
62  return 0;
63 
64  Gis_read_stream trs(wkt->charset(), wkt->ptr(), wkt->length());
65  uint32 srid= 0;
66 
67  if ((arg_count == 2) && !args[1]->null_value)
68  srid= (uint32)args[1]->val_int();
69 
70  str->set_charset(&my_charset_bin);
71  if (str->reserve(SRID_SIZE, 512))
72  return 0;
73  str->length(0);
74  str->q_append(srid);
75  if ((null_value= !Geometry::create_from_wkt(&buffer, &trs, str, 0)))
76  return 0;
77  return str;
78 }
79 
80 
81 String *Item_func_geometry_from_wkb::val_str(String *str)
82 {
83  DBUG_ASSERT(fixed == 1);
84  String *wkb;
85  Geometry_buffer buffer;
86  uint32 srid= 0;
87 
88  if (arg_count == 2)
89  {
90  srid= args[1]->val_int();
91  if ((null_value= args[1]->null_value))
92  return 0;
93  }
94 
95  wkb= args[0]->val_str(&tmp_value);
96  if ((null_value= args[0]->null_value))
97  return 0;
98 
99  /*
100  GeometryFromWKB(wkb [,srid]) understands both WKB (without SRID) and
101  Geometry (with SRID) values in the "wkb" argument.
102  In case if a Geometry type value is passed, we assume that the value
103  is well-formed and can directly return it without going through
104  Geometry::create_from_wkb().
105  */
106  if (args[0]->field_type() == MYSQL_TYPE_GEOMETRY)
107  {
108  /*
109  Check if SRID embedded into the Geometry value differs
110  from the SRID value passed in the second argument.
111  */
112  if (wkb->length() < 4 || srid == uint4korr(wkb->ptr()))
113  return wkb; // Do not differ
114  /*
115  Replace SRID to the one passed in the second argument.
116  Note, we cannot replace SRID directly in wkb->ptr(),
117  because wkb can point to some value that we should not touch,
118  e.g. to a SP variable value. So we need to copy to "str".
119  */
120  if ((null_value= str->copy(*wkb)))
121  return 0;
122  str->write_at_position(0, srid);
123  return str;
124  }
125 
126  str->set_charset(&my_charset_bin);
127  if (str->reserve(SRID_SIZE, 512))
128  {
129  null_value= TRUE; /* purecov: inspected */
130  return 0; /* purecov: inspected */
131  }
132  str->length(0);
133  str->q_append(srid);
134  if ((null_value=
135  (args[0]->null_value ||
136  !Geometry::create_from_wkb(&buffer, wkb->ptr(), wkb->length(), str))))
137  return 0;
138  return str;
139 }
140 
141 
142 String *Item_func_as_wkt::val_str_ascii(String *str)
143 {
144  DBUG_ASSERT(fixed == 1);
145  String arg_val;
146  String *swkb= args[0]->val_str(&arg_val);
147  Geometry_buffer buffer;
148  Geometry *geom= NULL;
149 
150  if ((null_value=
151  (args[0]->null_value ||
152  !(geom= Geometry::construct(&buffer, swkb)))))
153  return 0;
154 
155  str->length(0);
156  if ((null_value= geom->as_wkt(str)))
157  return 0;
158 
159  return str;
160 }
161 
162 
163 void Item_func_as_wkt::fix_length_and_dec()
164 {
165  collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
166  max_length=MAX_BLOB_WIDTH;
167  maybe_null= 1;
168 }
169 
170 
171 String *Item_func_as_wkb::val_str(String *str)
172 {
173  DBUG_ASSERT(fixed == 1);
174  String arg_val;
175  String *swkb= args[0]->val_str(&arg_val);
176  Geometry_buffer buffer;
177 
178  if ((null_value=
179  (args[0]->null_value ||
180  !(Geometry::construct(&buffer, swkb)))))
181  return 0;
182 
183  str->copy(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE,
184  &my_charset_bin);
185  return str;
186 }
187 
188 
189 String *Item_func_geometry_type::val_str_ascii(String *str)
190 {
191  DBUG_ASSERT(fixed == 1);
192  String *swkb= args[0]->val_str(str);
193  Geometry_buffer buffer;
194  Geometry *geom= NULL;
195 
196  if ((null_value=
197  (args[0]->null_value ||
198  !(geom= Geometry::construct(&buffer, swkb)))))
199  return 0;
200  /* String will not move */
201  str->copy(geom->get_class_info()->m_name.str,
202  geom->get_class_info()->m_name.length,
203  default_charset());
204  return str;
205 }
206 
207 
208 Field::geometry_type Item_func_envelope::get_geometry_type() const
209 {
210  return Field::GEOM_POLYGON;
211 }
212 
213 
214 String *Item_func_envelope::val_str(String *str)
215 {
216  DBUG_ASSERT(fixed == 1);
217  String arg_val;
218  String *swkb= args[0]->val_str(&arg_val);
219  Geometry_buffer buffer;
220  Geometry *geom= NULL;
221  uint32 srid;
222 
223  if ((null_value=
224  args[0]->null_value ||
225  !(geom= Geometry::construct(&buffer, swkb))))
226  return 0;
227 
228  srid= uint4korr(swkb->ptr());
229  str->set_charset(&my_charset_bin);
230  str->length(0);
231  if (str->reserve(SRID_SIZE, 512))
232  return 0;
233  str->q_append(srid);
234  return (null_value= geom->envelope(str)) ? 0 : str;
235 }
236 
237 
238 Field::geometry_type Item_func_centroid::get_geometry_type() const
239 {
240  return Field::GEOM_POINT;
241 }
242 
243 
244 String *Item_func_centroid::val_str(String *str)
245 {
246  DBUG_ASSERT(fixed == 1);
247  String arg_val;
248  String *swkb= args[0]->val_str(&arg_val);
249  Geometry_buffer buffer;
250  Geometry *geom= NULL;
251  uint32 srid;
252 
253  if ((null_value= args[0]->null_value ||
254  !(geom= Geometry::construct(&buffer, swkb))))
255  return 0;
256 
257  str->set_charset(&my_charset_bin);
258  if (str->reserve(SRID_SIZE, 512))
259  return 0;
260  str->length(0);
261  srid= uint4korr(swkb->ptr());
262  str->q_append(srid);
263 
264  return (null_value= test(geom->centroid(str))) ? 0 : str;
265 }
266 
267 
268 /*
269  Spatial decomposition functions
270 */
271 
272 String *Item_func_spatial_decomp::val_str(String *str)
273 {
274  DBUG_ASSERT(fixed == 1);
275  String arg_val;
276  String *swkb= args[0]->val_str(&arg_val);
277  Geometry_buffer buffer;
278  Geometry *geom= NULL;
279  uint32 srid;
280 
281  if ((null_value=
282  (args[0]->null_value ||
283  !(geom= Geometry::construct(&buffer, swkb)))))
284  return 0;
285 
286  srid= uint4korr(swkb->ptr());
287  str->set_charset(&my_charset_bin);
288  if (str->reserve(SRID_SIZE, 512))
289  goto err;
290  str->length(0);
291  str->q_append(srid);
292  switch (decomp_func) {
293  case SP_STARTPOINT:
294  if (geom->start_point(str))
295  goto err;
296  break;
297 
298  case SP_ENDPOINT:
299  if (geom->end_point(str))
300  goto err;
301  break;
302 
303  case SP_EXTERIORRING:
304  if (geom->exterior_ring(str))
305  goto err;
306  break;
307 
308  default:
309  goto err;
310  }
311  return str;
312 
313 err:
314  null_value= 1;
315  return 0;
316 }
317 
318 
319 String *Item_func_spatial_decomp_n::val_str(String *str)
320 {
321  DBUG_ASSERT(fixed == 1);
322  String arg_val;
323  String *swkb= args[0]->val_str(&arg_val);
324  long n= (long) args[1]->val_int();
325  Geometry_buffer buffer;
326  Geometry *geom= NULL;
327  uint32 srid;
328 
329  if ((null_value=
330  (args[0]->null_value || args[1]->null_value ||
331  !(geom= Geometry::construct(&buffer, swkb)))))
332  return 0;
333 
334  str->set_charset(&my_charset_bin);
335  if (str->reserve(SRID_SIZE, 512))
336  goto err;
337  srid= uint4korr(swkb->ptr());
338  str->length(0);
339  str->q_append(srid);
340  switch (decomp_func_n)
341  {
342  case SP_POINTN:
343  if (geom->point_n(n,str))
344  goto err;
345  break;
346 
347  case SP_GEOMETRYN:
348  if (geom->geometry_n(n,str))
349  goto err;
350  break;
351 
352  case SP_INTERIORRINGN:
353  if (geom->interior_ring_n(n,str))
354  goto err;
355  break;
356 
357  default:
358  goto err;
359  }
360  return str;
361 
362 err:
363  null_value=1;
364  return 0;
365 }
366 
367 
368 /*
369  Functions to concatenate various spatial objects
370 */
371 
372 
373 /*
374 * Concatenate doubles into Point
375 */
376 
377 
378 Field::geometry_type Item_func_point::get_geometry_type() const
379 {
380  return Field::GEOM_POINT;
381 }
382 
383 
384 String *Item_func_point::val_str(String *str)
385 {
386  DBUG_ASSERT(fixed == 1);
387  double x= args[0]->val_real();
388  double y= args[1]->val_real();
389  uint32 srid= 0;
390 
391  if ((null_value= (args[0]->null_value ||
392  args[1]->null_value ||
393  str->realloc(4/*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE * 2))))
394  return 0;
395 
396  str->set_charset(&my_charset_bin);
397  str->length(0);
398  str->q_append(srid);
399  str->q_append((char)Geometry::wkb_ndr);
400  str->q_append((uint32)Geometry::wkb_point);
401  str->q_append(x);
402  str->q_append(y);
403  return str;
404 }
405 
406 
417 String *Item_func_spatial_collection::val_str(String *str)
418 {
419  DBUG_ASSERT(fixed == 1);
420  String arg_value;
421  uint i;
422  uint32 srid= 0;
423 
424  str->set_charset(&my_charset_bin);
425  str->length(0);
426  if (str->reserve(4/*SRID*/ + 1 + 4 + 4, 512))
427  goto err;
428 
429  str->q_append(srid);
430  str->q_append((char) Geometry::wkb_ndr);
431  str->q_append((uint32) coll_type);
432  str->q_append((uint32) arg_count);
433 
434  for (i= 0; i < arg_count; ++i)
435  {
436  String *res= args[i]->val_str(&arg_value);
437  uint32 len;
438  if (args[i]->null_value || ((len= res->length()) < WKB_HEADER_SIZE))
439  goto err;
440 
441  if (coll_type == Geometry::wkb_geometrycollection)
442  {
443  /*
444  In the case of GeometryCollection we don't need any checkings
445  for item types, so just copy them into target collection
446  */
447  if (str->append(res->ptr() + 4/*SRID*/, len - 4/*SRID*/, (uint32) 512))
448  goto err;
449  }
450  else
451  {
452  enum Geometry::wkbType wkb_type;
453  const uint data_offset= 4/*SRID*/ + 1;
454  if (res->length() < data_offset + sizeof(uint32))
455  goto err;
456  const char *data= res->ptr() + data_offset;
457 
458  /*
459  In the case of named collection we must check that items
460  are of specific type, let's do this checking now
461  */
462 
463  wkb_type= (Geometry::wkbType) uint4korr(data);
464  data+= 4;
465  len-= 5 + 4/*SRID*/;
466  if (wkb_type != item_type)
467  goto err;
468 
469  switch (coll_type) {
470  case Geometry::wkb_multipoint:
471  case Geometry::wkb_multilinestring:
472  case Geometry::wkb_multipolygon:
473  if (len < WKB_HEADER_SIZE ||
474  str->append(data-WKB_HEADER_SIZE, len+WKB_HEADER_SIZE, 512))
475  goto err;
476  break;
477 
478  case Geometry::wkb_linestring:
479  if (len < POINT_DATA_SIZE || str->append(data, POINT_DATA_SIZE, 512))
480  goto err;
481  break;
482  case Geometry::wkb_polygon:
483  {
484  uint32 n_points;
485  double x1, y1, x2, y2;
486  const char *org_data= data;
487 
488  if (len < 4)
489  goto err;
490 
491  n_points= uint4korr(data);
492  data+= 4;
493 
494  if (n_points < 2 || len < 4 + n_points * POINT_DATA_SIZE)
495  goto err;
496 
497  float8get(x1, data);
498  data+= SIZEOF_STORED_DOUBLE;
499  float8get(y1, data);
500  data+= SIZEOF_STORED_DOUBLE;
501 
502  data+= (n_points - 2) * POINT_DATA_SIZE;
503 
504  float8get(x2, data);
505  float8get(y2, data + SIZEOF_STORED_DOUBLE);
506 
507  if ((x1 != x2) || (y1 != y2) ||
508  str->append(org_data, len, 512))
509  goto err;
510  }
511  break;
512 
513  default:
514  goto err;
515  }
516  }
517  }
518  if (str->length() > current_thd->variables.max_allowed_packet)
519  {
520  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
521  ER_WARN_ALLOWED_PACKET_OVERFLOWED,
522  ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED),
523  func_name(), current_thd->variables.max_allowed_packet);
524  goto err;
525  }
526 
527  null_value = 0;
528  return str;
529 
530 err:
531  null_value= 1;
532  return 0;
533 }
534 
535 
536 /*
537  Functions for spatial relations
538 */
539 
540 const char *Item_func_spatial_mbr_rel::func_name() const
541 {
542  switch (spatial_rel) {
543  case SP_CONTAINS_FUNC:
544  return "mbrcontains";
545  case SP_WITHIN_FUNC:
546  return "mbrwithin";
547  case SP_EQUALS_FUNC:
548  return "mbrequals";
549  case SP_DISJOINT_FUNC:
550  return "mbrdisjoint";
551  case SP_INTERSECTS_FUNC:
552  return "mbrintersects";
553  case SP_TOUCHES_FUNC:
554  return "mbrtouches";
555  case SP_CROSSES_FUNC:
556  return "mbrcrosses";
557  case SP_OVERLAPS_FUNC:
558  return "mbroverlaps";
559  default:
560  DBUG_ASSERT(0); // Should never happened
561  return "mbrsp_unknown";
562  }
563 }
564 
565 
566 longlong Item_func_spatial_mbr_rel::val_int()
567 {
568  DBUG_ASSERT(fixed == 1);
569  String *res1= args[0]->val_str(&cmp.value1);
570  String *res2= args[1]->val_str(&cmp.value2);
571  Geometry_buffer buffer1, buffer2;
572  Geometry *g1, *g2;
573  MBR mbr1, mbr2;
574 
575  if ((null_value=
576  (args[0]->null_value ||
577  args[1]->null_value ||
578  !(g1= Geometry::construct(&buffer1, res1)) ||
579  !(g2= Geometry::construct(&buffer2, res2)) ||
580  g1->get_mbr(&mbr1) ||
581  g2->get_mbr(&mbr2))))
582  return 0;
583 
584  switch (spatial_rel) {
585  case SP_CONTAINS_FUNC:
586  return mbr1.contains(&mbr2);
587  case SP_WITHIN_FUNC:
588  return mbr1.within(&mbr2);
589  case SP_EQUALS_FUNC:
590  return mbr1.equals(&mbr2);
591  case SP_DISJOINT_FUNC:
592  return mbr1.disjoint(&mbr2);
593  case SP_INTERSECTS_FUNC:
594  return mbr1.intersects(&mbr2);
595  case SP_TOUCHES_FUNC:
596  return mbr1.touches(&mbr2);
597  case SP_OVERLAPS_FUNC:
598  return mbr1.overlaps(&mbr2);
599  case SP_CROSSES_FUNC:
600  return 0;
601  default:
602  break;
603  }
604 
605  null_value=1;
606  return 0;
607 }
608 
609 
610 Item_func_spatial_rel::Item_func_spatial_rel(Item *a,Item *b,
611  enum Functype sp_rel) :
612  Item_bool_func2(a,b), collector()
613 {
614  spatial_rel = sp_rel;
615 }
616 
617 
618 Item_func_spatial_rel::~Item_func_spatial_rel()
619 {
620 }
621 
622 
623 const char *Item_func_spatial_rel::func_name() const
624 {
625  switch (spatial_rel) {
626  case SP_CONTAINS_FUNC:
627  return "st_contains";
628  case SP_WITHIN_FUNC:
629  return "st_within";
630  case SP_EQUALS_FUNC:
631  return "st_equals";
632  case SP_DISJOINT_FUNC:
633  return "st_disjoint";
634  case SP_INTERSECTS_FUNC:
635  return "st_intersects";
636  case SP_TOUCHES_FUNC:
637  return "st_touches";
638  case SP_CROSSES_FUNC:
639  return "st_crosses";
640  case SP_OVERLAPS_FUNC:
641  return "st_overlaps";
642  default:
643  DBUG_ASSERT(0); // Should never happened
644  return "sp_unknown";
645  }
646 }
647 
648 
649 static double count_edge_t(const Gcalc_heap::Info *ea,
650  const Gcalc_heap::Info *eb,
651  const Gcalc_heap::Info *v,
652  double &ex, double &ey, double &vx, double &vy,
653  double &e_sqrlen)
654 {
655  ex= eb->x - ea->x;
656  ey= eb->y - ea->y;
657  vx= v->x - ea->x;
658  vy= v->y - ea->y;
659  e_sqrlen= ex * ex + ey * ey;
660  return (ex * vx + ey * vy) / e_sqrlen;
661 }
662 
663 
664 static double distance_to_line(double ex, double ey, double vx, double vy,
665  double e_sqrlen)
666 {
667  return fabs(vx * ey - vy * ex) / sqrt(e_sqrlen);
668 }
669 
670 
671 static double distance_points(const Gcalc_heap::Info *a,
672  const Gcalc_heap::Info *b)
673 {
674  double x= a->x - b->x;
675  double y= a->y - b->y;
676  return sqrt(x * x + y * y);
677 }
678 
679 
680 /*
681  Calculates the distance between objects.
682 */
683 
684 static int calc_distance(double *result, Gcalc_heap *collector, uint obj2_si,
685  Gcalc_function *func, Gcalc_scan_iterator *scan_it)
686 {
687  bool cur_point_edge;
688  const Gcalc_scan_iterator::point *evpos;
689  const Gcalc_heap::Info *cur_point, *dist_point;
690  Gcalc_scan_events ev;
691  double t, distance, cur_distance;
692  double ex, ey, vx, vy, e_sqrlen;
693 
694  DBUG_ENTER("calc_distance");
695 
696  distance= DBL_MAX;
697 
698  while (scan_it->more_points())
699  {
700  if (scan_it->step())
701  goto mem_error;
702  evpos= scan_it->get_event_position();
703  ev= scan_it->get_event();
704  cur_point= evpos->pi;
705 
706  /*
707  handling intersection we only need to check if it's the intersecion
708  of objects 1 and 2. In this case distance is 0
709  */
710  if (ev == scev_intersection)
711  {
712  if ((evpos->get_next()->pi->shape >= obj2_si) !=
713  (cur_point->shape >= obj2_si))
714  {
715  distance= 0;
716  goto exit;
717  }
718  continue;
719  }
720 
721  /*
722  if we get 'scev_point | scev_end | scev_two_ends' we don't need
723  to check for intersection of objects.
724  Though we need to calculate distances.
725  */
726  if (ev & (scev_point | scev_end | scev_two_ends))
727  goto calculate_distance;
728 
729  goto calculate_distance;
730  /*
731  having these events we need to check for possible intersection
732  of objects
733  scev_thread | scev_two_threads | scev_single_point
734  */
735  DBUG_ASSERT(ev & (scev_thread | scev_two_threads | scev_single_point));
736 
737  func->clear_state();
738  for (Gcalc_point_iterator pit(scan_it); pit.point() != evpos; ++pit)
739  {
740  gcalc_shape_info si= pit.point()->get_shape();
741  if ((func->get_shape_kind(si) == Gcalc_function::shape_polygon))
742  func->invert_state(si);
743  }
744  func->invert_state(evpos->get_shape());
745  if (func->count())
746  {
747  /* Point of one object is inside the other - intersection found */
748  distance= 0;
749  goto exit;
750  }
751 
752 
753 calculate_distance:
754  if (cur_point->shape >= obj2_si)
755  continue;
756  cur_point_edge= !cur_point->is_bottom();
757 
758  for (dist_point= collector->get_first(); dist_point; dist_point= dist_point->get_next())
759  {
760  /* We only check vertices of object 2 */
761  if (dist_point->shape < obj2_si)
762  continue;
763 
764  /* if we have an edge to check */
765  if (dist_point->left)
766  {
767  t= count_edge_t(dist_point, dist_point->left, cur_point,
768  ex, ey, vx, vy, e_sqrlen);
769  if ((t > 0.0) && (t < 1.0))
770  {
771  cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
772  if (distance > cur_distance)
773  distance= cur_distance;
774  }
775  }
776  if (cur_point_edge)
777  {
778  t= count_edge_t(cur_point, cur_point->left, dist_point,
779  ex, ey, vx, vy, e_sqrlen);
780  if ((t > 0.0) && (t < 1.0))
781  {
782  cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
783  if (distance > cur_distance)
784  distance= cur_distance;
785  }
786  }
787  cur_distance= distance_points(cur_point, dist_point);
788  if (distance > cur_distance)
789  distance= cur_distance;
790  }
791  }
792 
793 exit:
794  *result= distance;
795  DBUG_RETURN(0);
796 
797 mem_error:
798  DBUG_RETURN(1);
799 }
800 
801 
802 #define GIS_ZERO 0.00000000001
803 
804 int Item_func_spatial_rel::func_touches()
805 {
806  double distance= GIS_ZERO;
807  int result= 0;
808  int cur_func= 0;
809 
810  Gcalc_operation_transporter trn(&func, &collector);
811 
812  String *res1= args[0]->val_str(&tmp_value1);
813  String *res2= args[1]->val_str(&tmp_value2);
814  Geometry_buffer buffer1, buffer2;
815  Geometry *g1, *g2;
816  int obj2_si;
817 
818  DBUG_ENTER("Item_func_spatial_rel::func_touches");
819  DBUG_ASSERT(fixed == 1);
820 
821  if ((null_value= (args[0]->null_value || args[1]->null_value ||
822  !(g1= Geometry::construct(&buffer1, res1)) ||
823  !(g2= Geometry::construct(&buffer2, res2)))))
824  goto mem_error;
825 
826  if ((g1->get_class_info()->m_type_id == Geometry::wkb_point) &&
827  (g2->get_class_info()->m_type_id == Geometry::wkb_point))
828  {
829  point_xy p1, p2, e;
830  if (((Gis_point *) g1)->get_xy(&p1) ||
831  ((Gis_point *) g2)->get_xy(&p2))
832  goto mem_error;
833  e.x= p2.x - p1.x;
834  e.y= p2.y - p1.y;
835  DBUG_RETURN((e.x * e.x + e.y * e.y) < GIS_ZERO);
836  }
837 
838  if (func.reserve_op_buffer(1))
839  goto mem_error;
840  func.add_operation(Gcalc_function::op_intersection, 2);
841 
842  if (g1->store_shapes(&trn))
843  goto mem_error;
844  obj2_si= func.get_nshapes();
845 
846  if (g2->store_shapes(&trn) || func.alloc_states())
847  goto mem_error;
848 
849 #ifndef DBUG_OFF
851 #endif
852 
853  collector.prepare_operation();
854  scan_it.init(&collector);
855 
856  if (calc_distance(&distance, &collector, obj2_si, &func, &scan_it))
857  goto mem_error;
858  if (distance > GIS_ZERO)
859  goto exit;
860 
861  scan_it.reset();
862  scan_it.init(&collector);
863 
864  distance= DBL_MAX;
865 
866  while (scan_it.more_trapezoids())
867  {
868  if (scan_it.step())
869  goto mem_error;
870 
871  func.clear_state();
872  for (Gcalc_trapezoid_iterator ti(&scan_it); ti.more(); ++ti)
873  {
874  gcalc_shape_info si= ti.lb()->get_shape();
875  if ((func.get_shape_kind(si) == Gcalc_function::shape_polygon))
876  {
877  func.invert_state(si);
878  cur_func= func.count();
879  }
880  if (cur_func)
881  {
882  double area= scan_it.get_h() *
883  ((ti.rb()->x - ti.lb()->x) + (ti.rt()->x - ti.lt()->x));
884  if (area > GIS_ZERO)
885  {
886  result= 0;
887  goto exit;
888  }
889  }
890  }
891  }
892  result= 1;
893 
894 exit:
895  collector.reset();
896  func.reset();
897  scan_it.reset();
898  DBUG_RETURN(result);
899 mem_error:
900  null_value= 1;
901  DBUG_RETURN(0);
902 }
903 
904 
905 int Item_func_spatial_rel::func_equals()
906 {
907  Gcalc_heap::Info *pi_s1, *pi_s2;
908  Gcalc_heap::Info *cur_pi= collector.get_first();
909  double d;
910 
911  if (!cur_pi)
912  return 1;
913 
914  do {
915  pi_s1= cur_pi;
916  pi_s2= 0;
917  while ((cur_pi= cur_pi->get_next()))
918  {
919  d= fabs(pi_s1->x - cur_pi->x) + fabs(pi_s1->y - cur_pi->y);
920  if (d > GIS_ZERO)
921  break;
922  if (!pi_s2 && pi_s1->shape != cur_pi->shape)
923  pi_s2= cur_pi;
924  }
925 
926  if (!pi_s2)
927  return 0;
928  } while (cur_pi);
929 
930  return 1;
931 }
932 
933 
934 longlong Item_func_spatial_rel::val_int()
935 {
936  DBUG_ENTER("Item_func_spatial_rel::val_int");
937  DBUG_ASSERT(fixed == 1);
938  String *res1;
939  String *res2;
940  Geometry_buffer buffer1, buffer2;
941  Geometry *g1, *g2;
942  int result= 0;
943  int mask= 0;
944 
945  if (spatial_rel == SP_TOUCHES_FUNC)
946  DBUG_RETURN(func_touches());
947 
948  res1= args[0]->val_str(&tmp_value1);
949  res2= args[1]->val_str(&tmp_value2);
950  Gcalc_operation_transporter trn(&func, &collector);
951 
952  if (func.reserve_op_buffer(1))
953  DBUG_RETURN(0);
954 
955  switch (spatial_rel) {
956  case SP_CONTAINS_FUNC:
957  mask= 1;
958  func.add_operation(Gcalc_function::op_backdifference, 2);
959  break;
960  case SP_WITHIN_FUNC:
961  mask= 1;
962  func.add_operation(Gcalc_function::op_difference, 2);
963  break;
964  case SP_EQUALS_FUNC:
965  break;
966  case SP_DISJOINT_FUNC:
967  mask= 1;
968  func.add_operation(Gcalc_function::op_intersection, 2);
969  break;
970  case SP_INTERSECTS_FUNC:
971  func.add_operation(Gcalc_function::op_intersection, 2);
972  break;
973  case SP_OVERLAPS_FUNC:
974  func.add_operation(Gcalc_function::op_backdifference, 2);
975  break;
976  case SP_CROSSES_FUNC:
977  func.add_operation(Gcalc_function::op_intersection, 2);
978  break;
979  default:
980  DBUG_ASSERT(FALSE);
981  break;
982  }
983 
984 
985  if ((null_value=
986  (args[0]->null_value || args[1]->null_value ||
987  !(g1= Geometry::construct(&buffer1, res1)) ||
988  !(g2= Geometry::construct(&buffer2, res2)) ||
989  g1->store_shapes(&trn) || g2->store_shapes(&trn))))
990  goto exit;
991 
992 #ifndef DBUG_OFF
994 #endif
995 
996  collector.prepare_operation();
997  scan_it.init(&collector);
998  /* Note: other functions might be checked here as well. */
999  if (spatial_rel == SP_EQUALS_FUNC ||
1000  spatial_rel == SP_WITHIN_FUNC ||
1001  spatial_rel == SP_CONTAINS_FUNC)
1002  {
1003  result= (g1->get_class_info()->m_type_id == g1->get_class_info()->m_type_id) &&
1004  func_equals();
1005  if (spatial_rel == SP_EQUALS_FUNC ||
1006  result) // for SP_WITHIN_FUNC and SP_CONTAINS_FUNC
1007  goto exit;
1008  }
1009 
1010  if (func.alloc_states())
1011  goto exit;
1012 
1013  result= func.find_function(scan_it) ^ mask;
1014 
1015 exit:
1016  collector.reset();
1017  func.reset();
1018  scan_it.reset();
1019  DBUG_RETURN(result);
1020 }
1021 
1022 
1023 Item_func_spatial_operation::~Item_func_spatial_operation()
1024 {
1025 }
1026 
1027 
1028 String *Item_func_spatial_operation::val_str(String *str_value)
1029 {
1030  DBUG_ENTER("Item_func_spatial_operation::val_str");
1031  DBUG_ASSERT(fixed == 1);
1032  String *res1= args[0]->val_str(&tmp_value1);
1033  String *res2= args[1]->val_str(&tmp_value2);
1034  Geometry_buffer buffer1, buffer2;
1035  Geometry *g1, *g2;
1036  uint32 srid= 0;
1037  Gcalc_operation_transporter trn(&func, &collector);
1038 
1039  if (func.reserve_op_buffer(1))
1040  DBUG_RETURN(0);
1041  func.add_operation(spatial_op, 2);
1042 
1043  null_value= true;
1044  if (args[0]->null_value || args[1]->null_value ||
1045  !(g1= Geometry::construct(&buffer1, res1)) ||
1046  !(g2= Geometry::construct(&buffer2, res2)) ||
1047  g1->store_shapes(&trn) || g2->store_shapes(&trn))
1048  goto exit;
1049 
1050 #ifndef DBUG_OFF
1052 #endif
1053 
1054  collector.prepare_operation();
1055  if (func.alloc_states())
1056  goto exit;
1057 
1058  operation.init(&func);
1059 
1060  if (operation.count_all(&collector) ||
1061  operation.get_result(&res_receiver))
1062  goto exit;
1063 
1064 
1065  str_value->set_charset(&my_charset_bin);
1066  if (str_value->reserve(SRID_SIZE, 512))
1067  goto exit;
1068  str_value->length(0);
1069  str_value->q_append(srid);
1070 
1071  if (!Geometry::create_from_opresult(&buffer1, str_value, res_receiver))
1072  goto exit;
1073 
1074  null_value= false;
1075 
1076 exit:
1077  collector.reset();
1078  func.reset();
1079  res_receiver.reset();
1080  DBUG_RETURN(null_value ? 0 : str_value);
1081 }
1082 
1083 
1084 const char *Item_func_spatial_operation::func_name() const
1085 {
1086  switch (spatial_op) {
1087  case Gcalc_function::op_intersection:
1088  return "st_intersection";
1089  case Gcalc_function::op_difference:
1090  return "st_difference";
1091  case Gcalc_function::op_union:
1092  return "st_union";
1093  case Gcalc_function::op_symdifference:
1094  return "st_symdifference";
1095  default:
1096  DBUG_ASSERT(0); // Should never happen
1097  return "sp_unknown";
1098  }
1099 }
1100 
1101 
1102 static const int SINUSES_CALCULATED= 32;
1103 static double n_sinus[SINUSES_CALCULATED+1]=
1104 {
1105  0,
1106  0.04906767432741802,
1107  0.0980171403295606,
1108  0.1467304744553618,
1109  0.1950903220161283,
1110  0.2429801799032639,
1111  0.2902846772544623,
1112  0.3368898533922201,
1113  0.3826834323650898,
1114  0.4275550934302821,
1115  0.4713967368259976,
1116  0.5141027441932217,
1117  0.5555702330196022,
1118  0.5956993044924334,
1119  0.6343932841636455,
1120  0.6715589548470183,
1121  0.7071067811865475,
1122  0.7409511253549591,
1123  0.773010453362737,
1124  0.8032075314806448,
1125  0.8314696123025452,
1126  0.8577286100002721,
1127  0.8819212643483549,
1128  0.9039892931234433,
1129  0.9238795325112867,
1130  0.9415440651830208,
1131  0.9569403357322089,
1132  0.970031253194544,
1133  0.9807852804032304,
1134  0.989176509964781,
1135  0.9951847266721968,
1136  0.9987954562051724,
1137  1
1138 };
1139 
1140 
1141 static void get_n_sincos(int n, double *sinus, double *cosinus)
1142 {
1143  DBUG_ASSERT(n > 0 && n < SINUSES_CALCULATED*2+1);
1144  if (n < (SINUSES_CALCULATED + 1))
1145  {
1146  *sinus= n_sinus[n];
1147  *cosinus= n_sinus[SINUSES_CALCULATED - n];
1148  }
1149  else
1150  {
1151  n-= SINUSES_CALCULATED;
1152  *sinus= n_sinus[SINUSES_CALCULATED - n];
1153  *cosinus= -n_sinus[n];
1154  }
1155 }
1156 
1157 
1158 static int fill_half_circle(Gcalc_shape_transporter *trn,
1159  Gcalc_shape_status *st,
1160  double x, double y,
1161  double ax, double ay)
1162 {
1163  double n_sin, n_cos;
1164  double x_n, y_n;
1165  for (int n = 1; n < (SINUSES_CALCULATED * 2 - 1); n++)
1166  {
1167  get_n_sincos(n, &n_sin, &n_cos);
1168  x_n= ax * n_cos - ay * n_sin;
1169  y_n= ax * n_sin + ay * n_cos;
1170  if (trn->add_point(st, x_n + x, y_n + y))
1171  return 1;
1172  }
1173  return 0;
1174 }
1175 
1176 
1177 static int fill_gap(Gcalc_shape_transporter *trn,
1178  Gcalc_shape_status *st,
1179  double x, double y,
1180  double ax, double ay, double bx, double by, double d,
1181  bool *empty_gap)
1182 {
1183  double ab= ax * bx + ay * by;
1184  double cosab= ab / (d * d) + GIS_ZERO;
1185  double n_sin, n_cos;
1186  double x_n, y_n;
1187  int n=1;
1188 
1189  *empty_gap= true;
1190  for (;;)
1191  {
1192  get_n_sincos(n++, &n_sin, &n_cos);
1193  if (n_cos <= cosab)
1194  break;
1195  *empty_gap= false;
1196  x_n= ax * n_cos - ay * n_sin;
1197  y_n= ax * n_sin + ay * n_cos;
1198  if (trn->add_point(st, x_n + x, y_n + y))
1199  return 1;
1200  }
1201  return 0;
1202 }
1203 
1204 
1205 /*
1206  Calculates the vector (p2,p1) and
1207  negatively orthogonal to it with the length of d.
1208  The result is (ex,ey) - the vector, (px,py) - the orthogonal.
1209 */
1210 
1211 static void calculate_perpendicular(
1212  double x1, double y1, double x2, double y2, double d,
1213  double *ex, double *ey,
1214  double *px, double *py)
1215 {
1216  double q;
1217  *ex= x1 - x2;
1218  *ey= y1 - y2;
1219  q= d / sqrt((*ex) * (*ex) + (*ey) * (*ey));
1220  *px= (*ey) * q;
1221  *py= -(*ex) * q;
1222 }
1223 
1224 
1225 int Item_func_buffer::Transporter::single_point(Gcalc_shape_status *st,
1226  double x, double y)
1227 {
1228  return add_point_buffer(st, x, y);
1229 }
1230 
1231 
1232 int Item_func_buffer::Transporter::add_edge_buffer(Gcalc_shape_status *st,
1233  double x3, double y3, bool round_p1, bool round_p2)
1234 {
1235  DBUG_PRINT("info", ("Item_func_buffer::Transporter::add_edge_buffer: "
1236  "(%g,%g)(%g,%g)(%g,%g) p1=%d p2=%d",
1237  x1, y1, x2, y2, x3, y3, (int) round_p1, (int) round_p2));
1238 
1239  Gcalc_operation_transporter trn(m_fn, m_heap);
1240  double e1_x, e1_y, e2_x, e2_y, p1_x, p1_y, p2_x, p2_y;
1241  double e1e2;
1242  double sin1, cos1;
1243  double x_n, y_n;
1244  bool empty_gap1, empty_gap2;
1245 
1246  st->m_nshapes++;
1247  Gcalc_shape_status dummy;
1248  if (trn.start_simple_poly(&dummy))
1249  return 1;
1250 
1251  calculate_perpendicular(x1, y1, x2, y2, m_d, &e1_x, &e1_y, &p1_x, &p1_y);
1252  calculate_perpendicular(x3, y3, x2, y2, m_d, &e2_x, &e2_y, &p2_x, &p2_y);
1253 
1254  e1e2= e1_x * e2_y - e2_x * e1_y;
1255  sin1= n_sinus[1];
1256  cos1= n_sinus[31];
1257  if (e1e2 < 0)
1258  {
1259  empty_gap2= false;
1260  x_n= x2 + p2_x * cos1 - p2_y * sin1;
1261  y_n= y2 + p2_y * cos1 + p2_x * sin1;
1262  if (fill_gap(&trn, &dummy, x2, y2, -p1_x,-p1_y, p2_x,p2_y, m_d, &empty_gap1) ||
1263  trn.add_point(&dummy, x2 + p2_x, y2 + p2_y) ||
1264  trn.add_point(&dummy, x_n, y_n))
1265  return 1;
1266  }
1267  else
1268  {
1269  x_n= x2 - p2_x * cos1 - p2_y * sin1;
1270  y_n= y2 - p2_y * cos1 + p2_x * sin1;
1271  if (trn.add_point(&dummy, x_n, y_n) ||
1272  trn.add_point(&dummy, x2 - p2_x, y2 - p2_y) ||
1273  fill_gap(&trn, &dummy, x2, y2, -p2_x, -p2_y, p1_x, p1_y, m_d, &empty_gap2))
1274  return 1;
1275  empty_gap1= false;
1276  }
1277  if ((!empty_gap2 && trn.add_point(&dummy, x2 + p1_x, y2 + p1_y)) ||
1278  trn.add_point(&dummy, x1 + p1_x, y1 + p1_y))
1279  return 1;
1280 
1281  if (round_p1 && fill_half_circle(&trn, &dummy, x1, y1, p1_x, p1_y))
1282  return 1;
1283 
1284  if (trn.add_point(&dummy, x1 - p1_x, y1 - p1_y) ||
1285  (!empty_gap1 && trn.add_point(&dummy, x2 - p1_x, y2 - p1_y)))
1286  return 1;
1287  return trn.complete_simple_poly(&dummy);
1288 }
1289 
1290 
1291 int Item_func_buffer::Transporter::add_last_edge_buffer(Gcalc_shape_status *st)
1292 {
1293  Gcalc_operation_transporter trn(m_fn, m_heap);
1294  Gcalc_shape_status dummy;
1295  double e1_x, e1_y, p1_x, p1_y;
1296 
1297  st->m_nshapes++;
1298  if (trn.start_simple_poly(&dummy))
1299  return 1;
1300 
1301  calculate_perpendicular(x1, y1, x2, y2, m_d, &e1_x, &e1_y, &p1_x, &p1_y);
1302 
1303  if (trn.add_point(&dummy, x1 + p1_x, y1 + p1_y) ||
1304  trn.add_point(&dummy, x1 - p1_x, y1 - p1_y) ||
1305  trn.add_point(&dummy, x2 - p1_x, y2 - p1_y) ||
1306  fill_half_circle(&trn, &dummy, x2, y2, -p1_x, -p1_y) ||
1307  trn.add_point(&dummy, x2 + p1_x, y2 + p1_y))
1308  return 1;
1309  return trn.complete_simple_poly(&dummy);
1310 }
1311 
1312 
1313 int Item_func_buffer::Transporter::add_point_buffer(Gcalc_shape_status *st,
1314  double x, double y)
1315 {
1316  Gcalc_operation_transporter trn(m_fn, m_heap);
1317  Gcalc_shape_status dummy;
1318 
1319  st->m_nshapes++;
1320  if (trn.start_simple_poly(&dummy))
1321  return 1;
1322  if (trn.add_point(&dummy, x - m_d, y) ||
1323  fill_half_circle(&trn, &dummy, x, y, -m_d, 0.0) ||
1324  trn.add_point(&dummy, x + m_d, y) ||
1325  fill_half_circle(&trn, &dummy, x, y, m_d, 0.0))
1326  return 1;
1327  return trn.complete_simple_poly(&dummy);
1328 }
1329 
1330 
1331 int Item_func_buffer::Transporter::start_line(Gcalc_shape_status *st)
1332 {
1333  st->m_nshapes= 0;
1334  if (m_fn->reserve_op_buffer(2))
1335  return 1;
1336  st->m_last_shape_pos= m_fn->get_next_operation_pos();
1337  m_fn->add_operation(m_buffer_op, 0); // Will be set in complete_line()
1338  m_npoints= 0;
1339  int_start_line();
1340  return 0;
1341 }
1342 
1343 
1344 int Item_func_buffer::Transporter::start_poly(Gcalc_shape_status *st)
1345 {
1346  st->m_nshapes= 1;
1347  if (m_fn->reserve_op_buffer(2))
1348  return 1;
1349  st->m_last_shape_pos= m_fn->get_next_operation_pos();
1350  m_fn->add_operation(m_buffer_op, 0); // Will be set in complete_poly()
1351  return Gcalc_operation_transporter::start_poly(st);
1352 }
1353 
1354 
1355 int Item_func_buffer::Transporter::complete_poly(Gcalc_shape_status *st)
1356 {
1357  if (Gcalc_operation_transporter::complete_poly(st))
1358  return 1;
1359  m_fn->add_operands_to_op(st->m_last_shape_pos, st->m_nshapes);
1360  return 0;
1361 }
1362 
1363 
1364 int Item_func_buffer::Transporter::start_ring(Gcalc_shape_status *st)
1365 {
1366  m_npoints= 0;
1367  return Gcalc_operation_transporter::start_ring(st);
1368 }
1369 
1370 
1371 int Item_func_buffer::Transporter::add_point(Gcalc_shape_status *st,
1372  double x, double y)
1373 {
1374  if (m_npoints && x == x2 && y == y2)
1375  return 0;
1376 
1377  ++m_npoints;
1378 
1379  if (m_npoints == 1)
1380  {
1381  x00= x;
1382  y00= y;
1383  }
1384  else if (m_npoints == 2)
1385  {
1386  x01= x;
1387  y01= y;
1388  }
1389  else if (add_edge_buffer(st, x, y, (m_npoints == 3) && line_started(), false))
1390  return 1;
1391 
1392  x1= x2;
1393  y1= y2;
1394  x2= x;
1395  y2= y;
1396 
1397  return line_started() ? 0 : Gcalc_operation_transporter::add_point(st, x, y);
1398 }
1399 
1400 
1401 int Item_func_buffer::Transporter::complete(Gcalc_shape_status *st)
1402 {
1403  if (m_npoints)
1404  {
1405  if (m_npoints == 1)
1406  {
1407  if (add_point_buffer(st, x2, y2))
1408  return 1;
1409  }
1410  else if (m_npoints == 2)
1411  {
1412  if (add_edge_buffer(st, x1, y1, true, true))
1413  return 1;
1414  }
1415  else if (line_started())
1416  {
1417  if (add_last_edge_buffer(st))
1418  return 1;
1419  }
1420  else
1421  {
1422  /*
1423  Add edge only the the most recent coordinate is not
1424  the same to the very first one.
1425  */
1426  if (x2 != x00 || y2 != y00)
1427  {
1428  if (add_edge_buffer(st, x00, y00, false, false))
1429  return 1;
1430  x1= x2;
1431  y1= y2;
1432  x2= x00;
1433  y2= y00;
1434  }
1435  if (add_edge_buffer(st, x01, y01, false, false))
1436  return 1;
1437  }
1438  }
1439 
1440  return 0;
1441 }
1442 
1443 
1444 int Item_func_buffer::Transporter::complete_line(Gcalc_shape_status *st)
1445 {
1446  if (complete(st))
1447  return 1;
1448  int_complete_line();
1449  // Set real number of operands (points) to the operation.
1450  m_fn->add_operands_to_op(st->m_last_shape_pos, st->m_nshapes);
1451  return 0;
1452 }
1453 
1454 
1455 int Item_func_buffer::Transporter::complete_ring(Gcalc_shape_status *st)
1456 {
1457  return complete(st) ||
1458  Gcalc_operation_transporter::complete_ring(st);
1459 }
1460 
1461 
1462 int Item_func_buffer::Transporter::start_collection(Gcalc_shape_status *st,
1463  int n_objects)
1464 {
1465  st->m_nshapes= 0;
1466  st->m_last_shape_pos= m_fn->get_next_operation_pos();
1467  return Gcalc_operation_transporter::start_collection(st, n_objects);
1468 }
1469 
1470 
1471 int Item_func_buffer::Transporter::complete_collection(Gcalc_shape_status *st)
1472 {
1473  Gcalc_operation_transporter::complete_collection(st);
1474  m_fn->set_operands_to_op(st->m_last_shape_pos, st->m_nshapes);
1475  return 0;
1476 }
1477 
1478 
1479 int Item_func_buffer::Transporter::collection_add_item(Gcalc_shape_status
1480  *st_collection,
1482  *st_item)
1483 {
1484  /*
1485  If some collection item created no shapes,
1486  it means it was skipped during transformation by filters
1487  skip_point(), skip_line(), skip_poly().
1488  In this case nothing was added into function_buffer by the item,
1489  so we don't increment shape counter of the owning collection.
1490  */
1491  if (st_item->m_nshapes)
1492  st_collection->m_nshapes++;
1493  return 0;
1494 }
1495 
1496 
1497 String *Item_func_buffer::val_str(String *str_value)
1498 {
1499  DBUG_ENTER("Item_func_buffer::val_str");
1500  DBUG_ASSERT(fixed == 1);
1501  String *obj= args[0]->val_str(&tmp_value);
1502  double dist= args[1]->val_real();
1503  Geometry_buffer buffer;
1504  Geometry *g;
1505  uint32 srid= 0;
1506  String *str_result= NULL;
1507  Transporter trn(&func, &collector, dist);
1508  Gcalc_shape_status st;
1509 
1510  null_value= 1;
1511  if (args[0]->null_value || args[1]->null_value ||
1512  !(g= Geometry::construct(&buffer, obj)))
1513  goto mem_error;
1514 
1515  /*
1516  If distance passed to ST_Buffer is too small, then we return the
1517  original geometry as its buffer. This is needed to avoid division
1518  overflow in buffer calculation, as well as for performance purposes.
1519  */
1520  if (fabs(dist) < GIS_ZERO)
1521  {
1522  null_value= 0;
1523  str_result= obj;
1524  goto mem_error;
1525  }
1526 
1527  if (g->store_shapes(&trn, &st))
1528  goto mem_error;
1529 
1530 #ifndef DBUG_OFF
1532 #endif
1533 
1534  if (st.m_nshapes == 0)
1535  {
1536  /*
1537  Buffer transformation returned empty set.
1538  This is possible with negative buffer distance
1539  if the original geometry consisted of only points and lines
1540  and did not have any polygons.
1541  */
1542  str_value->length(0);
1543  goto mem_error;
1544  }
1545 
1546  collector.prepare_operation();
1547  if (func.alloc_states())
1548  goto mem_error;
1549  operation.init(&func);
1550 
1551  if (operation.count_all(&collector) ||
1552  operation.get_result(&res_receiver))
1553  goto mem_error;
1554 
1555  str_value->set_charset(&my_charset_bin);
1556  if (str_value->reserve(SRID_SIZE, 512))
1557  goto mem_error;
1558  str_value->length(0);
1559  str_value->q_append(srid);
1560 
1561  if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
1562  goto mem_error;
1563 
1564  null_value= 0;
1565  str_result= str_value;
1566 mem_error:
1567  collector.reset();
1568  func.reset();
1569  res_receiver.reset();
1570  DBUG_RETURN(str_result);
1571 }
1572 
1573 
1574 longlong Item_func_isempty::val_int()
1575 {
1576  DBUG_ASSERT(fixed == 1);
1577  String tmp;
1578  String *swkb= args[0]->val_str(&tmp);
1579  Geometry_buffer buffer;
1580 
1581  null_value= args[0]->null_value ||
1582  !(Geometry::construct(&buffer, swkb));
1583  return null_value ? 1 : 0;
1584 }
1585 
1586 
1587 longlong Item_func_issimple::val_int()
1588 {
1589  String *swkb= args[0]->val_str(&tmp);
1590  Geometry_buffer buffer;
1591  Gcalc_operation_transporter trn(&func, &collector);
1592  Geometry *g;
1593  int result= 1;
1594 
1595  DBUG_ENTER("Item_func_issimple::val_int");
1596  DBUG_ASSERT(fixed == 1);
1597 
1598  if ((null_value= args[0]->null_value) ||
1599  !(g= Geometry::construct(&buffer, swkb)))
1600  DBUG_RETURN(0);
1601 
1602 
1603  if (g->get_class_info()->m_type_id == Geometry::wkb_point)
1604  DBUG_RETURN(1);
1605 
1606  if (g->store_shapes(&trn))
1607  goto mem_error;
1608 
1609 #ifndef DBUG_OFF
1611 #endif
1612 
1613  collector.prepare_operation();
1614  scan_it.init(&collector);
1615 
1616  while (scan_it.more_points())
1617  {
1618  if (scan_it.step())
1619  goto mem_error;
1620 
1621  if (scan_it.get_event() == scev_intersection)
1622  {
1623  result= 0;
1624  break;
1625  }
1626  }
1627 
1628  collector.reset();
1629  func.reset();
1630  scan_it.reset();
1631  DBUG_RETURN(result);
1632 mem_error:
1633  null_value= 1;
1634  DBUG_RETURN(0);
1635  return 0;
1636 }
1637 
1638 
1639 longlong Item_func_isclosed::val_int()
1640 {
1641  DBUG_ASSERT(fixed == 1);
1642  String tmp;
1643  String *swkb= args[0]->val_str(&tmp);
1644  Geometry_buffer buffer;
1645  Geometry *geom;
1646  int isclosed= 0; // In case of error
1647 
1648  null_value= (!swkb ||
1649  args[0]->null_value ||
1650  !(geom=
1651  Geometry::construct(&buffer, swkb)) ||
1652  geom->is_closed(&isclosed));
1653 
1654  return (longlong) isclosed;
1655 }
1656 
1657 /*
1658  Numerical functions
1659 */
1660 
1661 
1662 longlong Item_func_dimension::val_int()
1663 {
1664  DBUG_ASSERT(fixed == 1);
1665  uint32 dim= 0; // In case of error
1666  String *swkb= args[0]->val_str(&value);
1667  Geometry_buffer buffer;
1668  Geometry *geom;
1669 
1670  null_value= (!swkb ||
1671  args[0]->null_value ||
1672  !(geom= Geometry::construct(&buffer, swkb)) ||
1673  geom->dimension(&dim));
1674  return (longlong) dim;
1675 }
1676 
1677 
1678 longlong Item_func_numinteriorring::val_int()
1679 {
1680  DBUG_ASSERT(fixed == 1);
1681  uint32 num= 0; // In case of error
1682  String *swkb= args[0]->val_str(&value);
1683  Geometry_buffer buffer;
1684  Geometry *geom;
1685 
1686  null_value= (!swkb ||
1687  !(geom= Geometry::construct(&buffer, swkb)) ||
1688  geom->num_interior_ring(&num));
1689  return (longlong) num;
1690 }
1691 
1692 
1693 longlong Item_func_numgeometries::val_int()
1694 {
1695  DBUG_ASSERT(fixed == 1);
1696  uint32 num= 0; // In case of errors
1697  String *swkb= args[0]->val_str(&value);
1698  Geometry_buffer buffer;
1699  Geometry *geom;
1700 
1701  null_value= (!swkb ||
1702  !(geom= Geometry::construct(&buffer, swkb)) ||
1703  geom->num_geometries(&num));
1704  return (longlong) num;
1705 }
1706 
1707 
1708 longlong Item_func_numpoints::val_int()
1709 {
1710  DBUG_ASSERT(fixed == 1);
1711  uint32 num= 0; // In case of errors
1712  String *swkb= args[0]->val_str(&value);
1713  Geometry_buffer buffer;
1714  Geometry *geom;
1715 
1716  null_value= (!swkb ||
1717  args[0]->null_value ||
1718  !(geom= Geometry::construct(&buffer, swkb)) ||
1719  geom->num_points(&num));
1720  return (longlong) num;
1721 }
1722 
1723 
1724 double Item_func_x::val_real()
1725 {
1726  DBUG_ASSERT(fixed == 1);
1727  double res= 0.0; // In case of errors
1728  String *swkb= args[0]->val_str(&value);
1729  Geometry_buffer buffer;
1730  Geometry *geom;
1731 
1732  null_value= (!swkb ||
1733  !(geom= Geometry::construct(&buffer, swkb)) ||
1734  geom->get_x(&res));
1735  return res;
1736 }
1737 
1738 
1739 double Item_func_y::val_real()
1740 {
1741  DBUG_ASSERT(fixed == 1);
1742  double res= 0; // In case of errors
1743  String *swkb= args[0]->val_str(&value);
1744  Geometry_buffer buffer;
1745  Geometry *geom;
1746 
1747  null_value= (!swkb ||
1748  !(geom= Geometry::construct(&buffer,
1749  swkb->ptr(), swkb->length())) ||
1750  geom->get_y(&res));
1751  return res;
1752 }
1753 
1754 
1755 double Item_func_area::val_real()
1756 {
1757  DBUG_ASSERT(fixed == 1);
1758  double res= 0; // In case of errors
1759  String *swkb= args[0]->val_str(&value);
1760  Geometry_buffer buffer;
1761  Geometry *geom;
1762 
1763  null_value= (!swkb ||
1764  !(geom= Geometry::construct(&buffer, swkb)) ||
1765  geom->area(&res));
1766  return res;
1767 }
1768 
1769 double Item_func_glength::val_real()
1770 {
1771  DBUG_ASSERT(fixed == 1);
1772  double res= 0; // In case of errors
1773  String *swkb= args[0]->val_str(&value);
1774  Geometry_buffer buffer;
1775  Geometry *geom;
1776 
1777  null_value= (!swkb ||
1778  !(geom= Geometry::construct(&buffer, swkb)) ||
1779  geom->geom_length(&res));
1780  return res;
1781 }
1782 
1783 longlong Item_func_srid::val_int()
1784 {
1785  DBUG_ASSERT(fixed == 1);
1786  String *swkb= args[0]->val_str(&value);
1787  Geometry_buffer buffer;
1788 
1789  null_value= (!swkb ||
1790  !Geometry::construct(&buffer, swkb));
1791  if (null_value)
1792  return 0;
1793 
1794  return (longlong) (uint4korr(swkb->ptr()));
1795 }
1796 
1797 
1798 double Item_func_distance::val_real()
1799 {
1800  bool cur_point_edge;
1801  const Gcalc_scan_iterator::point *evpos;
1802  const Gcalc_heap::Info *cur_point, *dist_point;
1803  Gcalc_scan_events ev;
1804  double t, distance, cur_distance;
1805  double ex, ey, vx, vy, e_sqrlen;
1806  uint obj2_si;
1807  Gcalc_operation_transporter trn(&func, &collector);
1808 
1809  DBUG_ENTER("Item_func_distance::val_real");
1810  DBUG_ASSERT(fixed == 1);
1811  String *res1= args[0]->val_str(&tmp_value1);
1812  String *res2= args[1]->val_str(&tmp_value2);
1813  Geometry_buffer buffer1, buffer2;
1814  Geometry *g1, *g2;
1815 
1816  if ((null_value= (args[0]->null_value || args[1]->null_value ||
1817  !(g1= Geometry::construct(&buffer1, res1)) ||
1818  !(g2= Geometry::construct(&buffer2, res2)))))
1819  goto mem_error;
1820 
1821  if ((g1->get_class_info()->m_type_id == Geometry::wkb_point) &&
1822  (g2->get_class_info()->m_type_id == Geometry::wkb_point))
1823  {
1824  point_xy p1, p2;
1825  if (((Gis_point *) g1)->get_xy(&p1) ||
1826  ((Gis_point *) g2)->get_xy(&p2))
1827  goto mem_error;
1828  ex= p2.x - p1.x;
1829  ey= p2.y - p1.y;
1830  DBUG_RETURN(sqrt(ex * ex + ey * ey));
1831  }
1832 
1833  if (func.reserve_op_buffer(1))
1834  goto mem_error;
1835  func.add_operation(Gcalc_function::op_intersection, 2);
1836 
1837  if (g1->store_shapes(&trn))
1838  goto mem_error;
1839  obj2_si= func.get_nshapes();
1840  if (g2->store_shapes(&trn) || func.alloc_states())
1841  goto mem_error;
1842 
1843 #ifndef DBUG_OFF
1845 #endif
1846 
1847  collector.prepare_operation();
1848  scan_it.init(&collector);
1849 
1850  distance= DBL_MAX;
1851  while (scan_it.more_points())
1852  {
1853  if (scan_it.step())
1854  goto mem_error;
1855  evpos= scan_it.get_event_position();
1856  ev= scan_it.get_event();
1857  cur_point= evpos->pi;
1858 
1859  /*
1860  handling intersection we only need to check if it's the intersecion
1861  of objects 1 and 2. In this case distance is 0
1862  */
1863  if (ev == scev_intersection)
1864  {
1865  if ((evpos->get_next()->pi->shape >= obj2_si) !=
1866  (cur_point->shape >= obj2_si))
1867  {
1868  distance= 0;
1869  goto exit;
1870  }
1871  continue;
1872  }
1873 
1874  /*
1875  if we get 'scev_point | scev_end | scev_two_ends' we don't need
1876  to check for intersection of objects.
1877  Though we need to calculate distances.
1878  */
1879  if (ev & (scev_point | scev_end | scev_two_ends))
1880  goto count_distance;
1881 
1882  /*
1883  having these events we need to check for possible intersection
1884  of objects
1885  scev_thread | scev_two_threads | scev_single_point
1886  */
1887  DBUG_ASSERT(ev & (scev_thread | scev_two_threads | scev_single_point));
1888 
1889  func.clear_state();
1890  for (Gcalc_point_iterator pit(&scan_it); pit.point() != evpos; ++pit)
1891  {
1892  gcalc_shape_info si= pit.point()->get_shape();
1893  if ((func.get_shape_kind(si) == Gcalc_function::shape_polygon))
1894  func.invert_state(si);
1895  }
1896  func.invert_state(evpos->get_shape());
1897  if (func.count())
1898  {
1899  /* Point of one object is inside the other - intersection found */
1900  distance= 0;
1901  goto exit;
1902  }
1903 
1904 
1905 count_distance:
1906  if (cur_point->shape >= obj2_si)
1907  continue;
1908  cur_point_edge= !cur_point->is_bottom();
1909 
1910  for (dist_point= collector.get_first(); dist_point; dist_point= dist_point->get_next())
1911  {
1912  /* We only check vertices of object 2 */
1913  if (dist_point->shape < obj2_si)
1914  continue;
1915 
1916  /* if we have an edge to check */
1917  if (dist_point->left)
1918  {
1919  t= count_edge_t(dist_point, dist_point->left, cur_point,
1920  ex, ey, vx, vy, e_sqrlen);
1921  if ((t>0.0) && (t<1.0))
1922  {
1923  cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
1924  if (distance > cur_distance)
1925  distance= cur_distance;
1926  }
1927  }
1928  if (cur_point_edge)
1929  {
1930  t= count_edge_t(cur_point, cur_point->left, dist_point,
1931  ex, ey, vx, vy, e_sqrlen);
1932  if ((t>0.0) && (t<1.0))
1933  {
1934  cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
1935  if (distance > cur_distance)
1936  distance= cur_distance;
1937  }
1938  }
1939  cur_distance= distance_points(cur_point, dist_point);
1940  if (distance > cur_distance)
1941  distance= cur_distance;
1942  }
1943  }
1944 exit:
1945  collector.reset();
1946  func.reset();
1947  scan_it.reset();
1948  DBUG_RETURN(distance);
1949 mem_error:
1950  null_value= 1;
1951  DBUG_RETURN(0);
1952 }
1953 
1954 
1955 #ifndef DBUG_OFF
1956 longlong Item_func_gis_debug::val_int()
1957 {
1958  int val= args[0]->val_int();
1959  if (!args[0]->null_value)
1960  current_thd->set_gis_debug(val);
1961  return current_thd->get_gis_debug();
1962 }
1963 #endif
1964 
1965 
1966 #endif /*HAVE_SPATIAL*/