1 | /* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB |
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 | /* Testing of the basic functions of a MARIA spatial table */ |
17 | /* Written by Alex Barkov, who has a shared copyright to this code */ |
18 | |
19 | #include <my_global.h> |
20 | #include "maria.h" |
21 | |
22 | #ifdef HAVE_SPATIAL |
23 | #include "ma_sp_defs.h" |
24 | |
25 | #define MAX_REC_LENGTH 1024 |
26 | #define KEYALG HA_KEY_ALG_RTREE |
27 | |
28 | static void create_linestring(uchar *record,uint rownr); |
29 | static void print_record(uchar * record,my_off_t offs,const char * tail); |
30 | |
31 | static void create_key(uchar *key,uint rownr); |
32 | static void print_key(const uchar *key,const char * tail); |
33 | |
34 | static int run_test(const char *filename); |
35 | static int read_with_pos(MARIA_HA * file, int silent); |
36 | |
37 | static int maria_rtree_CreateLineStringWKB(double *ords, uint n_dims, uint n_points, |
38 | uchar *wkb); |
39 | static void maria_rtree_PrintWKB(uchar *wkb, uint n_dims); |
40 | |
41 | static char blob_key[MAX_REC_LENGTH]; |
42 | |
43 | |
44 | int main(int argc __attribute__((unused)),char *argv[]) |
45 | { |
46 | MY_INIT(argv[0]); |
47 | maria_init(); |
48 | exit(run_test("sp_test" )); |
49 | } |
50 | |
51 | |
52 | int run_test(const char *filename) |
53 | { |
54 | MARIA_HA *file; |
55 | MARIA_UNIQUEDEF uniquedef; |
56 | MARIA_CREATE_INFO create_info; |
57 | MARIA_COLUMNDEF recinfo[20]; |
58 | MARIA_KEYDEF keyinfo[20]; |
59 | HA_KEYSEG keyseg[20]; |
60 | key_range min_range, max_range; |
61 | int silent=0; |
62 | int create_flag=0; |
63 | int null_fields=0; |
64 | int nrecords=30; |
65 | int uniques=0; |
66 | int i; |
67 | int error; |
68 | int row_count=0; |
69 | uchar record[MAX_REC_LENGTH]; |
70 | uchar key[MAX_REC_LENGTH]; |
71 | uchar read_record[MAX_REC_LENGTH]; |
72 | int upd=10; |
73 | ha_rows hrows; |
74 | |
75 | /* Define a column for NULLs and DEL markers*/ |
76 | |
77 | recinfo[0].type=FIELD_NORMAL; |
78 | recinfo[0].length=1; /* For NULL bits */ |
79 | |
80 | |
81 | /* Define spatial column */ |
82 | |
83 | recinfo[1].type=FIELD_BLOB; |
84 | recinfo[1].length=4 + portable_sizeof_char_ptr; |
85 | |
86 | |
87 | |
88 | /* Define a key with 1 spatial segment */ |
89 | |
90 | keyinfo[0].seg=keyseg; |
91 | keyinfo[0].keysegs=1; |
92 | keyinfo[0].flag=HA_SPATIAL; |
93 | keyinfo[0].key_alg=KEYALG; |
94 | |
95 | keyinfo[0].seg[0].type= HA_KEYTYPE_BINARY; |
96 | keyinfo[0].seg[0].flag=0; |
97 | keyinfo[0].seg[0].start= 1; |
98 | keyinfo[0].seg[0].length=1; /* Spatial ignores it anyway */ |
99 | keyinfo[0].seg[0].null_bit= null_fields ? 2 : 0; |
100 | keyinfo[0].seg[0].null_pos=0; |
101 | keyinfo[0].seg[0].language=default_charset_info->number; |
102 | keyinfo[0].seg[0].bit_start=4; /* Long BLOB */ |
103 | |
104 | |
105 | if (!silent) |
106 | printf("- Creating isam-file\n" ); |
107 | |
108 | bzero((char*) &create_info,sizeof(create_info)); |
109 | create_info.max_rows=10000000; |
110 | |
111 | if (maria_create(filename, |
112 | DYNAMIC_RECORD, |
113 | 1, /* keys */ |
114 | keyinfo, |
115 | 2, /* columns */ |
116 | recinfo,uniques,&uniquedef,&create_info,create_flag)) |
117 | goto err; |
118 | |
119 | if (!silent) |
120 | printf("- Open isam-file\n" ); |
121 | |
122 | if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED))) |
123 | goto err; |
124 | |
125 | if (!silent) |
126 | printf("- Writing key:s\n" ); |
127 | |
128 | for (i=0; i<nrecords; i++ ) |
129 | { |
130 | create_linestring(record,i); |
131 | error=maria_write(file,record); |
132 | print_record(record,maria_position(file),"\n" ); |
133 | if (!error) |
134 | { |
135 | row_count++; |
136 | } |
137 | else |
138 | { |
139 | printf("maria_write: %d\n" , error); |
140 | goto err; |
141 | } |
142 | } |
143 | |
144 | if ((error=read_with_pos(file,silent))) |
145 | goto err; |
146 | |
147 | if (!silent) |
148 | printf("- Deleting rows with position\n" ); |
149 | for (i=0; i < nrecords/4; i++) |
150 | { |
151 | my_errno=0; |
152 | bzero((char*) read_record,MAX_REC_LENGTH); |
153 | error=maria_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR); |
154 | if (error) |
155 | { |
156 | printf("pos: %2d maria_rrnd: %3d errno: %3d\n" ,i,error,my_errno); |
157 | goto err; |
158 | } |
159 | print_record(read_record,maria_position(file),"\n" ); |
160 | error=maria_delete(file,read_record); |
161 | if (error) |
162 | { |
163 | printf("pos: %2d maria_delete: %3d errno: %3d\n" ,i,error,my_errno); |
164 | goto err; |
165 | } |
166 | } |
167 | |
168 | if (!silent) |
169 | printf("- Updating rows with position\n" ); |
170 | for (i=0; i < nrecords/2 ; i++) |
171 | { |
172 | my_errno=0; |
173 | bzero((char*) read_record,MAX_REC_LENGTH); |
174 | error=maria_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR); |
175 | if (error) |
176 | { |
177 | if (error==HA_ERR_RECORD_DELETED) |
178 | continue; |
179 | printf("pos: %2d maria_rrnd: %3d errno: %3d\n" ,i,error,my_errno); |
180 | goto err; |
181 | } |
182 | print_record(read_record,maria_position(file),"" ); |
183 | create_linestring(record,i+nrecords*upd); |
184 | printf("\t-> " ); |
185 | print_record(record,maria_position(file),"\n" ); |
186 | error=maria_update(file,read_record,record); |
187 | if (error) |
188 | { |
189 | printf("pos: %2d maria_update: %3d errno: %3d\n" ,i,error,my_errno); |
190 | goto err; |
191 | } |
192 | } |
193 | |
194 | if ((error=read_with_pos(file,silent))) |
195 | goto err; |
196 | |
197 | if (!silent) |
198 | printf("- Test maria_rkey then a sequence of maria_rnext_same\n" ); |
199 | |
200 | create_key(key, nrecords*4/5); |
201 | print_key(key," search for INTERSECT\n" ); |
202 | |
203 | if ((error=maria_rkey(file,read_record,0,key,0,HA_READ_MBR_INTERSECT))) |
204 | { |
205 | printf("maria_rkey: %3d errno: %3d\n" ,error,my_errno); |
206 | goto err; |
207 | } |
208 | print_record(read_record,maria_position(file)," maria_rkey\n" ); |
209 | row_count=1; |
210 | |
211 | for (;;) |
212 | { |
213 | if ((error=maria_rnext_same(file,read_record))) |
214 | { |
215 | if (error==HA_ERR_END_OF_FILE) |
216 | break; |
217 | printf("maria_next: %3d errno: %3d\n" ,error,my_errno); |
218 | goto err; |
219 | } |
220 | print_record(read_record,maria_position(file)," maria_rnext_same\n" ); |
221 | row_count++; |
222 | } |
223 | printf(" %d rows\n" ,row_count); |
224 | |
225 | if (!silent) |
226 | printf("- Test maria_rfirst then a sequence of maria_rnext\n" ); |
227 | |
228 | error=maria_rfirst(file,read_record,0); |
229 | if (error) |
230 | { |
231 | printf("maria_rfirst: %3d errno: %3d\n" ,error,my_errno); |
232 | goto err; |
233 | } |
234 | row_count=1; |
235 | print_record(read_record,maria_position(file)," maria_frirst\n" ); |
236 | |
237 | for(i=0;i<nrecords;i++) { |
238 | if ((error=maria_rnext(file,read_record,0))) |
239 | { |
240 | if (error==HA_ERR_END_OF_FILE) |
241 | break; |
242 | printf("maria_next: %3d errno: %3d\n" ,error,my_errno); |
243 | goto err; |
244 | } |
245 | print_record(read_record,maria_position(file)," maria_rnext\n" ); |
246 | row_count++; |
247 | } |
248 | printf(" %d rows\n" ,row_count); |
249 | |
250 | if (!silent) |
251 | printf("- Test maria_records_in_range()\n" ); |
252 | |
253 | create_key(key, nrecords*upd); |
254 | print_key(key," INTERSECT\n" ); |
255 | min_range.key= key; |
256 | min_range.length= 1000; /* Big enough */ |
257 | min_range.flag= HA_READ_MBR_INTERSECT; |
258 | max_range.key= record+1; |
259 | max_range.length= 1000; /* Big enough */ |
260 | max_range.flag= HA_READ_KEY_EXACT; |
261 | hrows= maria_records_in_range(file,0, &min_range, &max_range); |
262 | printf(" %ld rows\n" , (long) hrows); |
263 | |
264 | if (maria_close(file)) goto err; |
265 | maria_end(); |
266 | my_end(MY_CHECK_ERROR); |
267 | |
268 | return 0; |
269 | |
270 | err: |
271 | printf("got error: %3d when using maria-database\n" ,my_errno); |
272 | maria_end(); |
273 | return 1; /* skip warning */ |
274 | } |
275 | |
276 | |
277 | static int read_with_pos (MARIA_HA * file,int silent) |
278 | { |
279 | int error; |
280 | int i; |
281 | uchar read_record[MAX_REC_LENGTH]; |
282 | int rows=0; |
283 | |
284 | if (!silent) |
285 | printf("- Reading rows with position\n" ); |
286 | for (i=0;;i++) |
287 | { |
288 | my_errno=0; |
289 | bzero((char*) read_record,MAX_REC_LENGTH); |
290 | error=maria_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR); |
291 | if (error) |
292 | { |
293 | if (error==HA_ERR_END_OF_FILE) |
294 | break; |
295 | if (error==HA_ERR_RECORD_DELETED) |
296 | continue; |
297 | printf("pos: %2d maria_rrnd: %3d errno: %3d\n" ,i,error,my_errno); |
298 | return error; |
299 | } |
300 | rows++; |
301 | print_record(read_record,maria_position(file),"\n" ); |
302 | } |
303 | printf(" %d rows\n" ,rows); |
304 | return 0; |
305 | } |
306 | |
307 | |
308 | #ifdef NOT_USED |
309 | static void bprint_record(uchar * record, |
310 | my_off_t offs __attribute__((unused)), |
311 | const char * tail) |
312 | { |
313 | int i; |
314 | char * pos; |
315 | i=(unsigned char)record[0]; |
316 | printf("%02X " ,i); |
317 | |
318 | for( pos=record+1, i=0; i<32; i++,pos++) |
319 | { |
320 | int b=(unsigned char)*pos; |
321 | printf("%02X" ,b); |
322 | } |
323 | printf("%s" ,tail); |
324 | } |
325 | #endif |
326 | |
327 | |
328 | static void print_record(uchar * record, my_off_t offs,const char * tail) |
329 | { |
330 | uchar *pos; |
331 | char *ptr; |
332 | uint len; |
333 | |
334 | printf(" rec=(%d)" ,(unsigned char)record[0]); |
335 | pos=record+1; |
336 | len=sint4korr(pos); |
337 | pos+=4; |
338 | printf(" len=%d " ,len); |
339 | memcpy(&ptr,pos,sizeof(char*)); |
340 | if (ptr) |
341 | maria_rtree_PrintWKB((uchar*) ptr,SPDIMS); |
342 | else |
343 | printf("<NULL> " ); |
344 | printf(" offs=%ld " ,(long int)offs); |
345 | printf("%s" ,tail); |
346 | } |
347 | |
348 | |
349 | #ifdef NOT_USED |
350 | static void create_point(uchar *record,uint rownr) |
351 | { |
352 | uint tmp; |
353 | char *ptr; |
354 | char *pos=record; |
355 | double x[200]; |
356 | int i; |
357 | |
358 | for(i=0;i<SPDIMS;i++) |
359 | x[i]=rownr; |
360 | |
361 | bzero((char*) record,MAX_REC_LENGTH); |
362 | *pos=0x01; /* DEL marker */ |
363 | pos++; |
364 | |
365 | memset(blob_key,0,sizeof(blob_key)); |
366 | tmp=maria_rtree_CreatePointWKB(x,SPDIMS,blob_key); |
367 | |
368 | int4store(pos,tmp); |
369 | pos+=4; |
370 | |
371 | ptr=blob_key; |
372 | memcpy(pos,&ptr,sizeof(char*)); |
373 | } |
374 | #endif |
375 | |
376 | |
377 | static void create_linestring(uchar *record,uint rownr) |
378 | { |
379 | uint tmp; |
380 | char *ptr; |
381 | uchar *pos= record; |
382 | double x[200]; |
383 | int i,j; |
384 | int npoints=2; |
385 | |
386 | for(j=0;j<npoints;j++) |
387 | for(i=0;i<SPDIMS;i++) |
388 | x[i+j*SPDIMS]=rownr*j; |
389 | |
390 | bzero((char*) record,MAX_REC_LENGTH); |
391 | *pos=0x01; /* DEL marker */ |
392 | pos++; |
393 | |
394 | memset(blob_key,0,sizeof(blob_key)); |
395 | tmp=maria_rtree_CreateLineStringWKB(x,SPDIMS,npoints, (uchar*) blob_key); |
396 | |
397 | int4store(pos,tmp); |
398 | pos+=4; |
399 | |
400 | ptr=blob_key; |
401 | memcpy(pos,&ptr,sizeof(char*)); |
402 | } |
403 | |
404 | |
405 | static void create_key(uchar *key,uint rownr) |
406 | { |
407 | double c=rownr; |
408 | uchar *pos; |
409 | uint i; |
410 | |
411 | bzero(key,MAX_REC_LENGTH); |
412 | for ( pos=key, i=0; i<2*SPDIMS; i++) |
413 | { |
414 | float8store(pos,c); |
415 | pos+=sizeof(c); |
416 | } |
417 | } |
418 | |
419 | static void print_key(const uchar *key,const char * tail) |
420 | { |
421 | double c; |
422 | uint i; |
423 | |
424 | printf(" key=" ); |
425 | for (i=0; i<2*SPDIMS; i++) |
426 | { |
427 | float8get(c,key); |
428 | key+=sizeof(c); |
429 | printf("%.14g " ,c); |
430 | } |
431 | printf("%s" ,tail); |
432 | } |
433 | |
434 | |
435 | #ifdef NOT_USED |
436 | |
437 | static int maria_rtree_CreatePointWKB(double *ords, uint n_dims, uchar *wkb) |
438 | { |
439 | uint i; |
440 | |
441 | *wkb = wkbXDR; |
442 | ++wkb; |
443 | int4store(wkb, wkbPoint); |
444 | wkb += 4; |
445 | |
446 | for (i=0; i < n_dims; ++i) |
447 | { |
448 | float8store(wkb, ords[i]); |
449 | wkb += 8; |
450 | } |
451 | return 5 + n_dims * 8; |
452 | } |
453 | #endif |
454 | |
455 | |
456 | static int maria_rtree_CreateLineStringWKB(double *ords, uint n_dims, uint n_points, |
457 | uchar *wkb) |
458 | { |
459 | uint i; |
460 | uint n_ords = n_dims * n_points; |
461 | |
462 | *wkb = wkbXDR; |
463 | ++wkb; |
464 | int4store(wkb, wkbLineString); |
465 | wkb += 4; |
466 | int4store(wkb, n_points); |
467 | wkb += 4; |
468 | for (i=0; i < n_ords; ++i) |
469 | { |
470 | float8store(wkb, ords[i]); |
471 | wkb += 8; |
472 | } |
473 | return 9 + n_points * n_dims * 8; |
474 | } |
475 | |
476 | |
477 | static void maria_rtree_PrintWKB(uchar *wkb, uint n_dims) |
478 | { |
479 | uint wkb_type; |
480 | |
481 | ++wkb; |
482 | wkb_type = uint4korr(wkb); |
483 | wkb += 4; |
484 | |
485 | switch ((enum wkbType)wkb_type) |
486 | { |
487 | case wkbPoint: |
488 | { |
489 | uint i; |
490 | double ord; |
491 | |
492 | printf("POINT(" ); |
493 | for (i=0; i < n_dims; ++i) |
494 | { |
495 | float8get(ord, wkb); |
496 | wkb += 8; |
497 | printf("%.14g" , ord); |
498 | if (i < n_dims - 1) |
499 | printf(" " ); |
500 | else |
501 | printf(")" ); |
502 | } |
503 | break; |
504 | } |
505 | case wkbLineString: |
506 | { |
507 | uint p, i; |
508 | uint n_points; |
509 | double ord; |
510 | |
511 | printf("LineString(" ); |
512 | n_points = uint4korr(wkb); |
513 | wkb += 4; |
514 | for (p=0; p < n_points; ++p) |
515 | { |
516 | for (i=0; i < n_dims; ++i) |
517 | { |
518 | float8get(ord, wkb); |
519 | wkb += 8; |
520 | printf("%.14g" , ord); |
521 | if (i < n_dims - 1) |
522 | printf(" " ); |
523 | } |
524 | if (p < n_points - 1) |
525 | printf(", " ); |
526 | else |
527 | printf(")" ); |
528 | } |
529 | break; |
530 | } |
531 | case wkbPolygon: |
532 | { |
533 | printf("POLYGON(...)" ); |
534 | break; |
535 | } |
536 | case wkbMultiPoint: |
537 | { |
538 | printf("MULTIPOINT(...)" ); |
539 | break; |
540 | } |
541 | case wkbMultiLineString: |
542 | { |
543 | printf("MULTILINESTRING(...)" ); |
544 | break; |
545 | } |
546 | case wkbMultiPolygon: |
547 | { |
548 | printf("MULTIPOLYGON(...)" ); |
549 | break; |
550 | } |
551 | case wkbGeometryCollection: |
552 | { |
553 | printf("GEOMETRYCOLLECTION(...)" ); |
554 | break; |
555 | } |
556 | default: |
557 | { |
558 | printf("UNKNOWN GEOMETRY TYPE" ); |
559 | break; |
560 | } |
561 | } |
562 | } |
563 | |
564 | #include "ma_check_standalone.h" |
565 | |
566 | #else |
567 | int main(int argc __attribute__((unused)),char *argv[] __attribute__((unused))) |
568 | { |
569 | exit(0); |
570 | } |
571 | #endif /*HAVE_SPATIAL*/ |
572 | |