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