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 | |
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 | { |
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 | |
122 | static 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 | |
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 | { |
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 | |
163 | static 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 | |
170 | static 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 | |
187 | static 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 | |
210 | static 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 | |