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