1 /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
2    reserved
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
23 
24 /* Test av isam-databas: stor test */
25 
26 #include "heapdef.h"		/* Because of hp_find_block */
27 #include <signal.h>
28 
29 #define MAX_RECORDS 100000
30 #define MAX_KEYS 4
31 
32 static int get_options(int argc, char *argv[]);
33 static int rnd(int max_value);
34 static sig_handler endprog(int sig_number);
35 
36 static uint flag=0,verbose=0,testflag=0,recant=10000,silent=0;
37 static uint keys=MAX_KEYS;
38 static uint16 key1[1001];
39 static my_bool key3[MAX_RECORDS];
40 static int reclength=39;
41 
42 
43 static int calc_check(uchar *buf,uint length);
44 static void make_record(uchar *record, uint n1, uint n2, uint n3,
45 			const char *mark, uint count);
46 
47 /* Main program */
48 
main(int argc,char * argv[])49 int main(int argc, char *argv[])
50 {
51   register uint i,j;
52   uint ant,n1,n2,n3;
53   uint write_count,update,opt_delete,check2,dupp_keys,found_key;
54   int error;
55   ulong pos;
56   unsigned long key_check;
57   uchar record[128],record2[128],record3[128],key[10];
58   const char *filename,*filename2;
59   HP_INFO *file,*file2;
60   HP_SHARE *tmp_share;
61   HP_KEYDEF keyinfo[MAX_KEYS];
62   HA_KEYSEG keyseg[MAX_KEYS*5];
63   HEAP_PTR UNINIT_VAR(position);
64   HP_CREATE_INFO hp_create_info;
65   CHARSET_INFO *cs= &my_charset_latin1;
66   my_bool unused;
67   MY_INIT(argv[0]);		/* init my_sys library & pthreads */
68 
69   filename= "test2";
70   filename2= "test2_2";
71   file=file2=0;
72   get_options(argc,argv);
73 
74   memset(&hp_create_info, 0, sizeof(hp_create_info));
75   hp_create_info.max_table_size= 1024L*1024L;
76   hp_create_info.keys= keys;
77   hp_create_info.keydef= keyinfo;
78   hp_create_info.reclength= reclength;
79   hp_create_info.max_records= (ulong) flag*100000L;
80   hp_create_info.min_records= (ulong) recant/2;
81 
82   write_count=update=opt_delete=0;
83   key_check=0;
84 
85   keyinfo[0].seg=keyseg;
86   keyinfo[0].keysegs=1;
87   keyinfo[0].flag= 0;
88   keyinfo[0].algorithm= HA_KEY_ALG_HASH;
89   keyinfo[0].seg[0].type=HA_KEYTYPE_BINARY;
90   keyinfo[0].seg[0].start=0;
91   keyinfo[0].seg[0].length=6;
92   keyinfo[0].seg[0].null_bit=0;
93   keyinfo[0].seg[0].charset=cs;
94   keyinfo[1].seg=keyseg+1;
95   keyinfo[1].keysegs=2;
96   keyinfo[1].flag=0;
97   keyinfo[1].algorithm= HA_KEY_ALG_HASH;
98   keyinfo[1].seg[0].type=HA_KEYTYPE_BINARY;
99   keyinfo[1].seg[0].start=7;
100   keyinfo[1].seg[0].length=6;
101   keyinfo[1].seg[0].null_bit=0;
102   keyinfo[1].seg[0].charset=cs;
103   keyinfo[1].seg[1].type=HA_KEYTYPE_TEXT;
104   keyinfo[1].seg[1].start=0;			/* key in two parts */
105   keyinfo[1].seg[1].length=6;
106   keyinfo[1].seg[1].null_bit=0;
107   keyinfo[1].seg[1].charset=cs;
108   keyinfo[2].seg=keyseg+3;
109   keyinfo[2].keysegs=1;
110   keyinfo[2].flag=HA_NOSAME;
111   keyinfo[2].algorithm= HA_KEY_ALG_HASH;
112   keyinfo[2].seg[0].type=HA_KEYTYPE_BINARY;
113   keyinfo[2].seg[0].start=12;
114   keyinfo[2].seg[0].length=8;
115   keyinfo[2].seg[0].null_bit=0;
116   keyinfo[2].seg[0].charset=cs;
117   keyinfo[3].seg=keyseg+4;
118   keyinfo[3].keysegs=1;
119   keyinfo[3].flag=HA_NOSAME;
120   keyinfo[3].algorithm= HA_KEY_ALG_HASH;
121   keyinfo[3].seg[0].type=HA_KEYTYPE_BINARY;
122   keyinfo[3].seg[0].start=37;
123   keyinfo[3].seg[0].length=1;
124   keyinfo[3].seg[0].null_bit=1;
125   keyinfo[3].seg[0].null_pos=38;
126   keyinfo[3].seg[0].charset=cs;
127 
128   memset(key1, 0, sizeof(key1));
129   memset(key3, 0, sizeof(key3));
130 
131   printf("- Creating heap-file\n");
132   if (heap_create(filename, &hp_create_info, &tmp_share, &unused) ||
133       !(file= heap_open(filename, 2)))
134     goto err;
135   signal(SIGINT,endprog);
136 
137   printf("- Writing records:s\n");
138   strmov((char*) record,"          ..... key");
139 
140   for (i=0 ; i < recant ; i++)
141   {
142     n1= rnd(1000);
143     n2= rnd(100);
144     n3= rnd(MY_MIN(recant * 5, MAX_RECORDS));
145     make_record(record,n1,n2,n3,"Pos",write_count);
146 
147     if (heap_write(file,record))
148     {
149       if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
150       {
151 	printf("Error: %d in write at record: %d\n",my_errno,i);
152 	goto err;
153       }
154       if (verbose) printf("   Double key: %d\n",n3);
155     }
156     else
157     {
158       if (key3[n3] == 1)
159       {
160 	printf("Error: Didn't get error when writing second key: '%8d'\n",n3);
161 	goto err;
162       }
163       write_count++; key1[n1]++; key3[n3]=1;
164       key_check+=n1;
165     }
166     if (testflag == 1 && heap_check_heap(file,0))
167     {
168       puts("Heap keys crashed");
169       goto err;
170     }
171   }
172   if (testflag == 1)
173     goto end;
174   if (heap_check_heap(file,0))
175   {
176     puts("Heap keys crashed");
177     goto err;
178   }
179 
180   printf("- Delete\n");
181   for (i=0 ; i < write_count/10 ; i++)
182   {
183     for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
184     if (j != 0)
185     {
186       sprintf((char*) key,"%6d",j);
187       if (heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT))
188       {
189 	printf("can't find key1: \"%s\"\n",(char*) key);
190 	goto err;
191       }
192       if (heap_delete(file,record))
193       {
194 	printf("error: %d; can't delete record: \"%s\"\n", my_errno,(char*) record);
195 	goto err;
196       }
197       opt_delete++;
198       key1[atoi((char*) record+keyinfo[0].seg[0].start)]--;
199       key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0;
200       key_check-=atoi((char*) record);
201       if (testflag == 2 && heap_check_heap(file,0))
202       {
203 	puts("Heap keys crashed");
204 	goto err;
205       }
206     }
207     else
208       puts("Warning: Skipping delete test because no dupplicate keys");
209   }
210   if (testflag==2) goto end;
211   if (heap_check_heap(file,0))
212   {
213     puts("Heap keys crashed");
214     goto err;
215   }
216 
217   printf("- Update\n");
218   for (i=0 ; i < write_count/10 ; i++)
219   {
220     n1= rnd(1000);
221     n2= rnd(100);
222     n3= rnd(MY_MIN(recant * 2, MAX_RECORDS));
223     make_record(record2, n1, n2, n3, "XXX", update);
224     if (rnd(2) == 1)
225     {
226       if (heap_scan_init(file))
227 	goto err;
228       j=rnd(write_count-opt_delete);
229       while ((error=heap_scan(file,record) == HA_ERR_RECORD_DELETED) ||
230 	     (!error && j))
231       {
232 	if (!error)
233 	  j--;
234       }
235       if (error)
236 	goto err;
237     }
238     else
239     {
240       for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
241       if (!key1[j])
242 	continue;
243       sprintf((char*) key,"%6d",j);
244       if (heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT))
245       {
246 	printf("can't find key1: \"%s\"\n",(char*) key);
247 	goto err;
248       }
249     }
250     if (heap_update(file,record,record2))
251     {
252       if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
253       {
254 	printf("error: %d; can't update:\nFrom: \"%s\"\nTo:   \"%s\"\n",
255 	       my_errno,(char*) record, (char*) record2);
256 	goto err;
257       }
258       if (verbose)
259 	printf("Double key when tried to update:\nFrom: \"%s\"\nTo:   \"%s\"\n",
260                (char*) record, (char*) record2);
261     }
262     else
263     {
264       key1[atoi((char*) record+keyinfo[0].seg[0].start)]--;
265       key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0;
266       key1[n1]++; key3[n3]=1;
267       update++;
268       key_check=key_check-atoi((char*) record)+n1;
269     }
270     if (testflag == 3 && heap_check_heap(file,0))
271     {
272       puts("Heap keys crashed");
273       goto err;
274     }
275   }
276   if (testflag == 3) goto end;
277   if (heap_check_heap(file,0))
278   {
279     puts("Heap keys crashed");
280     goto err;
281   }
282 
283   for (i=999, dupp_keys=found_key=0 ; i>0 ; i--)
284   {
285     if (key1[i] > dupp_keys) { dupp_keys=key1[i]; found_key=i; }
286     sprintf((char*) key,"%6d",found_key);
287   }
288 
289   if (dupp_keys > 3)
290   {
291     if (!silent)
292       printf("- Read first key - next - delete - next -> last\n");
293     DBUG_PRINT("progpos",("first - next - delete - next -> last"));
294 
295     if (heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT))
296       goto err;
297     if (heap_rnext(file,record3)) goto err;
298     if (heap_delete(file,record3)) goto err;
299     key_check-=atoi((char*) record3);
300     key1[atoi((char*) record+keyinfo[0].seg[0].start)]--;
301     key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0;
302     opt_delete++;
303     ant=2;
304     while ((error=heap_rnext(file,record3)) == 0 ||
305 	   error == HA_ERR_RECORD_DELETED)
306       if (! error)
307 	ant++;
308     if (ant != dupp_keys)
309     {
310       printf("next: I can only find: %d records of %d\n",
311 	     ant,dupp_keys);
312       goto end;
313     }
314     dupp_keys--;
315     if (heap_check_heap(file,0))
316     {
317       puts("Heap keys crashed");
318       goto err;
319     }
320 
321     if (!silent)
322       printf("- Read last key - delete - prev - prev - opt_delete - prev -> first\n");
323 
324     if (heap_rlast(file,record3,0)) goto err;
325     if (heap_delete(file,record3)) goto err;
326     key_check-=atoi((char*) record3);
327     key1[atoi((char*) record+keyinfo[0].seg[0].start)]--;
328     key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0;
329     opt_delete++;
330     if (heap_rprev(file,record3) || heap_rprev(file,record3))
331       goto err;
332     if (heap_delete(file,record3)) goto err;
333     key_check-=atoi((char*) record3);
334     key1[atoi((char*) record+keyinfo[0].seg[0].start)]--;
335     key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0;
336     opt_delete++;
337     ant=3;
338     while ((error=heap_rprev(file,record3)) == 0 ||
339 	   error == HA_ERR_RECORD_DELETED)
340     {
341       if (! error)
342 	ant++;
343     }
344     if (ant != dupp_keys)
345     {
346       printf("next: I can only find: %d records of %d\n",
347 	     ant,dupp_keys);
348       goto end;
349     }
350     dupp_keys-=2;
351     if (heap_check_heap(file,0))
352     {
353       puts("Heap keys crashed");
354       goto err;
355     }
356   }
357   else
358     puts("Warning: Not enough duplicated keys:  Skipping delete key check");
359 
360   if (!silent)
361     printf("- Read (first) - next - delete - next -> last\n");
362   DBUG_PRINT("progpos",("first - next - delete - next -> last"));
363 
364   if (heap_scan_init(file))
365     goto err;
366   while ((error=heap_scan(file,record3) == HA_ERR_RECORD_DELETED)) ;
367   if (error)
368     goto err;
369   if (heap_delete(file,record3)) goto err;
370   key_check-=atoi((char*) record3);
371   opt_delete++;
372   key1[atoi((char*) record+keyinfo[0].seg[0].start)]--;
373   key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0;
374   ant=0;
375   while ((error=heap_scan(file,record3)) == 0 ||
376 	 error == HA_ERR_RECORD_DELETED)
377     if (! error)
378       ant++;
379   if (ant != write_count-opt_delete)
380   {
381     printf("next: Found: %d records of %d\n",ant,write_count-opt_delete);
382     goto end;
383   }
384   if (heap_check_heap(file,0))
385   {
386     puts("Heap keys crashed");
387     goto err;
388   }
389 
390   puts("- Test if: Read rrnd - same - rkey - same");
391   DBUG_PRINT("progpos",("Read rrnd - same"));
392   pos=rnd(write_count-opt_delete-5)+5;
393   heap_scan_init(file);
394   i=5;
395   while ((error=heap_scan(file,record)) == HA_ERR_RECORD_DELETED ||
396 	 (error == 0 && pos))
397   {
398     if (!error)
399       pos--;
400     if (!error && (i-- == 0))
401     {
402       bmove(record3,record,reclength);
403       position=heap_position(file);
404     }
405   }
406   if (error)
407     goto err;
408   bmove(record2,record,reclength);
409   if (heap_rsame(file,record,-1) || heap_rsame(file,record2,2))
410     goto err;
411   if (memcmp(record2,record,reclength))
412   {
413     puts("heap_rsame didn't find right record");
414     goto end;
415   }
416 
417   puts("- Test of read through position");
418   if (heap_rrnd(file,record,position))
419     goto err;
420   if (memcmp(record3,record,reclength))
421   {
422     puts("heap_frnd didn't find right record");
423     goto end;
424   }
425 
426   printf("- heap_info\n");
427   {
428     HEAPINFO info;
429     heap_info(file,&info,0);
430     /* We have to test with opt_delete +1 as this may be the case if the last
431        inserted row was a duplicate key */
432     if (info.records != write_count-opt_delete ||
433 	(info.deleted != opt_delete && info.deleted != opt_delete+1))
434     {
435       puts("Wrong info from heap_info");
436       printf("Got: records: %ld(%d)  deleted: %ld(%d)\n",
437 	     info.records,write_count-opt_delete,info.deleted,opt_delete);
438     }
439   }
440 
441 #ifdef OLD_HEAP_VERSION
442   {
443     uint check;
444     printf("- Read through all records with rnd\n");
445     if (heap_extra(file,HA_EXTRA_RESET) || heap_extra(file,HA_EXTRA_CACHE))
446     {
447       puts("got error from heap_extra");
448       goto end;
449     }
450     ant=check=0;
451     while ((error=heap_rrnd(file,record,(ulong) -1)) != HA_ERR_END_OF_FILE &&
452 	   ant < write_count + 10)
453     {
454       if (!error)
455       {
456 	ant++;
457 	check+=calc_check(record,reclength);
458       }
459     }
460     if (ant != write_count-opt_delete)
461     {
462       printf("rrnd: I can only find: %d records of %d\n", ant,
463 	     write_count-opt_delete);
464       goto end;
465     }
466     if (heap_extra(file,HA_EXTRA_NO_CACHE))
467     {
468       puts("got error from heap_extra(HA_EXTRA_NO_CACHE)");
469       goto end;
470     }
471   }
472 #endif
473 
474   printf("- Read through all records with scan\n");
475   if (heap_reset(file) || heap_extra(file,HA_EXTRA_CACHE))
476   {
477     puts("got error from heap_extra");
478     goto end;
479   }
480   ant=check2=0;
481   heap_scan_init(file);
482   while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE &&
483 	 ant < write_count + 10)
484   {
485     if (!error)
486     {
487       ant++;
488       check2+=calc_check(record,reclength);
489     }
490   }
491   if (ant != write_count-opt_delete)
492   {
493     printf("scan: I can only find: %d records of %d\n", ant,
494 	   write_count-opt_delete);
495     goto end;
496   }
497 #ifdef OLD_HEAP_VERSION
498   if (check != check2)
499   {
500     puts("scan: Checksum didn't match reading with rrnd");
501     goto end;
502   }
503 #endif
504 
505 
506   if (heap_extra(file,HA_EXTRA_NO_CACHE))
507   {
508     puts("got error from heap_extra(HA_EXTRA_NO_CACHE)");
509     goto end;
510   }
511 
512   for (i=999, dupp_keys=found_key=0 ; i>0 ; i--)
513   {
514     if (key1[i] > dupp_keys) { dupp_keys=key1[i]; found_key=i; }
515     sprintf((char*) key,"%6d",found_key);
516   }
517   printf("- Read through all keys with first-next-last-prev\n");
518   ant=0;
519   for (error=heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT);
520       ! error ;
521        error=heap_rnext(file,record))
522     ant++;
523   if (ant != dupp_keys)
524   {
525     printf("first-next: I can only find: %d records of %d\n", ant,
526 	   dupp_keys);
527     goto end;
528   }
529 
530   ant=0;
531   for (error=heap_rlast(file,record,0) ;
532       ! error ;
533       error=heap_rprev(file,record))
534   {
535     ant++;
536     check2+=calc_check(record,reclength);
537   }
538   if (ant != dupp_keys)
539   {
540     printf("last-prev: I can only find: %d records of %d\n", ant,
541 	   dupp_keys);
542     goto end;
543   }
544 
545   if (testflag == 4) goto end;
546 
547   printf("- Reading through all rows through keys\n");
548   if (!(file2=heap_open(filename, 2)))
549     goto err;
550   if (heap_scan_init(file))
551     goto err;
552   while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE)
553   {
554     if (error == 0)
555     {
556       if (heap_rkey(file2,record2,2,record+keyinfo[2].seg[0].start,8,
557 		    HA_READ_KEY_EXACT))
558       {
559 	printf("can't find key3: \"%.8s\"\n",
560 	       record+keyinfo[2].seg[0].start);
561 	goto err;
562       }
563     }
564   }
565   heap_close(file2);
566 
567   printf("- Creating output heap-file 2\n");
568   hp_create_info.keys= 1;
569   hp_create_info.max_records= 0;
570   hp_create_info.min_records= 0;
571   if (heap_create(filename2, &hp_create_info, &tmp_share, &unused) ||
572       !(file2= heap_open_from_share_and_register(tmp_share, 2)))
573     goto err;
574 
575   printf("- Copying and removing records\n");
576   if (heap_scan_init(file))
577     goto err;
578   while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE)
579   {
580     if (error == 0)
581     {
582       if (heap_write(file2,record))
583 	goto err;
584       key_check-=atoi((char*) record);
585       write_count++;
586       if (heap_delete(file,record))
587 	goto err;
588       opt_delete++;
589     }
590     pos++;
591   }
592   printf("- Checking heap tables\n");
593   if (heap_check_heap(file,1) || heap_check_heap(file2,1))
594   {
595     puts("Heap keys crashed");
596     goto err;
597   }
598 
599   if (my_errno != HA_ERR_END_OF_FILE)
600     printf("error: %d from heap_rrnd\n",my_errno);
601   if (key_check)
602     printf("error: Some read got wrong: check is %ld\n",(long) key_check);
603 
604 end:
605   printf("\nFollowing test have been made:\n");
606   printf("Write records: %d\nUpdate records: %d\nDelete records: %d\n", write_count,update,opt_delete);
607   heap_clear(file);
608   heap_clear(file2);
609   if (heap_close(file) || (file2 && heap_close(file2)))
610     goto err;
611   heap_delete_table(filename2);
612   hp_panic(HA_PANIC_CLOSE);
613   my_end(MY_GIVE_INFO);
614   return(0);
615 err:
616   printf("Got error: %d when using heap-database\n",my_errno);
617   (void) heap_close(file);
618   return(1);
619 } /* main */
620 
621 
622 	/* Read options */
623 
get_options(int argc,char * argv[])624 static int get_options(int argc,char *argv[])
625 {
626   char *pos,*progname;
627 
628   progname= argv[0];
629 
630   while (--argc >0 && *(pos = *(++argv)) == '-' ) {
631     switch(*++pos) {
632     case 'B':				/* Big file */
633       flag=1;
634       break;
635     case 'v':				/* verbose */
636       verbose=1;
637       break;
638     case 'm':				/* records */
639       recant=atoi(++pos);
640       break;
641     case 's':
642       silent=1;
643       break;
644     case 't':
645       testflag=atoi(++pos);		/* testmod */
646       break;
647     case 'V':
648     case 'I':
649     case '?':
650       printf("%s  Ver 1.1 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
651       puts("TCX Datakonsult AB, by Monty, for your professional use\n");
652       printf("Usage: %s [-?ABIKLsWv] [-m#] [-t#]\n",progname);
653       exit(0);
654     case '#':
655       DBUG_PUSH (++pos);
656       break;
657     }
658   }
659   return 0;
660 } /* get options */
661 
662 	/* Generate a random value in intervall 0 <=x <= n */
663 
rnd(int max_value)664 static int rnd(int max_value)
665 {
666   return (int) ((rand() & 32767)/32767.0*max_value);
667 } /* rnd */
668 
669 
endprog(int sig_number MY_ATTRIBUTE ((unused)))670 static sig_handler endprog(int sig_number MY_ATTRIBUTE((unused)))
671 {
672   {
673     hp_panic(HA_PANIC_CLOSE);
674     my_end(1);
675     exit(1);
676   }
677 }
678 
calc_check(uchar * buf,uint length)679 static int calc_check(uchar *buf, uint length)
680 {
681   int check=0;
682   while (length--)
683     check+= (int) (uchar) *(buf++);
684   return check;
685 }
686 
make_record(uchar * record,uint n1,uint n2,uint n3,const char * mark,uint count)687 static void make_record(uchar *record, uint n1, uint n2, uint n3,
688 			const char *mark, uint count)
689 {
690   memset(record, ' ', reclength);
691   sprintf((char*) record,"%6d:%4d:%8d:%3.3s: %4d",
692 	  n1,n2,n3,mark,count);
693   record[37]='A';				/* Store A in null key */
694   record[38]=1;					/* set as null */
695 }
696