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