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