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