1 /* Copyright (c) 2000, 2021, Oracle and/or its affiliates.
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 #include "sp_defs.h"
25
26 static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
27 uchar byte_order, double *mbr);
28 static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
29 uchar byte_order, double *mbr);
30 static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
31 uchar byte_order, double *mbr);
32 static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
33 uchar byte_order, double *mbr);
34 static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
35 double *mbr, int top);
36 static int sp_mbr_from_wkb(uchar (*wkb), uint size, uint n_dims, double *mbr);
37
sp_make_key(MI_INFO * info,uint keynr,uchar * key,const uchar * record,my_off_t filepos)38 uint sp_make_key(MI_INFO *info, uint keynr, uchar *key,
39 const uchar *record, my_off_t filepos)
40 {
41 HA_KEYSEG *keyseg;
42 MI_KEYDEF *keyinfo = &info->s->keyinfo[keynr];
43 uint len = 0;
44 uchar *pos;
45 uint dlen;
46 uchar *dptr;
47 double mbr[SPDIMS * 2];
48 uint i;
49
50 keyseg = &keyinfo->seg[-1];
51 pos = (uchar*)record + keyseg->start;
52
53 dlen = _mi_calc_blob_length(keyseg->bit_start, pos);
54 memcpy(&dptr, pos + keyseg->bit_start, sizeof(char*));
55 if (!dptr)
56 {
57 set_my_errno(HA_ERR_NULL_IN_SPATIAL);
58 return 0;
59 }
60 sp_mbr_from_wkb(dptr + 4, dlen - 4, SPDIMS, mbr); /* SRID */
61
62 for (i = 0, keyseg = keyinfo->seg; keyseg->type; keyseg++, i++)
63 {
64 uint length = keyseg->length, start= keyseg->start;
65 double val;
66
67 assert(length == sizeof(double));
68 assert(!(start % sizeof(double)));
69 assert(start < sizeof(mbr));
70 assert(keyseg->type == HA_KEYTYPE_DOUBLE);
71
72 val= mbr[start / sizeof (double)];
73 if (my_isnan(val))
74 {
75 memset(key, 0, length);
76 key+= length;
77 len+= length;
78 continue;
79 }
80
81 if (keyseg->flag & HA_SWAP_KEY)
82 {
83 uchar buf[sizeof(double)];
84
85 float8store(buf, val);
86 pos= &buf[length];
87 while (pos > buf)
88 *key++ = *--pos;
89 }
90 else
91 {
92 float8store((uchar *)key, val);
93 key += length;
94 }
95 len+= length;
96 }
97 _mi_dpointer(info, key, filepos);
98 return len;
99 }
100
101 /*
102 Calculate minimal bounding rectangle (mbr) of the spatial object
103 stored in "well-known binary representation" (wkb) format.
104 */
sp_mbr_from_wkb(uchar * wkb,uint size,uint n_dims,double * mbr)105 static int sp_mbr_from_wkb(uchar *wkb, uint size, uint n_dims, double *mbr)
106 {
107 uint i;
108
109 for (i=0; i < n_dims; ++i)
110 {
111 mbr[i * 2] = DBL_MAX;
112 mbr[i * 2 + 1] = -DBL_MAX;
113 }
114
115 return sp_get_geometry_mbr(&wkb, wkb + size, n_dims, mbr, 1);
116 }
117
118 /*
119 Add one point stored in wkb to mbr
120 */
121
sp_add_point_to_mbr(uchar * (* wkb),uchar * end,uint n_dims,uchar byte_order MY_ATTRIBUTE ((unused)),double * mbr)122 static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
123 uchar byte_order MY_ATTRIBUTE((unused)),
124 double *mbr)
125 {
126 double ord;
127 double *mbr_end= mbr + n_dims * 2;
128
129 while (mbr < mbr_end)
130 {
131 if ((*wkb) > end - 8)
132 return -1;
133 float8get(&ord, (const uchar*) *wkb);
134 (*wkb)+= 8;
135 if (ord < *mbr)
136 *mbr= ord;
137 mbr++;
138 if (ord > *mbr)
139 *mbr= ord;
140 mbr++;
141 }
142 return 0;
143 }
144
145
sp_get_point_mbr(uchar * (* wkb),uchar * end,uint n_dims,uchar byte_order,double * mbr)146 static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
147 uchar byte_order, double *mbr)
148 {
149 return sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr);
150 }
151
152
sp_get_linestring_mbr(uchar * (* wkb),uchar * end,uint n_dims,uchar byte_order,double * mbr)153 static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
154 uchar byte_order, double *mbr)
155 {
156 uint n_points;
157
158 n_points = uint4korr(*wkb);
159 (*wkb) += 4;
160 for (; n_points > 0; --n_points)
161 {
162 /* Add next point to mbr */
163 if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
164 return -1;
165 }
166 return 0;
167 }
168
169
sp_get_polygon_mbr(uchar * (* wkb),uchar * end,uint n_dims,uchar byte_order,double * mbr)170 static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
171 uchar byte_order, double *mbr)
172 {
173 uint n_linear_rings;
174 uint n_points;
175
176 n_linear_rings = uint4korr((*wkb));
177 (*wkb) += 4;
178
179 for (; n_linear_rings > 0; --n_linear_rings)
180 {
181 n_points = uint4korr((*wkb));
182 (*wkb) += 4;
183 for (; n_points > 0; --n_points)
184 {
185 /* Add next point to mbr */
186 if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
187 return -1;
188 }
189 }
190 return 0;
191 }
192
sp_get_geometry_mbr(uchar * (* wkb),uchar * end,uint n_dims,double * mbr,int top)193 static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
194 double *mbr, int top)
195 {
196 int res;
197 uchar byte_order;
198 uint wkb_type;
199
200 byte_order = *(*wkb);
201 ++(*wkb);
202
203 wkb_type = uint4korr((*wkb));
204 (*wkb) += 4;
205
206 switch ((enum wkbType) wkb_type)
207 {
208 case wkbPoint:
209 res = sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr);
210 break;
211 case wkbLineString:
212 res = sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr);
213 break;
214 case wkbPolygon:
215 res = sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr);
216 break;
217 case wkbMultiPoint:
218 {
219 uint n_items;
220 n_items = uint4korr((*wkb));
221 (*wkb) += 4;
222 for (; n_items > 0; --n_items)
223 {
224 byte_order = *(*wkb);
225 ++(*wkb);
226 (*wkb) += 4;
227 if (sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr))
228 return -1;
229 }
230 res = 0;
231 break;
232 }
233 case wkbMultiLineString:
234 {
235 uint n_items;
236 n_items = uint4korr((*wkb));
237 (*wkb) += 4;
238 for (; n_items > 0; --n_items)
239 {
240 byte_order = *(*wkb);
241 ++(*wkb);
242 (*wkb) += 4;
243 if (sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr))
244 return -1;
245 }
246 res = 0;
247 break;
248 }
249 case wkbMultiPolygon:
250 {
251 uint n_items;
252 n_items = uint4korr((*wkb));
253 (*wkb) += 4;
254 for (; n_items > 0; --n_items)
255 {
256 byte_order = *(*wkb);
257 ++(*wkb);
258 (*wkb) += 4;
259 if (sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr))
260 return -1;
261 }
262 res = 0;
263 break;
264 }
265 case wkbGeometryCollection:
266 {
267 uint n_items;
268
269 if (!top)
270 return -1;
271
272 n_items = uint4korr((*wkb));
273 (*wkb) += 4;
274 for (; n_items > 0; --n_items)
275 {
276 if (sp_get_geometry_mbr(wkb, end, n_dims, mbr, 0))
277 return -1;
278 }
279 res = 0;
280 break;
281 }
282 default:
283 res = -1;
284 }
285 return res;
286 }
287