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