1 /* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
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, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 /* Testing of the basic functions of a MyISAM spatial table */
24 /* Written by Alex Barkov, who has a shared copyright to this code */
25
26 #include "myisam.h"
27
28 #ifdef HAVE_SPATIAL
29 #include "sp_defs.h"
30
31 #define MAX_REC_LENGTH 1024
32 #define KEYALG HA_KEY_ALG_RTREE
33
34 static void create_linestring(uchar *record,uint rownr);
35 static void print_record(uchar * record,my_off_t offs,const char * tail);
36
37 static void create_key(uchar *key,uint rownr);
38 static void print_key(const uchar *key,const char * tail);
39
40 static int run_test(const char *filename);
41 static int read_with_pos(MI_INFO * file, int silent);
42
43 static int rtree_CreateLineStringWKB(double *ords, uint n_dims, uint n_points,
44 uchar *wkb);
45 static void rtree_PrintWKB(uchar *wkb, uint n_dims);
46
47 static char blob_key[MAX_REC_LENGTH];
48
49
main(int argc MY_ATTRIBUTE ((unused)),char * argv[])50 int main(int argc MY_ATTRIBUTE((unused)),char *argv[])
51 {
52 MY_INIT(argv[0]);
53 exit(run_test("sp_test"));
54 }
55
56
run_test(const char * filename)57 int run_test(const char *filename)
58 {
59 MI_INFO *file;
60 MI_UNIQUEDEF uniquedef;
61 MI_CREATE_INFO create_info;
62 MI_COLUMNDEF recinfo[20];
63 MI_KEYDEF keyinfo[20];
64 HA_KEYSEG keyseg[20];
65 key_range min_range, max_range;
66 int silent=0;
67 int create_flag=0;
68 int null_fields=0;
69 int nrecords=30;
70 int uniques=0;
71 int i;
72 int error;
73 int row_count=0;
74 uchar record[MAX_REC_LENGTH];
75 uchar key[MAX_REC_LENGTH];
76 uchar read_record[MAX_REC_LENGTH];
77 int upd=10;
78 ha_rows hrows;
79
80 /* Define a column for NULLs and DEL markers*/
81
82 recinfo[0].type=FIELD_NORMAL;
83 recinfo[0].length=1; /* For NULL bits */
84
85
86 /* Define spatial column */
87
88 recinfo[1].type=FIELD_BLOB;
89 recinfo[1].length=4 + portable_sizeof_char_ptr;
90
91
92
93 /* Define a key with 1 spatial segment */
94
95 keyinfo[0].seg=keyseg;
96 keyinfo[0].keysegs=1;
97 keyinfo[0].flag=HA_SPATIAL;
98 keyinfo[0].key_alg=KEYALG;
99
100 keyinfo[0].seg[0].type= HA_KEYTYPE_BINARY;
101 keyinfo[0].seg[0].flag=0;
102 keyinfo[0].seg[0].start= 1;
103 keyinfo[0].seg[0].length=1; /* Spatial ignores it anyway */
104 keyinfo[0].seg[0].null_bit= null_fields ? 2 : 0;
105 keyinfo[0].seg[0].null_pos=0;
106 keyinfo[0].seg[0].language=default_charset_info->number;
107 keyinfo[0].seg[0].bit_start=4; /* Long BLOB */
108
109
110 if (!silent)
111 printf("- Creating isam-file\n");
112
113 memset(&create_info, 0, sizeof(create_info));
114 create_info.max_rows=10000000;
115
116 if (mi_create(filename,
117 1, /* keys */
118 keyinfo,
119 2, /* columns */
120 recinfo,uniques,&uniquedef,&create_info,create_flag))
121 goto err;
122
123 if (!silent)
124 printf("- Open isam-file\n");
125
126 if (!(file=mi_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
127 goto err;
128
129 if (!silent)
130 printf("- Writing key:s\n");
131
132 for (i=0; i<nrecords; i++ )
133 {
134 create_linestring(record,i);
135 error=mi_write(file,record);
136 print_record(record,mi_position(file),"\n");
137 if (!error)
138 {
139 row_count++;
140 }
141 else
142 {
143 printf("mi_write: %d\n", error);
144 goto err;
145 }
146 }
147
148 if ((error=read_with_pos(file,silent)))
149 goto err;
150
151 if (!silent)
152 printf("- Deleting rows with position\n");
153 for (i=0; i < nrecords/4; i++)
154 {
155 my_errno=0;
156 memset(read_record, 0, MAX_REC_LENGTH);
157 error=mi_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR);
158 if (error)
159 {
160 printf("pos: %2d mi_rrnd: %3d errno: %3d\n",i,error,my_errno);
161 goto err;
162 }
163 print_record(read_record,mi_position(file),"\n");
164 error=mi_delete(file,read_record);
165 if (error)
166 {
167 printf("pos: %2d mi_delete: %3d errno: %3d\n",i,error,my_errno);
168 goto err;
169 }
170 }
171
172 if (!silent)
173 printf("- Updating rows with position\n");
174 for (i=0; i < nrecords/2 ; i++)
175 {
176 my_errno=0;
177 memset(read_record, 0, MAX_REC_LENGTH);
178 error=mi_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR);
179 if (error)
180 {
181 if (error==HA_ERR_RECORD_DELETED)
182 continue;
183 printf("pos: %2d mi_rrnd: %3d errno: %3d\n",i,error,my_errno);
184 goto err;
185 }
186 print_record(read_record,mi_position(file),"");
187 create_linestring(record,i+nrecords*upd);
188 printf("\t-> ");
189 print_record(record,mi_position(file),"\n");
190 error=mi_update(file,read_record,record);
191 if (error)
192 {
193 printf("pos: %2d mi_update: %3d errno: %3d\n",i,error,my_errno);
194 goto err;
195 }
196 }
197
198 if ((error=read_with_pos(file,silent)))
199 goto err;
200
201 if (!silent)
202 printf("- Test mi_rkey then a sequence of mi_rnext_same\n");
203
204 create_key(key, nrecords*4/5);
205 print_key(key," search for INTERSECT\n");
206
207 if ((error=mi_rkey(file,read_record,0,key,0,HA_READ_MBR_INTERSECT)))
208 {
209 printf("mi_rkey: %3d errno: %3d\n",error,my_errno);
210 goto err;
211 }
212 print_record(read_record,mi_position(file)," mi_rkey\n");
213 row_count=1;
214
215 for (;;)
216 {
217 if ((error=mi_rnext_same(file,read_record)))
218 {
219 if (error==HA_ERR_END_OF_FILE)
220 break;
221 printf("mi_next: %3d errno: %3d\n",error,my_errno);
222 goto err;
223 }
224 print_record(read_record,mi_position(file)," mi_rnext_same\n");
225 row_count++;
226 }
227 printf(" %d rows\n",row_count);
228
229 if (!silent)
230 printf("- Test mi_rfirst then a sequence of mi_rnext\n");
231
232 error=mi_rfirst(file,read_record,0);
233 if (error)
234 {
235 printf("mi_rfirst: %3d errno: %3d\n",error,my_errno);
236 goto err;
237 }
238 row_count=1;
239 print_record(read_record,mi_position(file)," mi_frirst\n");
240
241 for(i=0;i<nrecords;i++) {
242 if ((error=mi_rnext(file,read_record,0)))
243 {
244 if (error==HA_ERR_END_OF_FILE)
245 break;
246 printf("mi_next: %3d errno: %3d\n",error,my_errno);
247 goto err;
248 }
249 print_record(read_record,mi_position(file)," mi_rnext\n");
250 row_count++;
251 }
252 printf(" %d rows\n",row_count);
253
254 if (!silent)
255 printf("- Test mi_records_in_range()\n");
256
257 create_key(key, nrecords*upd);
258 print_key(key," INTERSECT\n");
259 min_range.key= key;
260 min_range.length= 1000; /* Big enough */
261 min_range.flag= HA_READ_MBR_INTERSECT;
262 max_range.key= record+1;
263 max_range.length= 1000; /* Big enough */
264 max_range.flag= HA_READ_KEY_EXACT;
265 hrows= mi_records_in_range(file, 0, &min_range, &max_range);
266 printf(" %ld rows\n", (long) hrows);
267
268 if (mi_close(file)) goto err;
269 my_end(MY_CHECK_ERROR);
270 return 0;
271
272 err:
273 printf("got error: %3d when using myisam-database\n",my_errno);
274 return 1; /* skip warning */
275 }
276
277
read_with_pos(MI_INFO * file,int silent)278 static int read_with_pos (MI_INFO * file,int silent)
279 {
280 int error;
281 int i;
282 uchar read_record[MAX_REC_LENGTH];
283 int rows=0;
284
285 if (!silent)
286 printf("- Reading rows with position\n");
287 for (i=0;;i++)
288 {
289 my_errno=0;
290 memset(read_record, 0, MAX_REC_LENGTH);
291 error=mi_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR);
292 if (error)
293 {
294 if (error==HA_ERR_END_OF_FILE)
295 break;
296 if (error==HA_ERR_RECORD_DELETED)
297 continue;
298 printf("pos: %2d mi_rrnd: %3d errno: %3d\n",i,error,my_errno);
299 return error;
300 }
301 rows++;
302 print_record(read_record,mi_position(file),"\n");
303 }
304 printf(" %d rows\n",rows);
305 return 0;
306 }
307
308
print_record(uchar * record,my_off_t offs,const char * tail)309 static void print_record(uchar * record, my_off_t offs,const char * tail)
310 {
311 uchar *pos;
312 char *ptr;
313 uint len;
314
315 printf(" rec=(%d)",(unsigned char)record[0]);
316 pos=record+1;
317 len=sint4korr(pos);
318 pos+=4;
319 printf(" len=%d ",len);
320 memcpy(&ptr, pos, sizeof(char*));
321 if (ptr)
322 rtree_PrintWKB((uchar*) ptr,SPDIMS);
323 else
324 printf("<NULL> ");
325 printf(" offs=%ld ",(long int)offs);
326 printf("%s",tail);
327 }
328
329
create_linestring(uchar * record,uint rownr)330 static void create_linestring(uchar *record,uint rownr)
331 {
332 uint tmp;
333 char *ptr;
334 uchar *pos= record;
335 double x[200];
336 int i,j;
337 int npoints=2;
338
339 for(j=0;j<npoints;j++)
340 for(i=0;i<SPDIMS;i++)
341 x[i+j*SPDIMS]=rownr*j;
342
343 memset(record, 0, MAX_REC_LENGTH);
344 *pos=0x01; /* DEL marker */
345 pos++;
346
347 memset(blob_key,0,sizeof(blob_key));
348 tmp=rtree_CreateLineStringWKB(x,SPDIMS,npoints, (uchar*) blob_key);
349
350 int4store(pos,tmp);
351 pos+=4;
352
353 ptr=blob_key;
354 memcpy(pos, &ptr, sizeof(char*));
355 }
356
357
create_key(uchar * key,uint rownr)358 static void create_key(uchar *key,uint rownr)
359 {
360 double c=rownr;
361 uchar *pos;
362 uint i;
363
364 memset(key, 0, MAX_REC_LENGTH);
365 for (pos=key, i=0; i<2*SPDIMS; i++)
366 {
367 float8store(pos,c);
368 pos+=sizeof(c);
369 }
370 }
371
print_key(const uchar * key,const char * tail)372 static void print_key(const uchar *key,const char * tail)
373 {
374 double c;
375 uint i;
376
377 printf(" key=");
378 for (i=0; i<2*SPDIMS; i++)
379 {
380 float8get(c,key);
381 key+=sizeof(c);
382 printf("%.14g ",c);
383 }
384 printf("%s",tail);
385 }
386
387
rtree_CreateLineStringWKB(double * ords,uint n_dims,uint n_points,uchar * wkb)388 static int rtree_CreateLineStringWKB(double *ords, uint n_dims, uint n_points,
389 uchar *wkb)
390 {
391 uint i;
392 uint n_ords = n_dims * n_points;
393
394 *wkb = wkbXDR;
395 ++wkb;
396 int4store(wkb, wkbLineString);
397 wkb += 4;
398 int4store(wkb, n_points);
399 wkb += 4;
400 for (i=0; i < n_ords; ++i)
401 {
402 float8store(wkb, ords[i]);
403 wkb += 8;
404 }
405 return 9 + n_points * n_dims * 8;
406 }
407
408
rtree_PrintWKB(uchar * wkb,uint n_dims)409 static void rtree_PrintWKB(uchar *wkb, uint n_dims)
410 {
411 uint wkb_type;
412
413 ++wkb;
414 wkb_type = uint4korr(wkb);
415 wkb += 4;
416
417 switch ((enum wkbType)wkb_type)
418 {
419 case wkbPoint:
420 {
421 uint i;
422 double ord;
423
424 printf("POINT(");
425 for (i=0; i < n_dims; ++i)
426 {
427 float8get(ord, wkb);
428 wkb += 8;
429 printf("%.14g", ord);
430 if (i < n_dims - 1)
431 printf(" ");
432 else
433 printf(")");
434 }
435 break;
436 }
437 case wkbLineString:
438 {
439 uint p, i;
440 uint n_points;
441 double ord;
442
443 printf("LineString(");
444 n_points = uint4korr(wkb);
445 wkb += 4;
446 for (p=0; p < n_points; ++p)
447 {
448 for (i=0; i < n_dims; ++i)
449 {
450 float8get(ord, wkb);
451 wkb += 8;
452 printf("%.14g", ord);
453 if (i < n_dims - 1)
454 printf(" ");
455 }
456 if (p < n_points - 1)
457 printf(", ");
458 else
459 printf(")");
460 }
461 break;
462 }
463 case wkbPolygon:
464 {
465 printf("POLYGON(...)");
466 break;
467 }
468 case wkbMultiPoint:
469 {
470 printf("MULTIPOINT(...)");
471 break;
472 }
473 case wkbMultiLineString:
474 {
475 printf("MULTILINESTRING(...)");
476 break;
477 }
478 case wkbMultiPolygon:
479 {
480 printf("MULTIPOLYGON(...)");
481 break;
482 }
483 case wkbGeometryCollection:
484 {
485 printf("GEOMETRYCOLLECTION(...)");
486 break;
487 }
488 default:
489 {
490 printf("UNKNOWN GEOMETRY TYPE");
491 break;
492 }
493 }
494 }
495
496 #else
main(int argc MY_ATTRIBUTE ((unused)),char * argv[]MY_ATTRIBUTE ((unused)))497 int main(int argc MY_ATTRIBUTE((unused)),char *argv[] MY_ATTRIBUTE((unused)))
498 {
499 exit(0);
500 }
501 #endif /*HAVE_SPATIAL*/
502
503 #include "mi_extrafunc.h"
504