1 /* Copyright (c) 2000, 2011, 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 /* Test av isam-databas: stor test */
24 
25 #ifndef USE_MY_FUNC		/* We want to be able to dbug this !! */
26 #define USE_MY_FUNC
27 #endif
28 #ifdef DBUG_OFF
29 #undef DBUG_OFF
30 #endif
31 #include "myisamdef.h"
32 #include <m_ctype.h>
33 #include <my_bit.h>
34 
35 #define STANDARD_LENGTH 37
36 #define MYISAM_KEYS 6
37 #define MAX_PARTS 4
38 #if !defined(labs)
39 #define labs(a) abs(a)
40 #endif
41 
42 static void get_options(int argc, char *argv[]);
43 static uint rnd(uint max_value);
44 static void fix_length(uchar *record,uint length);
45 static void put_blob_in_record(uchar *blob_pos,char **blob_buffer);
46 static void copy_key(struct st_myisam_info *info,uint inx,
47 		     uchar *record,uchar *key);
48 
49 static	int verbose=0,testflag=0,
50 	    first_key=0,async_io=0,key_cacheing=0,write_cacheing=0,locking=0,
51             rec_pointer_size=0,pack_fields=1,use_log=0,silent=0,
52             opt_quick_mode=0;
53 static int pack_seg=HA_SPACE_PACK,pack_type=HA_PACK_KEY,remove_count=-1,
54 	   create_flag=0;
55 static ulong key_cache_size=IO_SIZE*16;
56 static uint key_cache_block_size= KEY_CACHE_BLOCK_SIZE;
57 
58 static uint keys=MYISAM_KEYS,recant=1000;
59 static uint use_blob=0;
60 static uint16 key1[1001],key3[5000];
61 static uchar record[300],record2[300],key[100],key2[100];
62 static uchar read_record[300],read_record2[300],read_record3[300];
63 static HA_KEYSEG glob_keyseg[MYISAM_KEYS][MAX_PARTS];
64 
65 		/* Test program */
66 
main(int argc,char * argv[])67 int main(int argc, char *argv[])
68 {
69   uint i;
70   int j,n1,n2,n3,error,k;
71   uint write_count,update,dupp_keys,opt_delete,start,length,blob_pos,
72        reclength,ant,found_parts;
73   my_off_t lastpos;
74   ha_rows range_records,records;
75   MI_INFO *file;
76   MI_KEYDEF keyinfo[10];
77   MI_COLUMNDEF recinfo[10];
78   MI_ISAMINFO info;
79   const char *filename;
80   char *blob_buffer;
81   MI_CREATE_INFO create_info;
82   MY_INIT(argv[0]);
83 
84   filename= "test2";
85   get_options(argc,argv);
86   if (! async_io)
87     my_disable_async_io=1;
88 
89   reclength=STANDARD_LENGTH+60+(use_blob ? 8 : 0);
90   blob_pos=STANDARD_LENGTH+60;
91   keyinfo[0].seg= &glob_keyseg[0][0];
92   keyinfo[0].seg[0].start=0;
93   keyinfo[0].seg[0].length=6;
94   keyinfo[0].seg[0].type=HA_KEYTYPE_TEXT;
95   keyinfo[0].seg[0].language= default_charset_info->number;
96   keyinfo[0].seg[0].flag=(uint8) pack_seg;
97   keyinfo[0].seg[0].null_bit=0;
98   keyinfo[0].seg[0].null_pos=0;
99   keyinfo[0].key_alg=HA_KEY_ALG_BTREE;
100   keyinfo[0].keysegs=1;
101   keyinfo[0].flag = pack_type;
102   keyinfo[0].block_length= 0;                   /* Default block length */
103   keyinfo[1].seg= &glob_keyseg[1][0];
104   keyinfo[1].seg[0].start=7;
105   keyinfo[1].seg[0].length=6;
106   keyinfo[1].seg[0].type=HA_KEYTYPE_BINARY;
107   keyinfo[1].seg[0].flag=0;
108   keyinfo[1].seg[0].null_bit=0;
109   keyinfo[1].seg[0].null_pos=0;
110   keyinfo[1].seg[1].start=0;			/* two part key */
111   keyinfo[1].seg[1].length=6;
112   keyinfo[1].seg[1].type=HA_KEYTYPE_NUM;
113   keyinfo[1].seg[1].flag=HA_REVERSE_SORT;
114   keyinfo[1].seg[1].null_bit=0;
115   keyinfo[1].seg[1].null_pos=0;
116   keyinfo[1].key_alg=HA_KEY_ALG_BTREE;
117   keyinfo[1].keysegs=2;
118   keyinfo[1].flag =0;
119   keyinfo[1].block_length= MI_MIN_KEY_BLOCK_LENGTH;  /* Diff blocklength */
120   keyinfo[2].seg= &glob_keyseg[2][0];
121   keyinfo[2].seg[0].start=12;
122   keyinfo[2].seg[0].length=8;
123   keyinfo[2].seg[0].type=HA_KEYTYPE_BINARY;
124   keyinfo[2].seg[0].flag=HA_REVERSE_SORT;
125   keyinfo[2].seg[0].null_bit=0;
126   keyinfo[2].seg[0].null_pos=0;
127   keyinfo[2].key_alg=HA_KEY_ALG_BTREE;
128   keyinfo[2].keysegs=1;
129   keyinfo[2].flag =HA_NOSAME;
130   keyinfo[2].block_length= 0;                   /* Default block length */
131   keyinfo[3].seg= &glob_keyseg[3][0];
132   keyinfo[3].seg[0].start=0;
133   keyinfo[3].seg[0].length=reclength-(use_blob ? 8 : 0);
134   keyinfo[3].seg[0].type=HA_KEYTYPE_TEXT;
135   keyinfo[3].seg[0].language=default_charset_info->number;
136   keyinfo[3].seg[0].flag=(uint8) pack_seg;
137   keyinfo[3].seg[0].null_bit=0;
138   keyinfo[3].seg[0].null_pos=0;
139   keyinfo[3].key_alg=HA_KEY_ALG_BTREE;
140   keyinfo[3].keysegs=1;
141   keyinfo[3].flag = pack_type;
142   keyinfo[3].block_length= 0;                   /* Default block length */
143   keyinfo[4].seg= &glob_keyseg[4][0];
144   keyinfo[4].seg[0].start=0;
145   keyinfo[4].seg[0].length=5;
146   keyinfo[4].seg[0].type=HA_KEYTYPE_TEXT;
147   keyinfo[4].seg[0].language=default_charset_info->number;
148   keyinfo[4].seg[0].flag=0;
149   keyinfo[4].seg[0].null_bit=0;
150   keyinfo[4].seg[0].null_pos=0;
151   keyinfo[4].key_alg=HA_KEY_ALG_BTREE;
152   keyinfo[4].keysegs=1;
153   keyinfo[4].flag = pack_type;
154   keyinfo[4].block_length= 0;                   /* Default block length */
155   keyinfo[5].seg= &glob_keyseg[5][0];
156   keyinfo[5].seg[0].start=0;
157   keyinfo[5].seg[0].length=4;
158   keyinfo[5].seg[0].type=HA_KEYTYPE_TEXT;
159   keyinfo[5].seg[0].language=default_charset_info->number;
160   keyinfo[5].seg[0].flag=pack_seg;
161   keyinfo[5].seg[0].null_bit=0;
162   keyinfo[5].seg[0].null_pos=0;
163   keyinfo[5].key_alg=HA_KEY_ALG_BTREE;
164   keyinfo[5].keysegs=1;
165   keyinfo[5].flag = pack_type;
166   keyinfo[5].block_length= 0;                   /* Default block length */
167 
168   recinfo[0].type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
169   recinfo[0].length=7;
170   recinfo[0].null_bit=0;
171   recinfo[0].null_pos=0;
172   recinfo[1].type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
173   recinfo[1].length=5;
174   recinfo[1].null_bit=0;
175   recinfo[1].null_pos=0;
176   recinfo[2].type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
177   recinfo[2].length=9;
178   recinfo[2].null_bit=0;
179   recinfo[2].null_pos=0;
180   recinfo[3].type=FIELD_NORMAL;
181   recinfo[3].length=STANDARD_LENGTH-7-5-9-4;
182   recinfo[3].null_bit=0;
183   recinfo[3].null_pos=0;
184   recinfo[4].type=pack_fields ? FIELD_SKIP_ZERO : 0;
185   recinfo[4].length=4;
186   recinfo[4].null_bit=0;
187   recinfo[4].null_pos=0;
188   recinfo[5].type=pack_fields ? FIELD_SKIP_ENDSPACE : 0;
189   recinfo[5].length=60;
190   recinfo[5].null_bit=0;
191   recinfo[5].null_pos=0;
192   if (use_blob)
193   {
194     recinfo[6].type=FIELD_BLOB;
195     recinfo[6].length=4+portable_sizeof_char_ptr;
196     recinfo[6].null_bit=0;
197     recinfo[6].null_pos=0;
198   }
199 
200   write_count=update=dupp_keys=opt_delete=0;
201   blob_buffer=0;
202 
203   for (i=1000 ; i>0 ; i--) key1[i]=0;
204   for (i=4999 ; i>0 ; i--) key3[i]=0;
205 
206   if (!silent)
207     printf("- Creating isam-file\n");
208   /*  DBUG_PUSH(""); */
209   /* my_delete(filename,MYF(0)); */	/* Remove old locks under gdb */
210   file= 0;
211   memset(&create_info, 0, sizeof(create_info));
212   create_info.max_rows=(ha_rows) (rec_pointer_size ?
213 				  (1L << (rec_pointer_size*8))/
214 				  reclength : 0);
215   create_info.reloc_rows=(ha_rows) 100;
216   if (mi_create(filename,keys,&keyinfo[first_key],
217 		use_blob ? 7 : 6, &recinfo[0],
218 		0,(MI_UNIQUEDEF*) 0,
219 		&create_info,create_flag))
220     goto err;
221   if (use_log)
222     mi_log(1);
223   if (!(file=mi_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
224     goto err;
225   if (!silent)
226     printf("- Writing key:s\n");
227   if (key_cacheing)
228     init_key_cache(dflt_key_cache,key_cache_block_size,key_cache_size,0,0);
229   if (locking)
230     mi_lock_database(file,F_WRLCK);
231   if (write_cacheing)
232     mi_extra(file,HA_EXTRA_WRITE_CACHE,0);
233   if (opt_quick_mode)
234     mi_extra(file,HA_EXTRA_QUICK,0);
235 
236   for (i=0 ; i < recant ; i++)
237   {
238     n1=rnd(1000); n2=rnd(100); n3=rnd(5000);
239     sprintf((char*) record,"%6d:%4d:%8d:Pos: %4d    ",n1,n2,n3,write_count);
240     int4store(record+STANDARD_LENGTH-4,(long) i);
241     fix_length(record,(uint) STANDARD_LENGTH+rnd(60));
242     put_blob_in_record(record+blob_pos,&blob_buffer);
243     DBUG_PRINT("test",("record: %d",i));
244 
245     if (mi_write(file,record))
246     {
247       if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
248       {
249 	printf("Error: %d in write at record: %d\n",my_errno,i);
250 	goto err;
251       }
252       if (verbose) printf("   Double key: %d\n",n3);
253     }
254     else
255     {
256       if (key3[n3] == 1 && first_key <3 && first_key+keys >= 3)
257       {
258 	printf("Error: Didn't get error when writing second key: '%8d'\n",n3);
259 	goto err;
260       }
261       write_count++; key1[n1]++; key3[n3]=1;
262     }
263 
264     /* Check if we can find key without flushing database */
265     if (i == recant/2)
266     {
267       for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
268       if (!j)
269 	for (j=999 ; j>0 && key1[j] == 0 ; j--) ;
270       sprintf((char*) key,"%6d",j);
271       if (mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
272       {
273 	printf("Test in loop: Can't find key: \"%s\"\n",key);
274 	goto err;
275       }
276     }
277   }
278   if (testflag==1) goto end;
279 
280   if (write_cacheing)
281   {
282     if (mi_extra(file,HA_EXTRA_NO_CACHE,0))
283     {
284       puts("got error from mi_extra(HA_EXTRA_NO_CACHE)");
285       goto end;
286     }
287   }
288   if (key_cacheing)
289     resize_key_cache(dflt_key_cache,key_cache_block_size,key_cache_size*2,0,0);
290 
291   if (!silent)
292     printf("- Delete\n");
293   for (i=0 ; i<recant/10 ; i++)
294   {
295     for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
296     if (j != 0)
297     {
298       sprintf((char*) key,"%6d",j);
299       if (mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
300       {
301 	printf("can't find key1: \"%s\"\n",key);
302 	goto err;
303       }
304       if (opt_delete == (uint) remove_count)		/* While testing */
305 	goto end;
306       if (mi_delete(file,read_record))
307       {
308 	printf("error: %d; can't delete record: \"%s\"\n", my_errno,read_record);
309 	goto err;
310       }
311       opt_delete++;
312       key1[atoi((char*) read_record+keyinfo[0].seg[0].start)]--;
313       key3[atoi((char*) read_record+keyinfo[2].seg[0].start)]=0;
314     }
315     else
316       puts("Warning: Skipping delete test because no dupplicate keys");
317   }
318   if (testflag==2) goto end;
319 
320   if (!silent)
321     printf("- Update\n");
322   for (i=0 ; i<recant/10 ; i++)
323   {
324     n1=rnd(1000); n2=rnd(100); n3=rnd(5000);
325     sprintf((char*) record2,"%6d:%4d:%8d:XXX: %4d     ",n1,n2,n3,update);
326     int4store(record2+STANDARD_LENGTH-4,(long) i);
327     fix_length(record2,(uint) STANDARD_LENGTH+rnd(60));
328 
329     for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
330     if (j != 0)
331     {
332       sprintf((char*) key,"%6d",j);
333       if (mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
334       {
335 	printf("can't find key1: \"%s\"\n",(char*) key);
336 	goto err;
337       }
338       if (use_blob)
339       {
340 	if (i & 1)
341 	  put_blob_in_record(record+blob_pos,&blob_buffer);
342 	else
343 	  bmove(record+blob_pos,read_record+blob_pos,8);
344       }
345       if (mi_update(file,read_record,record2))
346       {
347 	if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
348 	{
349 	  printf("error: %d; can't update:\nFrom: \"%s\"\nTo:   \"%s\"\n",
350 		 my_errno,read_record,record2);
351 	  goto err;
352 	}
353 	if (verbose)
354 	  printf("Double key when tried to update:\nFrom: \"%s\"\nTo:   \"%s\"\n",record,record2);
355       }
356       else
357       {
358 	key1[atoi((char*) read_record+keyinfo[0].seg[0].start)]--;
359 	key3[atoi((char*) read_record+keyinfo[2].seg[0].start)]=0;
360 	key1[n1]++; key3[n3]=1;
361 	update++;
362       }
363     }
364   }
365   if (testflag == 3)
366     goto end;
367 
368   for (i=999, dupp_keys=j=0 ; i>0 ; i--)
369   {
370     if (key1[i] > dupp_keys)
371     {
372       dupp_keys=key1[i]; j=i;
373     }
374   }
375   sprintf((char*) key,"%6d",j);
376   start=keyinfo[0].seg[0].start;
377   length=keyinfo[0].seg[0].length;
378   if (dupp_keys)
379   {
380     if (!silent)
381       printf("- Same key: first - next -> last - prev -> first\n");
382     DBUG_PRINT("progpos",("first - next -> last - prev -> first"));
383     if (verbose) printf("	 Using key: \"%s\"  Keys: %d\n",key,dupp_keys);
384 
385     if (mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
386       goto err;
387     if (mi_rsame(file,read_record2,-1))
388       goto err;
389     if (memcmp(read_record,read_record2,reclength) != 0)
390     {
391       printf("mi_rsame didn't find same record\n");
392       goto end;
393     }
394     info.recpos=mi_position(file);
395     if (mi_rfirst(file,read_record2,0) ||
396 	mi_rsame_with_pos(file,read_record2,0,info.recpos) ||
397 	memcmp(read_record,read_record2,reclength) != 0)
398     {
399       printf("mi_rsame_with_pos didn't find same record\n");
400       goto end;
401     }
402     {
403       int skr=mi_rnext(file,read_record2,0);
404       if ((skr && my_errno != HA_ERR_END_OF_FILE) ||
405 	  mi_rprev(file,read_record2,-1) ||
406 	  memcmp(read_record,read_record2,reclength) != 0)
407       {
408 	printf("mi_rsame_with_pos lost position\n");
409 	goto end;
410       }
411     }
412     ant=1;
413     while (mi_rnext(file,read_record2,0) == 0 &&
414 	   memcmp(read_record2+start,key,length) == 0) ant++;
415     if (ant != dupp_keys)
416     {
417       printf("next: Found: %d keys of %d\n",ant,dupp_keys);
418       goto end;
419     }
420     ant=0;
421     while (mi_rprev(file,read_record3,0) == 0 &&
422 	   memcmp(read_record3+start,key,length) == 0) ant++;
423     if (ant != dupp_keys)
424     {
425       printf("prev: Found: %d records of %d\n",ant,dupp_keys);
426       goto end;
427     }
428 
429     /* Check of mi_rnext_same */
430     if (mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
431       goto err;
432     ant=1;
433     while (!mi_rnext_same(file,read_record3) && ant < dupp_keys+10)
434       ant++;
435     if (ant != dupp_keys || my_errno != HA_ERR_END_OF_FILE)
436     {
437       printf("mi_rnext_same: Found: %d records of %d\n",ant,dupp_keys);
438       goto end;
439     }
440   }
441 
442   if (!silent)
443     printf("- All keys: first - next -> last - prev -> first\n");
444   DBUG_PRINT("progpos",("All keys: first - next -> last - prev -> first"));
445   ant=1;
446   if (mi_rfirst(file,read_record,0))
447   {
448     printf("Can't find first record\n");
449     goto end;
450   }
451   while ((error=mi_rnext(file,read_record3,0)) == 0 && ant < write_count+10)
452     ant++;
453   if (ant != write_count - opt_delete || error != HA_ERR_END_OF_FILE)
454   {
455     printf("next: I found: %d records of %d (error: %d)\n",
456 	   ant, write_count - opt_delete, error);
457     goto end;
458   }
459   if (mi_rlast(file,read_record2,0) ||
460       memcmp(read_record2,read_record3,reclength))
461   {
462     printf("Can't find last record\n");
463     DBUG_DUMP("record2",(uchar*) read_record2,reclength);
464     DBUG_DUMP("record3",(uchar*) read_record3,reclength);
465     goto end;
466   }
467   ant=1;
468   while (mi_rprev(file,read_record3,0) == 0 && ant < write_count+10)
469     ant++;
470   if (ant != write_count - opt_delete)
471   {
472     printf("prev: I found: %d records of %d\n",ant,write_count);
473     goto end;
474   }
475   if (memcmp(read_record,read_record3,reclength))
476   {
477     printf("Can't find first record\n");
478     goto end;
479   }
480 
481   if (!silent)
482     printf("- Test if: Read first - next - prev - prev - next == first\n");
483   DBUG_PRINT("progpos",("- Read first - next - prev - prev - next == first"));
484   if (mi_rfirst(file,read_record,0) ||
485       mi_rnext(file,read_record3,0) ||
486       mi_rprev(file,read_record3,0) ||
487       mi_rprev(file,read_record3,0) == 0 ||
488       mi_rnext(file,read_record3,0))
489       goto err;
490   if (memcmp(read_record,read_record3,reclength) != 0)
491      printf("Can't find first record\n");
492 
493   if (!silent)
494     printf("- Test if: Read last - prev - next - next - prev == last\n");
495   DBUG_PRINT("progpos",("Read last - prev - next - next - prev == last"));
496   if (mi_rlast(file,read_record2,0) ||
497       mi_rprev(file,read_record3,0) ||
498       mi_rnext(file,read_record3,0) ||
499       mi_rnext(file,read_record3,0) == 0 ||
500       mi_rprev(file,read_record3,0))
501       goto err;
502   if (memcmp(read_record2,read_record3,reclength))
503      printf("Can't find last record\n");
504 #ifdef NOT_ANYMORE
505   if (!silent)
506     puts("- Test read key-part");
507   strmov(key2,key);
508   for(i=strlen(key2) ; i-- > 1 ;)
509   {
510     key2[i]=0;
511 
512     /* The following row is just to catch some bugs in the key code */
513     memset(file->lastkey, 0, file->s->base.max_key_length*2);
514     if (mi_rkey(file,read_record,0,key2,(uint) i,HA_READ_PREFIX))
515       goto err;
516     if (memcmp(read_record+start,key,(uint) i))
517     {
518       puts("Didn't find right record");
519       goto end;
520     }
521   }
522 #endif
523   if (dupp_keys > 2)
524   {
525     if (!silent)
526       printf("- Read key (first) - next - delete - next -> last\n");
527     DBUG_PRINT("progpos",("first - next - delete - next -> last"));
528     if (mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
529       goto err;
530     if (mi_rnext(file,read_record3,0)) goto err;
531     if (mi_delete(file,read_record3)) goto err;
532     opt_delete++;
533     ant=1;
534     while (mi_rnext(file,read_record3,0) == 0 &&
535 	   memcmp(read_record3+start,key,length) == 0) ant++;
536     if (ant != dupp_keys-1)
537     {
538       printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-1);
539       goto end;
540     }
541   }
542   if (dupp_keys>4)
543   {
544     if (!silent)
545       printf("- Read last of key - prev - delete - prev -> first\n");
546     DBUG_PRINT("progpos",("last - prev - delete - prev -> first"));
547     if (mi_rprev(file,read_record3,0)) goto err;
548     if (mi_rprev(file,read_record3,0)) goto err;
549     if (mi_delete(file,read_record3)) goto err;
550     opt_delete++;
551     ant=1;
552     while (mi_rprev(file,read_record3,0) == 0 &&
553 	   memcmp(read_record3+start,key,length) == 0) ant++;
554     if (ant != dupp_keys-2)
555     {
556       printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-2);
557       goto end;
558     }
559   }
560   if (dupp_keys > 6)
561   {
562     if (!silent)
563       printf("- Read first - delete - next -> last\n");
564     DBUG_PRINT("progpos",("first - delete - next -> last"));
565     if (mi_rkey(file,read_record3,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
566       goto err;
567     if (mi_delete(file,read_record3)) goto err;
568     opt_delete++;
569     ant=1;
570     if (mi_rnext(file,read_record,0))
571       goto err;					/* Skall finnas poster */
572     while (mi_rnext(file,read_record3,0) == 0 &&
573 	   memcmp(read_record3+start,key,length) == 0) ant++;
574     if (ant != dupp_keys-3)
575     {
576       printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-3);
577       goto end;
578     }
579 
580     if (!silent)
581       printf("- Read last - delete - prev -> first\n");
582     DBUG_PRINT("progpos",("last - delete - prev -> first"));
583     if (mi_rprev(file,read_record3,0)) goto err;
584     if (mi_delete(file,read_record3)) goto err;
585     opt_delete++;
586     ant=0;
587     while (mi_rprev(file,read_record3,0) == 0 &&
588 	   memcmp(read_record3+start,key,length) == 0) ant++;
589     if (ant != dupp_keys-4)
590     {
591       printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-4);
592       goto end;
593     }
594   }
595 
596   if (!silent)
597     puts("- Test if: Read rrnd - same");
598   DBUG_PRINT("progpos",("Read rrnd - same"));
599   for (i=0 ; i < write_count ; i++)
600   {
601     if (mi_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR) == 0)
602       break;
603   }
604   if (i == write_count)
605     goto err;
606 
607   bmove(read_record2,read_record,reclength);
608   for (i=min(2,keys) ; i-- > 0 ;)
609   {
610     if (mi_rsame(file,read_record2,(int) i)) goto err;
611     if (memcmp(read_record,read_record2,reclength) != 0)
612     {
613       printf("is_rsame didn't find same record\n");
614       goto end;
615     }
616   }
617   if (!silent)
618     puts("- Test mi_records_in_range");
619   mi_status(file,&info,HA_STATUS_VARIABLE);
620   for (i=0 ; i < info.keys ; i++)
621   {
622     key_range min_key, max_key;
623     if (mi_rfirst(file,read_record,(int) i) ||
624 	mi_rlast(file,read_record2,(int) i))
625       goto err;
626     copy_key(file,(uint) i,(uchar*) read_record,(uchar*) key);
627     copy_key(file,(uint) i,(uchar*) read_record2,(uchar*) key2);
628     min_key.key= key;
629     min_key.keypart_map= HA_WHOLE_KEY;
630     min_key.flag= HA_READ_KEY_EXACT;
631     max_key.key= key2;
632     max_key.keypart_map= HA_WHOLE_KEY;
633     max_key.flag= HA_READ_AFTER_KEY;
634 
635     range_records= mi_records_in_range(file,(int) i, &min_key, &max_key);
636     if (range_records < info.records*8/10 ||
637 	range_records > info.records*12/10)
638     {
639       printf("mi_records_range returned %ld; Should be about %ld\n",
640 	     (long) range_records,(long) info.records);
641       goto end;
642     }
643     if (verbose)
644     {
645       printf("mi_records_range returned %ld;  Exact is %ld  (diff: %4.2g %%)\n",
646 	     (long) range_records, (long) info.records,
647 	     labs((long) range_records - (long) info.records)*100.0/
648 	     info.records);
649     }
650   }
651   for (i=0 ; i < 5 ; i++)
652   {
653     for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
654     for (k=rnd(1000)+1 ; k>0 && key1[k] == 0 ; k--) ;
655     if (j != 0 && k != 0)
656     {
657       key_range min_key, max_key;
658       if (j > k)
659 	swap_variables(int, j, k);
660       sprintf((char*) key,"%6d",j);
661       sprintf((char*) key2,"%6d",k);
662 
663       min_key.key= key;
664       min_key.length= USE_WHOLE_KEY;
665       min_key.flag= HA_READ_AFTER_KEY;
666       max_key.key= key2;
667       max_key.length= USE_WHOLE_KEY;
668       max_key.flag= HA_READ_BEFORE_KEY;
669       range_records= mi_records_in_range(file, 0, &min_key, &max_key);
670       records=0;
671       for (j++ ; j < k ; j++)
672 	records+=key1[j];
673       if ((long) range_records < (long) records*7/10-2 ||
674 	  (long) range_records > (long) records*14/10+2)
675       {
676 	printf("mi_records_range for key: %d returned %lu; Should be about %lu\n",
677 	       i, (ulong) range_records, (ulong) records);
678 	goto end;
679       }
680       if (verbose && records)
681       {
682 	printf("mi_records_range returned %lu;  Exact is %lu  (diff: %4.2g %%)\n",
683 	       (ulong) range_records, (ulong) records,
684 	       labs((long) range_records-(long) records)*100.0/records);
685 
686       }
687     }
688     }
689 
690   if (!silent)
691     printf("- mi_info\n");
692   mi_status(file,&info,HA_STATUS_VARIABLE | HA_STATUS_CONST);
693   if (info.records != write_count-opt_delete || info.deleted > opt_delete + update
694       || info.keys != keys)
695   {
696     puts("Wrong info from mi_info");
697     printf("Got: records: %lu  delete: %lu  i_keys: %d\n",
698 	   (ulong) info.records, (ulong) info.deleted, info.keys);
699   }
700   if (verbose)
701   {
702     char buff[80];
703     get_date(buff,3,info.create_time);
704     printf("info: Created %s\n",buff);
705     get_date(buff,3,info.check_time);
706     printf("info: checked %s\n",buff);
707     get_date(buff,3,info.update_time);
708     printf("info: Modified %s\n",buff);
709   }
710 
711   mi_panic(HA_PANIC_WRITE);
712   mi_panic(HA_PANIC_READ);
713   if (mi_is_changed(file))
714     puts("Warning: mi_is_changed reported that datafile was changed");
715 
716   if (!silent)
717     printf("- mi_extra(CACHE) + mi_rrnd.... + mi_extra(NO_CACHE)\n");
718   if (mi_reset(file) || mi_extra(file,HA_EXTRA_CACHE,0))
719   {
720     if (locking || (!use_blob && !pack_fields))
721     {
722       puts("got error from mi_extra(HA_EXTRA_CACHE)");
723       goto end;
724     }
725   }
726   ant=0;
727   while ((error=mi_rrnd(file,record,HA_OFFSET_ERROR)) != HA_ERR_END_OF_FILE &&
728 	 ant < write_count + 10)
729 	ant+= error ? 0 : 1;
730   if (ant != write_count-opt_delete)
731   {
732     printf("rrnd with cache: I can only find: %d records of %d\n",
733 	   ant,write_count-opt_delete);
734     goto end;
735   }
736   if (mi_extra(file,HA_EXTRA_NO_CACHE,0))
737   {
738     puts("got error from mi_extra(HA_EXTRA_NO_CACHE)");
739     goto end;
740   }
741 
742   ant=0;
743   mi_scan_init(file);
744   while ((error=mi_scan(file,record)) != HA_ERR_END_OF_FILE &&
745 	 ant < write_count + 10)
746 	ant+= error ? 0 : 1;
747   if (ant != write_count-opt_delete)
748   {
749     printf("scan with cache: I can only find: %d records of %d\n",
750 	   ant,write_count-opt_delete);
751     goto end;
752   }
753 
754   if (testflag == 4) goto end;
755 
756   if (!silent)
757     printf("- Removing keys\n");
758   DBUG_PRINT("progpos",("Removing keys"));
759   lastpos = HA_OFFSET_ERROR;
760   /* DBUG_POP(); */
761   mi_reset(file);
762   found_parts=0;
763   while ((error=mi_rrnd(file,read_record,HA_OFFSET_ERROR)) !=
764 	 HA_ERR_END_OF_FILE)
765   {
766     info.recpos=mi_position(file);
767     if (lastpos >= info.recpos && lastpos != HA_OFFSET_ERROR)
768     {
769       printf("mi_rrnd didn't advance filepointer; old: %ld, new: %ld\n",
770 	     (long) lastpos, (long) info.recpos);
771       goto err;
772     }
773     lastpos=info.recpos;
774     if (error == 0)
775     {
776       if (opt_delete == (uint) remove_count)		/* While testing */
777 	goto end;
778       if (mi_rsame(file,read_record,-1))
779       {
780 	printf("can't find record %lx\n",(long) info.recpos);
781 	goto err;
782       }
783       if (use_blob)
784       {
785 	ulong blob_length,pos;
786 	uchar *ptr;
787 	longget(blob_length,read_record+blob_pos+4);
788 	ptr=(uchar*) blob_length;
789 	longget(blob_length,read_record+blob_pos);
790 	for (pos=0 ; pos < blob_length ; pos++)
791 	{
792 	  if (ptr[pos] != (uchar) (blob_length+pos))
793 	  {
794 	    printf("found blob with wrong info at %ld\n",(long) lastpos);
795 	    use_blob=0;
796 	    break;
797 	  }
798 	}
799       }
800       if (mi_delete(file,read_record))
801       {
802 	printf("can't delete record: %6.6s,  delete_count: %d\n",
803 	       read_record, opt_delete);
804 	goto err;
805       }
806       opt_delete++;
807     }
808     else
809       found_parts++;
810   }
811   if (my_errno != HA_ERR_END_OF_FILE && my_errno != HA_ERR_RECORD_DELETED)
812     printf("error: %d from mi_rrnd\n",my_errno);
813   if (write_count != opt_delete)
814   {
815     printf("Deleted only %d of %d records (%d parts)\n",opt_delete,write_count,
816 	   found_parts);
817     goto err;
818   }
819 end:
820   if (mi_close(file))
821     goto err;
822   mi_panic(HA_PANIC_CLOSE);			/* Should close log */
823   if (!silent)
824   {
825     printf("\nFollowing test have been made:\n");
826     printf("Write records: %d\nUpdate records: %d\nSame-key-read: %d\nDelete records: %d\n", write_count,update,dupp_keys,opt_delete);
827     if (rec_pointer_size)
828       printf("Record pointer size:  %d\n",rec_pointer_size);
829     printf("myisam_block_size:    %lu\n", myisam_block_size);
830     if (key_cacheing)
831     {
832       puts("Key cache used");
833       printf("key_cache_block_size: %u\n", key_cache_block_size);
834       if (write_cacheing)
835 	puts("Key cache resized");
836     }
837     if (write_cacheing)
838       puts("Write cacheing used");
839     if (write_cacheing)
840       puts("quick mode");
841     if (async_io && locking)
842       puts("Asyncron io with locking used");
843     else if (locking)
844       puts("Locking used");
845     if (use_blob)
846       puts("blobs used");
847     printf("key cache status: \n\
848 blocks used:%10lu\n\
849 not flushed:%10lu\n\
850 w_requests: %10lu\n\
851 writes:     %10lu\n\
852 r_requests: %10lu\n\
853 reads:      %10lu\n",
854            dflt_key_cache->blocks_used,
855            dflt_key_cache->global_blocks_changed,
856            (ulong) dflt_key_cache->global_cache_w_requests,
857            (ulong) dflt_key_cache->global_cache_write,
858            (ulong) dflt_key_cache->global_cache_r_requests,
859            (ulong) dflt_key_cache->global_cache_read);
860   }
861   end_key_cache(dflt_key_cache,1);
862   if (blob_buffer)
863     my_free(blob_buffer);
864   my_end(silent ? MY_CHECK_ERROR : MY_CHECK_ERROR | MY_GIVE_INFO);
865   return(0);
866 err:
867   printf("got error: %d when using MyISAM-database\n",my_errno);
868   if (file)
869     (void) mi_close(file);
870   return(1);
871 } /* main */
872 
873 
874 	/* l{ser optioner */
875 	/* OBS! intierar endast DEBUG - ingen debuggning h{r ! */
876 
get_options(int argc,char ** argv)877 static void get_options(int argc, char **argv)
878 {
879   char *pos,*progname;
880 
881   progname= argv[0];
882 
883   while (--argc >0 && *(pos = *(++argv)) == '-' ) {
884     switch(*++pos) {
885     case 'B':
886       pack_type= HA_BINARY_PACK_KEY;
887       break;
888     case 'b':
889       use_blob=1;
890       break;
891     case 'K':				/* Use key cacheing */
892       key_cacheing=1;
893       if (*++pos)
894 	key_cache_size=atol(pos);
895       break;
896     case 'W':				/* Use write cacheing */
897       write_cacheing=1;
898       if (*++pos)
899 	my_default_record_cache_size=atoi(pos);
900       break;
901     case 'd':
902       remove_count= atoi(++pos);
903       break;
904     case 'i':
905       if (*++pos)
906 	srand(atoi(pos));
907       break;
908     case 'l':
909       use_log=1;
910       break;
911     case 'L':
912       locking=1;
913       break;
914     case 'A':				/* use asyncron io */
915       async_io=1;
916       if (*++pos)
917 	my_default_record_cache_size=atoi(pos);
918       break;
919     case 'v':				/* verbose */
920       verbose=1;
921       break;
922     case 'm':				/* records */
923       if ((recant=atoi(++pos)) < 10)
924       {
925 	fprintf(stderr,"record count must be >= 10\n");
926 	exit(1);
927       }
928       break;
929     case 'e':				/* myisam_block_length */
930       if ((myisam_block_size= atoi(++pos)) < MI_MIN_KEY_BLOCK_LENGTH ||
931 	  myisam_block_size > MI_MAX_KEY_BLOCK_LENGTH)
932       {
933 	fprintf(stderr,"Wrong myisam_block_length\n");
934 	exit(1);
935       }
936       myisam_block_size= my_round_up_to_next_power(myisam_block_size);
937       break;
938     case 'E':				/* myisam_block_length */
939       if ((key_cache_block_size=atoi(++pos)) < MI_MIN_KEY_BLOCK_LENGTH ||
940 	  key_cache_block_size > MI_MAX_KEY_BLOCK_LENGTH)
941       {
942 	fprintf(stderr,"Wrong key_cache_block_size\n");
943 	exit(1);
944       }
945       key_cache_block_size= my_round_up_to_next_power(key_cache_block_size);
946       break;
947     case 'f':
948       if ((first_key=atoi(++pos)) < 0 || first_key >= MYISAM_KEYS)
949 	first_key=0;
950       break;
951     case 'k':
952       if ((keys=(uint) atoi(++pos)) < 1 ||
953 	   keys > (uint) (MYISAM_KEYS-first_key))
954 	keys=MYISAM_KEYS-first_key;
955       break;
956     case 'P':
957       pack_type=0;			/* Don't use DIFF_LENGTH */
958       pack_seg=0;
959       break;
960     case 'R':				/* Length of record pointer */
961       rec_pointer_size=atoi(++pos);
962       if (rec_pointer_size > 7)
963 	rec_pointer_size=0;
964       break;
965     case 'S':
966       pack_fields=0;			/* Static-length-records */
967       break;
968     case 's':
969       silent=1;
970       break;
971     case 't':
972       testflag=atoi(++pos);		/* testmod */
973       break;
974     case 'q':
975       opt_quick_mode=1;
976       break;
977     case 'c':
978       create_flag|= HA_CREATE_CHECKSUM;
979       break;
980     case 'D':
981       create_flag|=HA_CREATE_DELAY_KEY_WRITE;
982       break;
983     case '?':
984     case 'I':
985     case 'V':
986       printf("%s  Ver 1.2 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
987       puts("By Monty, for your professional use\n");
988       printf("Usage: %s [-?AbBcDIKLPRqSsVWltv] [-k#] [-f#] [-m#] [-e#] [-E#] [-t#]\n",
989 	     progname);
990       exit(0);
991     case '#':
992       DBUG_PUSH (++pos);
993       break;
994     default:
995       printf("Illegal option: '%c'\n",*pos);
996       break;
997     }
998   }
999   return;
1000 } /* get options */
1001 
1002 	/* Get a random value 0 <= x <= n */
1003 
rnd(uint max_value)1004 static uint rnd(uint max_value)
1005 {
1006   return (uint) ((rand() & 32767)/32767.0*max_value);
1007 } /* rnd */
1008 
1009 
1010 	/* Create a variable length record */
1011 
fix_length(uchar * rec,uint length)1012 static void fix_length(uchar *rec, uint length)
1013 {
1014   bmove(rec+STANDARD_LENGTH,
1015 	"0123456789012345678901234567890123456789012345678901234567890",
1016 	length-STANDARD_LENGTH);
1017   strfill((char*) rec+length,STANDARD_LENGTH+60-length,' ');
1018 } /* fix_length */
1019 
1020 
1021 	/* Put maybe a blob in record */
1022 
put_blob_in_record(uchar * blob_pos,char ** blob_buffer)1023 static void put_blob_in_record(uchar *blob_pos, char **blob_buffer)
1024 {
1025   ulong i,length;
1026   if (use_blob)
1027   {
1028     if (rnd(10) == 0)
1029     {
1030       if (! *blob_buffer &&
1031 	  !(*blob_buffer=my_malloc((uint) use_blob,MYF(MY_WME))))
1032       {
1033 	use_blob=0;
1034 	return;
1035       }
1036       length=rnd(use_blob);
1037       for (i=0 ; i < length ; i++)
1038 	(*blob_buffer)[i]=(char) (length+i);
1039       int4store(blob_pos,length);
1040       memcpy(blob_pos+4, blob_buffer, sizeof(char*));
1041     }
1042     else
1043     {
1044       int4store(blob_pos,0);
1045     }
1046   }
1047   return;
1048 }
1049 
1050 
copy_key(MI_INFO * info,uint inx,uchar * rec,uchar * key_buff)1051 static void copy_key(MI_INFO *info,uint inx,uchar *rec,uchar *key_buff)
1052 {
1053   HA_KEYSEG *keyseg;
1054 
1055   for (keyseg=info->s->keyinfo[inx].seg ; keyseg->type ; keyseg++)
1056   {
1057     memcpy(key_buff,rec+keyseg->start,(size_t) keyseg->length);
1058     key_buff+=keyseg->length;
1059   }
1060   return;
1061 }
1062 
1063 #include "mi_extrafunc.h"
1064