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