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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 :
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 0 : {
45 : HA_KEYSEG *keyseg;
46 0 : MARIA_KEYDEF *keyinfo = &info->s->keyinfo[keynr];
47 0 : uint len = 0;
48 : const uchar *pos;
49 : uint dlen;
50 : uchar *dptr;
51 : double mbr[SPDIMS * 2];
52 : uint i;
53 0 : DBUG_ENTER("_ma_sp_make_key");
54 :
55 0 : keyseg = &keyinfo->seg[-1];
56 0 : pos = record + keyseg->start;
57 0 : ret_key->data= key;
58 :
59 0 : dlen = _ma_calc_blob_length(keyseg->bit_start, pos);
60 0 : memcpy_fixed(&dptr, pos + keyseg->bit_start, sizeof(char*));
61 0 : if (!dptr)
62 : {
63 0 : my_errno= HA_ERR_NULL_IN_SPATIAL;
64 0 : DBUG_RETURN(0);
65 : }
66 :
67 0 : sp_mbr_from_wkb(dptr + 4, dlen - 4, SPDIMS, mbr); /* SRID */
68 :
69 0 : for (i = 0, keyseg = keyinfo->seg; keyseg->type; keyseg++, i++)
70 : {
71 0 : uint length = keyseg->length, start= keyseg->start;
72 : double val;
73 :
74 0 : DBUG_ASSERT(length == 8);
75 0 : DBUG_ASSERT(!(start % 8));
76 0 : DBUG_ASSERT(start < sizeof(mbr));
77 0 : DBUG_ASSERT(keyseg->type == HA_KEYTYPE_DOUBLE);
78 :
79 0 : val= mbr[start / sizeof (double)];
80 : #ifdef HAVE_ISNAN
81 0 : if (isnan(val))
82 : {
83 0 : bzero(key, length);
84 0 : key+= length;
85 0 : len+= length;
86 0 : continue;
87 : }
88 : #endif
89 :
90 0 : if (keyseg->flag & HA_SWAP_KEY)
91 : {
92 0 : mi_float8store(key, val);
93 : }
94 : else
95 : {
96 0 : float8store((uchar *)key, val);
97 : }
98 0 : key += length;
99 0 : len+= length;
100 : }
101 0 : _ma_dpointer(info->s, key, filepos);
102 0 : ret_key->keyinfo= keyinfo;
103 0 : ret_key->data_length= len;
104 0 : ret_key->ref_length= info->s->rec_reflength;
105 0 : ret_key->flag= 0;
106 0 : if (_ma_have_versioning(info) && trid)
107 : {
108 0 : ret_key->ref_length+= transid_store_packed(info,
109 : key + ret_key->ref_length,
110 : trid);
111 : }
112 0 : DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, ret_key););
113 0 : 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 :
122 : static int sp_mbr_from_wkb(uchar *wkb, uint size, uint n_dims, double *mbr)
123 0 : {
124 : uint i;
125 :
126 0 : for (i=0; i < n_dims; ++i)
127 : {
128 0 : mbr[i * 2] = DBL_MAX;
129 0 : mbr[i * 2 + 1] = -DBL_MAX;
130 : }
131 :
132 0 : 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 :
139 : static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
140 : uchar byte_order __attribute__((unused)),
141 : double *mbr)
142 0 : {
143 : double ord;
144 0 : double *mbr_end= mbr + n_dims * 2;
145 :
146 0 : while (mbr < mbr_end)
147 : {
148 0 : if ((*wkb) > end - 8)
149 0 : return -1;
150 0 : float8get(ord, (const uchar*) *wkb);
151 0 : (*wkb)+= 8;
152 0 : if (ord < *mbr)
153 0 : *mbr= ord;
154 0 : mbr++;
155 0 : if (ord > *mbr)
156 0 : *mbr= ord;
157 0 : mbr++;
158 : }
159 0 : return 0;
160 : }
161 :
162 :
163 : static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
164 : uchar byte_order, double *mbr)
165 0 : {
166 0 : return sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr);
167 : }
168 :
169 :
170 : static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
171 : uchar byte_order, double *mbr)
172 0 : {
173 : uint n_points;
174 :
175 0 : n_points = uint4korr(*wkb);
176 0 : (*wkb) += 4;
177 0 : for (; n_points > 0; --n_points)
178 : {
179 : /* Add next point to mbr */
180 0 : if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
181 0 : return -1;
182 : }
183 0 : return 0;
184 : }
185 :
186 :
187 : static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
188 : uchar byte_order, double *mbr)
189 0 : {
190 : uint n_linear_rings;
191 : uint n_points;
192 :
193 0 : n_linear_rings = uint4korr((*wkb));
194 0 : (*wkb) += 4;
195 :
196 0 : for (; n_linear_rings > 0; --n_linear_rings)
197 : {
198 0 : n_points = uint4korr((*wkb));
199 0 : (*wkb) += 4;
200 0 : for (; n_points > 0; --n_points)
201 : {
202 : /* Add next point to mbr */
203 0 : if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
204 0 : return -1;
205 : }
206 : }
207 0 : return 0;
208 : }
209 :
210 : static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
211 : double *mbr, int top)
212 0 : {
213 : int res;
214 : uchar byte_order;
215 : uint wkb_type;
216 :
217 0 : byte_order = *(*wkb);
218 0 : ++(*wkb);
219 :
220 0 : wkb_type = uint4korr((*wkb));
221 0 : (*wkb) += 4;
222 :
223 0 : switch ((enum wkbType) wkb_type)
224 : {
225 : case wkbPoint:
226 0 : res = sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr);
227 0 : break;
228 : case wkbLineString:
229 0 : res = sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr);
230 0 : break;
231 : case wkbPolygon:
232 0 : res = sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr);
233 0 : break;
234 : case wkbMultiPoint:
235 : {
236 : uint n_items;
237 0 : n_items = uint4korr((*wkb));
238 0 : (*wkb) += 4;
239 0 : for (; n_items > 0; --n_items)
240 : {
241 0 : byte_order = *(*wkb);
242 0 : ++(*wkb);
243 0 : (*wkb) += 4;
244 0 : if (sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr))
245 0 : return -1;
246 : }
247 0 : res = 0;
248 0 : break;
249 : }
250 : case wkbMultiLineString:
251 : {
252 : uint n_items;
253 0 : n_items = uint4korr((*wkb));
254 0 : (*wkb) += 4;
255 0 : for (; n_items > 0; --n_items)
256 : {
257 0 : byte_order = *(*wkb);
258 0 : ++(*wkb);
259 0 : (*wkb) += 4;
260 0 : if (sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr))
261 0 : return -1;
262 : }
263 0 : res = 0;
264 0 : break;
265 : }
266 : case wkbMultiPolygon:
267 : {
268 : uint n_items;
269 0 : n_items = uint4korr((*wkb));
270 0 : (*wkb) += 4;
271 0 : for (; n_items > 0; --n_items)
272 : {
273 0 : byte_order = *(*wkb);
274 0 : ++(*wkb);
275 0 : (*wkb) += 4;
276 0 : if (sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr))
277 0 : return -1;
278 : }
279 0 : res = 0;
280 0 : break;
281 : }
282 : case wkbGeometryCollection:
283 : {
284 : uint n_items;
285 :
286 0 : if (!top)
287 0 : return -1;
288 :
289 0 : n_items = uint4korr((*wkb));
290 0 : (*wkb) += 4;
291 0 : for (; n_items > 0; --n_items)
292 : {
293 0 : if (sp_get_geometry_mbr(wkb, end, n_dims, mbr, 0))
294 0 : return -1;
295 : }
296 0 : res = 0;
297 0 : break;
298 : }
299 : default:
300 0 : res = -1;
301 : }
302 0 : return res;
303 : }
304 :
305 : #endif /*HAVE_SPATIAL*/
|