1 /* Copyright (C) 2006 MySQL AB & Ramil Kalimullin
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
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
15
16 #include "maria_def.h"
17 #include "ma_blockrec.h" /* For ROW_FLAG_TRANSID */
18 #include "trnman.h"
19
20 #ifdef HAVE_SPATIAL
21
22 #include "ma_sp_defs.h"
23
24 static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
25 uchar byte_order, double *mbr);
26 static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
27 uchar byte_order, double *mbr);
28 static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
29 uchar byte_order, double *mbr);
30 static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
31 uchar byte_order, double *mbr);
32 static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
33 double *mbr, int top);
34 static int sp_mbr_from_wkb(uchar (*wkb), uint size, uint n_dims, double *mbr);
35
36
37 /**
38 Create spactial key
39 */
40
_ma_sp_make_key(MARIA_HA * info,MARIA_KEY * ret_key,uint keynr,uchar * key,const uchar * record,my_off_t filepos,ulonglong trid)41 MARIA_KEY *_ma_sp_make_key(MARIA_HA *info, MARIA_KEY *ret_key, uint keynr,
42 uchar *key, const uchar *record, my_off_t filepos,
43 ulonglong trid)
44 {
45 HA_KEYSEG *keyseg;
46 MARIA_KEYDEF *keyinfo = &info->s->keyinfo[keynr];
47 uint len = 0;
48 const uchar *pos;
49 uint dlen;
50 uchar *dptr;
51 double mbr[SPDIMS * 2];
52 uint i;
53 DBUG_ENTER("_ma_sp_make_key");
54
55 keyseg = &keyinfo->seg[-1];
56 pos = record + keyseg->start;
57 ret_key->data= key;
58
59 dlen = _ma_calc_blob_length(keyseg->bit_start, pos);
60 memcpy(&dptr, pos + keyseg->bit_start, sizeof(char*));
61 if (!dptr)
62 {
63 my_errno= HA_ERR_NULL_IN_SPATIAL;
64 DBUG_RETURN(0);
65 }
66
67 sp_mbr_from_wkb(dptr + 4, dlen - 4, SPDIMS, mbr); /* SRID */
68
69 for (i = 0, keyseg = keyinfo->seg; keyseg->type; keyseg++, i++)
70 {
71 uint length = keyseg->length, start= keyseg->start;
72 double val;
73
74 DBUG_ASSERT(length == 8);
75 DBUG_ASSERT(!(start % 8));
76 DBUG_ASSERT(start < sizeof(mbr));
77 DBUG_ASSERT(keyseg->type == HA_KEYTYPE_DOUBLE);
78
79 val= mbr[start / sizeof (double)];
80 if (isnan(val))
81 {
82 bzero(key, length);
83 key+= length;
84 len+= length;
85 continue;
86 }
87
88 if (keyseg->flag & HA_SWAP_KEY)
89 {
90 mi_float8store(key, val);
91 }
92 else
93 {
94 float8store((uchar *)key, val);
95 }
96 key += length;
97 len+= length;
98 }
99 _ma_dpointer(info->s, key, filepos);
100 ret_key->keyinfo= keyinfo;
101 ret_key->data_length= len;
102 ret_key->ref_length= info->s->rec_reflength;
103 ret_key->flag= 0;
104 if (_ma_have_versioning(info) && trid)
105 {
106 ret_key->ref_length+= transid_store_packed(info,
107 key + ret_key->ref_length,
108 trid);
109 }
110 DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, ret_key););
111 DBUG_RETURN(ret_key);
112 }
113
114
115 /*
116 Calculate minimal bounding rectangle (mbr) of the spatial object
117 stored in "well-known binary representation" (wkb) format.
118 */
119
sp_mbr_from_wkb(uchar * wkb,uint size,uint n_dims,double * mbr)120 static int sp_mbr_from_wkb(uchar *wkb, uint size, uint n_dims, double *mbr)
121 {
122 uint i;
123
124 for (i=0; i < n_dims; ++i)
125 {
126 mbr[i * 2] = DBL_MAX;
127 mbr[i * 2 + 1] = -DBL_MAX;
128 }
129
130 return sp_get_geometry_mbr(&wkb, wkb + size, n_dims, mbr, 1);
131 }
132
133 /*
134 Add one point stored in wkb to mbr
135 */
136
sp_add_point_to_mbr(uchar * (* wkb),uchar * end,uint n_dims,uchar byte_order,double * mbr)137 static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
138 uchar byte_order __attribute__((unused)),
139 double *mbr)
140 {
141 double ord;
142 double *mbr_end= mbr + n_dims * 2;
143
144 while (mbr < mbr_end)
145 {
146 if ((*wkb) > end - 8)
147 return -1;
148 float8get(ord, (const uchar*) *wkb);
149 (*wkb)+= 8;
150 if (ord < *mbr)
151 *mbr= ord;
152 mbr++;
153 if (ord > *mbr)
154 *mbr= ord;
155 mbr++;
156 }
157 return 0;
158 }
159
160
sp_get_point_mbr(uchar * (* wkb),uchar * end,uint n_dims,uchar byte_order,double * mbr)161 static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
162 uchar byte_order, double *mbr)
163 {
164 return sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr);
165 }
166
167
sp_get_linestring_mbr(uchar * (* wkb),uchar * end,uint n_dims,uchar byte_order,double * mbr)168 static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
169 uchar byte_order, double *mbr)
170 {
171 uint n_points;
172
173 n_points = uint4korr(*wkb);
174 (*wkb) += 4;
175 for (; n_points > 0; --n_points)
176 {
177 /* Add next point to mbr */
178 if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
179 return -1;
180 }
181 return 0;
182 }
183
184
sp_get_polygon_mbr(uchar * (* wkb),uchar * end,uint n_dims,uchar byte_order,double * mbr)185 static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
186 uchar byte_order, double *mbr)
187 {
188 uint n_linear_rings;
189 uint n_points;
190
191 n_linear_rings = uint4korr((*wkb));
192 (*wkb) += 4;
193
194 for (; n_linear_rings > 0; --n_linear_rings)
195 {
196 n_points = uint4korr((*wkb));
197 (*wkb) += 4;
198 for (; n_points > 0; --n_points)
199 {
200 /* Add next point to mbr */
201 if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
202 return -1;
203 }
204 }
205 return 0;
206 }
207
sp_get_geometry_mbr(uchar * (* wkb),uchar * end,uint n_dims,double * mbr,int top)208 static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
209 double *mbr, int top)
210 {
211 int res;
212 uchar byte_order;
213 uint wkb_type;
214
215 byte_order = *(*wkb);
216 ++(*wkb);
217
218 wkb_type = uint4korr((*wkb));
219 (*wkb) += 4;
220
221 switch ((enum wkbType) wkb_type)
222 {
223 case wkbPoint:
224 res = sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr);
225 break;
226 case wkbLineString:
227 res = sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr);
228 break;
229 case wkbPolygon:
230 res = sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr);
231 break;
232 case wkbMultiPoint:
233 {
234 uint n_items;
235 n_items = uint4korr((*wkb));
236 (*wkb) += 4;
237 for (; n_items > 0; --n_items)
238 {
239 byte_order = *(*wkb);
240 ++(*wkb);
241 (*wkb) += 4;
242 if (sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr))
243 return -1;
244 }
245 res = 0;
246 break;
247 }
248 case wkbMultiLineString:
249 {
250 uint n_items;
251 n_items = uint4korr((*wkb));
252 (*wkb) += 4;
253 for (; n_items > 0; --n_items)
254 {
255 byte_order = *(*wkb);
256 ++(*wkb);
257 (*wkb) += 4;
258 if (sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr))
259 return -1;
260 }
261 res = 0;
262 break;
263 }
264 case wkbMultiPolygon:
265 {
266 uint n_items;
267 n_items = uint4korr((*wkb));
268 (*wkb) += 4;
269 for (; n_items > 0; --n_items)
270 {
271 byte_order = *(*wkb);
272 ++(*wkb);
273 (*wkb) += 4;
274 if (sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr))
275 return -1;
276 }
277 res = 0;
278 break;
279 }
280 case wkbGeometryCollection:
281 {
282 uint n_items;
283
284 if (!top)
285 return -1;
286
287 n_items = uint4korr((*wkb));
288 (*wkb) += 4;
289 for (; n_items > 0; --n_items)
290 {
291 if (sp_get_geometry_mbr(wkb, end, n_dims, mbr, 0))
292 return -1;
293 }
294 res = 0;
295 break;
296 }
297 default:
298 res = -1;
299 }
300 return res;
301 }
302
303 #endif /*HAVE_SPATIAL*/
304