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