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 02111-1301 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
24static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
25 uchar byte_order, double *mbr);
26static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
27 uchar byte_order, double *mbr);
28static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
29 uchar byte_order, double *mbr);
30static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
31 uchar byte_order, double *mbr);
32static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
33 double *mbr, int top);
34static int sp_mbr_from_wkb(uchar (*wkb), uint size, uint n_dims, double *mbr);
35
36
37/**
38 Create spactial key
39*/
40
41MARIA_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#ifdef HAVE_ISNAN
81 if (isnan(val))
82 {
83 bzero(key, length);
84 key+= length;
85 len+= length;
86 continue;
87 }
88#endif
89
90 if (keyseg->flag & HA_SWAP_KEY)
91 {
92 mi_float8store(key, val);
93 }
94 else
95 {
96 float8store((uchar *)key, val);
97 }
98 key += length;
99 len+= length;
100 }
101 _ma_dpointer(info->s, key, filepos);
102 ret_key->keyinfo= keyinfo;
103 ret_key->data_length= len;
104 ret_key->ref_length= info->s->rec_reflength;
105 ret_key->flag= 0;
106 if (_ma_have_versioning(info) && trid)
107 {
108 ret_key->ref_length+= transid_store_packed(info,
109 key + ret_key->ref_length,
110 trid);
111 }
112 DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, ret_key););
113 DBUG_RETURN(ret_key);
114}
115
116
117/*
118 Calculate minimal bounding rectangle (mbr) of the spatial object
119 stored in "well-known binary representation" (wkb) format.
120*/
121
122static int sp_mbr_from_wkb(uchar *wkb, uint size, uint n_dims, double *mbr)
123{
124 uint i;
125
126 for (i=0; i < n_dims; ++i)
127 {
128 mbr[i * 2] = DBL_MAX;
129 mbr[i * 2 + 1] = -DBL_MAX;
130 }
131
132 return sp_get_geometry_mbr(&wkb, wkb + size, n_dims, mbr, 1);
133}
134
135/*
136 Add one point stored in wkb to mbr
137*/
138
139static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
140 uchar byte_order __attribute__((unused)),
141 double *mbr)
142{
143 double ord;
144 double *mbr_end= mbr + n_dims * 2;
145
146 while (mbr < mbr_end)
147 {
148 if ((*wkb) > end - 8)
149 return -1;
150 float8get(ord, (const uchar*) *wkb);
151 (*wkb)+= 8;
152 if (ord < *mbr)
153 *mbr= ord;
154 mbr++;
155 if (ord > *mbr)
156 *mbr= ord;
157 mbr++;
158 }
159 return 0;
160}
161
162
163static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
164 uchar byte_order, double *mbr)
165{
166 return sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr);
167}
168
169
170static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
171 uchar byte_order, double *mbr)
172{
173 uint n_points;
174
175 n_points = uint4korr(*wkb);
176 (*wkb) += 4;
177 for (; n_points > 0; --n_points)
178 {
179 /* Add next point to mbr */
180 if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
181 return -1;
182 }
183 return 0;
184}
185
186
187static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
188 uchar byte_order, double *mbr)
189{
190 uint n_linear_rings;
191 uint n_points;
192
193 n_linear_rings = uint4korr((*wkb));
194 (*wkb) += 4;
195
196 for (; n_linear_rings > 0; --n_linear_rings)
197 {
198 n_points = uint4korr((*wkb));
199 (*wkb) += 4;
200 for (; n_points > 0; --n_points)
201 {
202 /* Add next point to mbr */
203 if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
204 return -1;
205 }
206 }
207 return 0;
208}
209
210static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
211 double *mbr, int top)
212{
213 int res;
214 uchar byte_order;
215 uint wkb_type;
216
217 byte_order = *(*wkb);
218 ++(*wkb);
219
220 wkb_type = uint4korr((*wkb));
221 (*wkb) += 4;
222
223 switch ((enum wkbType) wkb_type)
224 {
225 case wkbPoint:
226 res = sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr);
227 break;
228 case wkbLineString:
229 res = sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr);
230 break;
231 case wkbPolygon:
232 res = sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr);
233 break;
234 case wkbMultiPoint:
235 {
236 uint n_items;
237 n_items = uint4korr((*wkb));
238 (*wkb) += 4;
239 for (; n_items > 0; --n_items)
240 {
241 byte_order = *(*wkb);
242 ++(*wkb);
243 (*wkb) += 4;
244 if (sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr))
245 return -1;
246 }
247 res = 0;
248 break;
249 }
250 case wkbMultiLineString:
251 {
252 uint n_items;
253 n_items = uint4korr((*wkb));
254 (*wkb) += 4;
255 for (; n_items > 0; --n_items)
256 {
257 byte_order = *(*wkb);
258 ++(*wkb);
259 (*wkb) += 4;
260 if (sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr))
261 return -1;
262 }
263 res = 0;
264 break;
265 }
266 case wkbMultiPolygon:
267 {
268 uint n_items;
269 n_items = uint4korr((*wkb));
270 (*wkb) += 4;
271 for (; n_items > 0; --n_items)
272 {
273 byte_order = *(*wkb);
274 ++(*wkb);
275 (*wkb) += 4;
276 if (sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr))
277 return -1;
278 }
279 res = 0;
280 break;
281 }
282 case wkbGeometryCollection:
283 {
284 uint n_items;
285
286 if (!top)
287 return -1;
288
289 n_items = uint4korr((*wkb));
290 (*wkb) += 4;
291 for (; n_items > 0; --n_items)
292 {
293 if (sp_get_geometry_mbr(wkb, end, n_dims, mbr, 0))
294 return -1;
295 }
296 res = 0;
297 break;
298 }
299 default:
300 res = -1;
301 }
302 return res;
303}
304
305#endif /*HAVE_SPATIAL*/
306