1 /* Copyright (c) 2000, 2016, 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, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #include "myisamdef.h"
24 
25 #ifdef HAVE_SPATIAL
26 
27 #include "sp_defs.h"
28 
29 static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
30                              uchar byte_order, double *mbr);
31 static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
32                            uchar byte_order, double *mbr);
33 static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
34                                 uchar byte_order, double *mbr);
35 static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
36                              uchar byte_order, double *mbr);
37 static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
38                               double *mbr, int top);
39 static int sp_mbr_from_wkb(uchar (*wkb), uint size, uint n_dims, double *mbr);
40 
sp_make_key(MI_INFO * info,uint keynr,uchar * key,const uchar * record,my_off_t filepos)41 uint sp_make_key(MI_INFO *info, uint keynr, uchar *key,
42 		 const uchar *record, my_off_t filepos)
43 {
44   HA_KEYSEG *keyseg;
45   MI_KEYDEF *keyinfo = &info->s->keyinfo[keynr];
46   uint len = 0;
47   uchar *pos;
48   uint dlen;
49   uchar *dptr;
50   double mbr[SPDIMS * 2];
51   uint i;
52 
53   keyseg = &keyinfo->seg[-1];
54   pos = (uchar*)record + keyseg->start;
55 
56   dlen = _mi_calc_blob_length(keyseg->bit_start, pos);
57   memcpy(&dptr, pos + keyseg->bit_start, sizeof(char*));
58   if (!dptr)
59   {
60     my_errno= HA_ERR_NULL_IN_SPATIAL;
61     return 0;
62   }
63   sp_mbr_from_wkb(dptr + 4, dlen - 4, SPDIMS, mbr);	/* SRID */
64 
65   for (i = 0, keyseg = keyinfo->seg; keyseg->type; keyseg++, i++)
66   {
67     uint length = keyseg->length, start= keyseg->start;
68     double val;
69 
70     DBUG_ASSERT(length == sizeof(double));
71     DBUG_ASSERT(!(start % sizeof(double)));
72     DBUG_ASSERT(start < sizeof(mbr));
73     DBUG_ASSERT(keyseg->type == HA_KEYTYPE_DOUBLE);
74 
75     val= mbr[start / sizeof (double)];
76 #ifdef HAVE_ISNAN
77     if (my_isnan(val))
78     {
79       memset(key, 0, length);
80       key+= length;
81       len+= length;
82       continue;
83     }
84 #endif
85 
86     if (keyseg->flag & HA_SWAP_KEY)
87     {
88       uchar buf[sizeof(double)];
89 
90       float8store(buf, val);
91       pos= &buf[length];
92       while (pos > buf)
93         *key++ = *--pos;
94     }
95     else
96     {
97       float8store((uchar *)key, val);
98       key += length;
99     }
100     len+= length;
101   }
102   _mi_dpointer(info, key, filepos);
103   return len;
104 }
105 
106 /*
107 Calculate minimal bounding rectangle (mbr) of the spatial object
108 stored in "well-known binary representation" (wkb) format.
109 */
sp_mbr_from_wkb(uchar * wkb,uint size,uint n_dims,double * mbr)110 static int sp_mbr_from_wkb(uchar *wkb, uint size, uint n_dims, double *mbr)
111 {
112   uint i;
113 
114   for (i=0; i < n_dims; ++i)
115   {
116     mbr[i * 2] = DBL_MAX;
117     mbr[i * 2 + 1] = -DBL_MAX;
118   }
119 
120   return sp_get_geometry_mbr(&wkb, wkb + size, n_dims, mbr, 1);
121 }
122 
123 /*
124   Add one point stored in wkb to mbr
125 */
126 
sp_add_point_to_mbr(uchar * (* wkb),uchar * end,uint n_dims,uchar byte_order MY_ATTRIBUTE ((unused)),double * mbr)127 static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
128 			       uchar byte_order MY_ATTRIBUTE((unused)),
129 			       double *mbr)
130 {
131   double ord;
132   double *mbr_end= mbr + n_dims * 2;
133 
134   while (mbr < mbr_end)
135   {
136     if ((*wkb) > end - 8)
137       return -1;
138     float8get(ord, (const uchar*) *wkb);
139     (*wkb)+= 8;
140     if (ord < *mbr)
141       *mbr= ord;
142     mbr++;
143     if (ord > *mbr)
144       *mbr= ord;
145     mbr++;
146   }
147   return 0;
148 }
149 
150 
sp_get_point_mbr(uchar * (* wkb),uchar * end,uint n_dims,uchar byte_order,double * mbr)151 static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
152                            uchar byte_order, double *mbr)
153 {
154   return sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr);
155 }
156 
157 
sp_get_linestring_mbr(uchar * (* wkb),uchar * end,uint n_dims,uchar byte_order,double * mbr)158 static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
159                                   uchar byte_order, double *mbr)
160 {
161   uint n_points;
162 
163   n_points = uint4korr(*wkb);
164   (*wkb) += 4;
165   for (; n_points > 0; --n_points)
166   {
167     /* Add next point to mbr */
168     if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
169       return -1;
170   }
171   return 0;
172 }
173 
174 
sp_get_polygon_mbr(uchar * (* wkb),uchar * end,uint n_dims,uchar byte_order,double * mbr)175 static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
176                                uchar byte_order, double *mbr)
177 {
178   uint n_linear_rings;
179   uint n_points;
180 
181   n_linear_rings = uint4korr((*wkb));
182   (*wkb) += 4;
183 
184   for (; n_linear_rings > 0; --n_linear_rings)
185   {
186     n_points = uint4korr((*wkb));
187     (*wkb) += 4;
188     for (; n_points > 0; --n_points)
189     {
190       /* Add next point to mbr */
191       if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
192         return -1;
193     }
194   }
195   return 0;
196 }
197 
sp_get_geometry_mbr(uchar * (* wkb),uchar * end,uint n_dims,double * mbr,int top)198 static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
199                               double *mbr, int top)
200 {
201   int res;
202   uchar byte_order;
203   uint wkb_type;
204 
205   byte_order = *(*wkb);
206   ++(*wkb);
207 
208   wkb_type = uint4korr((*wkb));
209   (*wkb) += 4;
210 
211   switch ((enum wkbType) wkb_type)
212   {
213     case wkbPoint:
214       res = sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr);
215       break;
216     case wkbLineString:
217       res = sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr);
218       break;
219     case wkbPolygon:
220       res = sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr);
221       break;
222     case wkbMultiPoint:
223     {
224       uint n_items;
225       n_items = uint4korr((*wkb));
226       (*wkb) += 4;
227       for (; n_items > 0; --n_items)
228       {
229         byte_order = *(*wkb);
230         ++(*wkb);
231         (*wkb) += 4;
232         if (sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr))
233           return -1;
234       }
235       res = 0;
236       break;
237     }
238     case wkbMultiLineString:
239     {
240       uint n_items;
241       n_items = uint4korr((*wkb));
242       (*wkb) += 4;
243       for (; n_items > 0; --n_items)
244       {
245         byte_order = *(*wkb);
246         ++(*wkb);
247         (*wkb) += 4;
248         if (sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr))
249           return -1;
250       }
251       res = 0;
252       break;
253     }
254     case wkbMultiPolygon:
255     {
256       uint n_items;
257       n_items = uint4korr((*wkb));
258       (*wkb) += 4;
259       for (; n_items > 0; --n_items)
260       {
261         byte_order = *(*wkb);
262         ++(*wkb);
263         (*wkb) += 4;
264         if (sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr))
265           return -1;
266       }
267       res = 0;
268       break;
269     }
270     case wkbGeometryCollection:
271     {
272       uint n_items;
273 
274       if (!top)
275         return -1;
276 
277       n_items = uint4korr((*wkb));
278       (*wkb) += 4;
279       for (; n_items > 0; --n_items)
280       {
281         if (sp_get_geometry_mbr(wkb, end, n_dims, mbr, 0))
282           return -1;
283       }
284       res = 0;
285       break;
286     }
287     default:
288       res = -1;
289   }
290   return res;
291 }
292 
293 #endif /*HAVE_SPATIAL*/
294