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