1 /* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2 Copyright (c) 2020, MariaDB Corporation.
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 as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
16
17 /* Testing of the basic functions of a MARIA table */
18
19 #include "maria_def.h"
20 #include <my_getopt.h>
21 #include <m_string.h>
22 #include "ma_control_file.h"
23 #include "ma_loghandler.h"
24 #include "ma_checkpoint.h"
25 #include "trnman.h"
26
27 extern PAGECACHE *maria_log_pagecache;
28 extern const char *maria_data_root;
29
30 #define MAX_REC_LENGTH 1024
31
32 static void usage();
33
34 static int rec_pointer_size=0, flags[50], testflag, checkpoint;
35 static int key_field=FIELD_SKIP_PRESPACE,extra_field=FIELD_SKIP_ENDSPACE;
36 static int key_type=HA_KEYTYPE_NUM;
37 static int create_flag=0;
38 static ulong blob_length;
39 static enum data_file_type record_type= DYNAMIC_RECORD;
40
41 static uint insert_count, update_count, remove_count;
42 static uint pack_keys=0, pack_seg=0, key_length;
43 static uint unique_key=HA_NOSAME;
44 static uint die_in_middle_of_transaction;
45 static my_bool pagecacheing, null_fields, silent, skip_update, opt_unique;
46 static my_bool verbose, skip_delete, transactional;
47 static my_bool opt_versioning= 0;
48 static MARIA_COLUMNDEF recinfo[4];
49 static MARIA_KEYDEF keyinfo[10];
50 static HA_KEYSEG keyseg[10];
51 static HA_KEYSEG uniqueseg[10];
52
53 static int run_test(const char *filename);
54 static void get_options(int argc, char *argv[]);
55 static void create_key(uchar *key,uint rownr);
56 static void create_record(uchar *record,uint rownr);
57 static void update_record(uchar *record);
58
59 /*
60 These are here only for testing of recovery with undo. We are not
61 including maria_def.h here as this test is also to be an example of
62 how to use maria outside of the maria directory
63 */
64
65 extern int _ma_flush_table_files(MARIA_HA *info, uint flush_data_or_index,
66 enum flush_type flush_type_for_data,
67 enum flush_type flush_type_for_index);
68 #define MARIA_FLUSH_DATA 1
69
70
main(int argc,char * argv[])71 int main(int argc,char *argv[])
72 {
73 char buff[FN_REFLEN];
74 #ifdef SAFE_MUTEX
75 safe_mutex_deadlock_detector= 1;
76 #endif
77 MY_INIT(argv[0]);
78 maria_data_root= ".";
79 get_options(argc,argv);
80 /* Maria requires that we always have a page cache */
81 if (maria_init() ||
82 (init_pagecache(maria_pagecache, maria_block_size * 16, 0, 0,
83 maria_block_size, 0, MY_WME) == 0) ||
84 ma_control_file_open(TRUE, TRUE, TRUE) ||
85 (init_pagecache(maria_log_pagecache,
86 TRANSLOG_PAGECACHE_SIZE, 0, 0,
87 TRANSLOG_PAGE_SIZE, 0, MY_WME) == 0) ||
88 translog_init(maria_data_root, TRANSLOG_FILE_SIZE,
89 0, 0, maria_log_pagecache,
90 TRANSLOG_DEFAULT_FLAGS, 0) ||
91 (transactional && (trnman_init(0) || ma_checkpoint_init(0))))
92 {
93 fprintf(stderr, "Error in initialization\n");
94 exit(1);
95 }
96 if (opt_versioning)
97 init_thr_lock();
98
99 exit(run_test(fn_format(buff, "test1", maria_data_root, "", MYF(0))));
100 }
101
102
run_test(const char * filename)103 static int run_test(const char *filename)
104 {
105 MARIA_HA *file;
106 int i,j= 0,error,deleted,rec_length,uniques=0;
107 uint offset_to_key;
108 ha_rows found,row_count;
109 uchar record[MAX_REC_LENGTH],key[MAX_REC_LENGTH],read_record[MAX_REC_LENGTH];
110 MARIA_UNIQUEDEF uniquedef;
111 MARIA_CREATE_INFO create_info;
112
113 if (die_in_middle_of_transaction)
114 null_fields= 1;
115
116 bzero((char*) recinfo,sizeof(recinfo));
117 bzero((char*) &create_info,sizeof(create_info));
118
119 /* First define 2 columns */
120 create_info.null_bytes= 1;
121 recinfo[0].type= key_field;
122 recinfo[0].length= (key_field == FIELD_BLOB ? 4+portable_sizeof_char_ptr :
123 key_length);
124 if (key_field == FIELD_VARCHAR)
125 recinfo[0].length+= HA_VARCHAR_PACKLENGTH(key_length);
126 recinfo[1].type=extra_field;
127 recinfo[1].length= (extra_field == FIELD_BLOB ? 4 + portable_sizeof_char_ptr : 24);
128 if (extra_field == FIELD_VARCHAR)
129 recinfo[1].length+= HA_VARCHAR_PACKLENGTH(recinfo[1].length);
130 recinfo[1].null_bit= null_fields ? 2 : 0;
131
132 if (opt_unique)
133 {
134 recinfo[2].type=FIELD_CHECK;
135 recinfo[2].length=MARIA_UNIQUE_HASH_LENGTH;
136 }
137 rec_length= recinfo[0].length + recinfo[1].length + recinfo[2].length +
138 create_info.null_bytes;
139
140 if (key_type == HA_KEYTYPE_VARTEXT1 &&
141 key_length > 255)
142 key_type= HA_KEYTYPE_VARTEXT2;
143
144 /* Define a key over the first column */
145 keyinfo[0].seg=keyseg;
146 keyinfo[0].keysegs=1;
147 keyinfo[0].block_length= 0; /* Default block length */
148 keyinfo[0].key_alg=HA_KEY_ALG_BTREE;
149 keyinfo[0].seg[0].type= key_type;
150 keyinfo[0].seg[0].flag= pack_seg;
151 keyinfo[0].seg[0].start=1;
152 keyinfo[0].seg[0].length=key_length;
153 keyinfo[0].seg[0].null_bit= null_fields ? 2 : 0;
154 keyinfo[0].seg[0].null_pos=0;
155 keyinfo[0].seg[0].language= default_charset_info->number;
156 if (pack_seg & HA_BLOB_PART)
157 {
158 keyinfo[0].seg[0].bit_start=4; /* Length of blob length */
159 }
160 keyinfo[0].flag = (uint8) (pack_keys | unique_key);
161
162 bzero((uchar*) flags,sizeof(flags));
163 if (opt_unique)
164 {
165 uint start;
166 uniques=1;
167 bzero((char*) &uniquedef,sizeof(uniquedef));
168 bzero((char*) uniqueseg,sizeof(uniqueseg));
169 uniquedef.seg=uniqueseg;
170 uniquedef.keysegs=2;
171
172 /* Make a unique over all columns (except first NULL fields) */
173 for (i=0, start=1 ; i < 2 ; i++)
174 {
175 uniqueseg[i].start=start;
176 start+=recinfo[i].length;
177 uniqueseg[i].length=recinfo[i].length;
178 uniqueseg[i].language= default_charset_info->number;
179 }
180 uniqueseg[0].type= key_type;
181 uniqueseg[0].null_bit= null_fields ? 2 : 0;
182 uniqueseg[1].type= HA_KEYTYPE_TEXT;
183 if (extra_field == FIELD_BLOB)
184 {
185 uniqueseg[1].length=0; /* The whole blob */
186 uniqueseg[1].bit_start=4; /* long blob */
187 uniqueseg[1].flag|= HA_BLOB_PART;
188 }
189 else if (extra_field == FIELD_VARCHAR)
190 {
191 uniqueseg[1].flag|= HA_VAR_LENGTH_PART;
192 uniqueseg[1].type= (HA_VARCHAR_PACKLENGTH(recinfo[1].length-1) == 1 ?
193 HA_KEYTYPE_VARTEXT1 : HA_KEYTYPE_VARTEXT2);
194 }
195 }
196 else
197 uniques=0;
198
199 offset_to_key= MY_TEST(null_fields);
200 if (key_field == FIELD_BLOB || key_field == FIELD_VARCHAR)
201 offset_to_key+= 2;
202
203 if (!silent)
204 printf("- Creating maria file\n");
205 create_info.max_rows=(ulong) (rec_pointer_size ?
206 (1L << (rec_pointer_size*8))/40 :
207 0);
208 create_info.transactional= transactional;
209 if (maria_create(filename, record_type, 1, keyinfo,2+opt_unique,recinfo,
210 uniques, &uniquedef, &create_info,
211 create_flag))
212 goto err;
213 if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED, 0)))
214 goto err;
215 if (!silent)
216 printf("- Writing key:s\n");
217
218 if (maria_begin(file))
219 goto err;
220 if (opt_versioning)
221 maria_versioning(file, 1);
222 my_errno=0;
223 row_count=deleted=0;
224 for (i=49 ; i>=1 ; i-=2 )
225 {
226 if (insert_count-- == 0)
227 {
228 if (testflag)
229 break;
230 maria_close(file);
231 exit(0);
232 }
233 j=i%25 +1;
234 create_record(record,j);
235 error=maria_write(file,record);
236 if (!error)
237 row_count++;
238 flags[j]=1;
239 if (verbose || error)
240 printf("J= %2d maria_write: %d errno: %d\n", j,error,my_errno);
241 }
242
243 if (maria_commit(file) || maria_begin(file))
244 goto err;
245
246 if (checkpoint == 1 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
247 goto err;
248
249 if (testflag == 1)
250 goto end;
251
252 /* Insert 2 rows with null values */
253 if (null_fields)
254 {
255 create_record(record,0);
256 error=maria_write(file,record);
257 if (!error)
258 row_count++;
259 if (verbose || error)
260 printf("J= NULL maria_write: %d errno: %d\n", error,my_errno);
261 error=maria_write(file,record);
262 if (!error)
263 row_count++;
264 if (verbose || error)
265 printf("J= NULL maria_write: %d errno: %d\n", error,my_errno);
266 flags[0]=2;
267 }
268
269 if (checkpoint == 2 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
270 goto err;
271
272 if (testflag == 2)
273 {
274 printf("Terminating after inserts\n");
275 goto end;
276 }
277
278 if (maria_commit(file) || maria_begin(file))
279 goto err;
280
281 if (!skip_update)
282 {
283 if (opt_unique)
284 {
285 if (!silent)
286 printf("- Checking unique constraint\n");
287 create_record(record,j); /* Check last created row */
288 if (!maria_write(file,record) || my_errno != HA_ERR_FOUND_DUPP_UNIQUE)
289 {
290 printf("unique check failed\n");
291 }
292 }
293 if (!silent)
294 printf("- Updating rows\n");
295
296 create_key(key, j);
297 if ((maria_rkey(file, read_record, 0, key,
298 HA_WHOLE_KEY, HA_READ_KEY_EXACT)))
299 printf("Can't find last written row with maria_rkey\n");
300
301 /* Update first last row to force extend of file */
302 if (maria_rsame(file,read_record,-1))
303 {
304 printf("Can't find last row with maria_rsame\n");
305 }
306 else
307 {
308 memcpy(record,read_record,rec_length);
309 update_record(record);
310 if (maria_update(file,read_record,record))
311 {
312 printf("Can't update last row: %.*s\n",
313 keyinfo[0].seg[0].length,read_record+1);
314 }
315 }
316
317 /* Read through all rows and update them */
318 maria_scan_init(file);
319
320 found=0;
321 while ((error= maria_scan(file,read_record)) == 0)
322 {
323 if (--update_count == 0) { maria_close(file); exit(0) ; }
324 memcpy(record,read_record,rec_length);
325 update_record(record);
326 if (maria_update(file,read_record,record))
327 {
328 printf("Can't update row: %.*s, error: %d\n",
329 keyinfo[0].seg[0].length,record+1,my_errno);
330 }
331 found++;
332 }
333 if (found != row_count)
334 printf("Found %ld of %ld rows\n", (ulong) found, (ulong) row_count);
335 maria_scan_end(file);
336 }
337
338 if (checkpoint == 3 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
339 goto err;
340
341 if (testflag == 3)
342 {
343 printf("Terminating after updates\n");
344 goto end;
345 }
346 if (!silent)
347 printf("- Reopening file\n");
348 if (maria_commit(file))
349 goto err;
350 if (maria_close(file))
351 goto err;
352 if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED, 0)))
353 goto err;
354 if (maria_begin(file))
355 goto err;
356 if (opt_versioning)
357 maria_versioning(file, 1);
358 if (!skip_delete)
359 {
360 if (!silent)
361 printf("- Removing keys\n");
362
363 for (i=0 ; i <= 10 ; i++)
364 {
365 /*
366 If you want to debug the problem in ma_test_recovery with BLOBs
367 (see @todo there), you can break out of the loop after just one
368 delete, it is enough, like this:
369 if (i==1) break;
370 */
371 /* testing */
372 if (remove_count-- == 0)
373 {
374 fprintf(stderr,
375 "delete-rows number of rows deleted; Going down hard!\n");
376 goto end;
377 }
378 j=i*2;
379 if (!flags[j])
380 continue;
381 create_key(key,j);
382 my_errno=0;
383 if ((error = maria_rkey(file, read_record, 0, key,
384 HA_WHOLE_KEY, HA_READ_KEY_EXACT)))
385 {
386 if (verbose || (flags[j] >= 1 ||
387 (error && my_errno != HA_ERR_KEY_NOT_FOUND)))
388 printf("key: '%.*s' maria_rkey: %3d errno: %3d\n",
389 (int) key_length,key+offset_to_key,error,my_errno);
390 }
391 else
392 {
393 error=maria_delete(file,read_record);
394 if (verbose || error)
395 printf("key: '%.*s' maria_delete: %3d errno: %3d\n",
396 (int) key_length, key+offset_to_key, error, my_errno);
397 if (! error)
398 {
399 deleted++;
400 flags[j]--;
401 }
402 }
403 }
404 }
405
406 if (checkpoint == 4 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
407 goto err;
408
409 if (testflag == 4)
410 {
411 printf("Terminating after deletes\n");
412 goto end;
413 }
414
415 if (!silent)
416 printf("- Reading rows with key\n");
417 record[1]= 0; /* For nicer printf */
418
419 if (record_type == NO_RECORD)
420 maria_extra(file, HA_EXTRA_KEYREAD, 0);
421
422 for (i=0 ; i <= 25 ; i++)
423 {
424 create_key(key,i);
425 my_errno=0;
426 error=maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT);
427 if (verbose ||
428 (error == 0 && flags[i] == 0 && unique_key) ||
429 (error && (flags[i] != 0 || my_errno != HA_ERR_KEY_NOT_FOUND)))
430 {
431 printf("key: '%.*s' maria_rkey: %3d errno: %3d record: %s\n",
432 (int) key_length,key+offset_to_key,error,my_errno,record+1);
433 }
434 }
435 if (record_type == NO_RECORD)
436 {
437 maria_extra(file, HA_EXTRA_NO_KEYREAD, 0);
438 goto end;
439 }
440
441 if (!silent)
442 printf("- Reading rows with position\n");
443
444 if (maria_scan_init(file))
445 {
446 fprintf(stderr, "maria_scan_init failed\n");
447 goto err;
448 }
449
450 for (i=1,found=0 ; i <= 30 ; i++)
451 {
452 my_errno=0;
453 if ((error= maria_scan(file, read_record)) == HA_ERR_END_OF_FILE)
454 {
455 if (found != row_count-deleted)
456 printf("Found only %ld of %ld rows\n", (ulong) found,
457 (ulong) (row_count - deleted));
458 break;
459 }
460 if (!error)
461 found++;
462 if (verbose || (error != 0 && error != HA_ERR_RECORD_DELETED &&
463 error != HA_ERR_END_OF_FILE))
464 {
465 printf("pos: %2d maria_rrnd: %3d errno: %3d record: %s\n",
466 i-1,error,my_errno,read_record+1);
467 }
468 }
469 maria_scan_end(file);
470
471 end:
472 if (die_in_middle_of_transaction)
473 {
474 /* As commit record is not done, UNDO entries needs to be rolled back */
475 switch (die_in_middle_of_transaction) {
476 case 1:
477 /*
478 Flush changed pages go to disk. That will also flush log. Recovery
479 will skip REDOs and apply UNDOs.
480 */
481 _ma_flush_table_files(file, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
482 FLUSH_RELEASE, FLUSH_RELEASE);
483 break;
484 case 2:
485 /*
486 Just flush log. Pages are likely to not be on disk. Recovery will
487 then execute REDOs and UNDOs.
488 */
489 if (translog_flush(file->trn->undo_lsn))
490 goto err;
491 break;
492 case 3:
493 /*
494 Flush nothing. Pages and log are likely to not be on disk. Recovery
495 will then do nothing.
496 */
497 break;
498 case 4:
499 /*
500 Flush changed data pages go to disk. Changed index pages are not
501 flushed. Recovery will skip some REDOs and apply UNDOs.
502 */
503 _ma_flush_table_files(file, MARIA_FLUSH_DATA, FLUSH_RELEASE,
504 FLUSH_RELEASE);
505 /*
506 We have to flush log separately as the redo for the last key page
507 may not be flushed
508 */
509 if (translog_flush(file->trn->undo_lsn))
510 goto err;
511 break;
512 }
513 printf("Dying on request without maria_commit()/maria_close()\n");
514 sf_leaking_memory= 1;
515 exit(0);
516 }
517
518 if (maria_commit(file))
519 goto err;
520 if (maria_close(file))
521 goto err;
522 maria_end();
523 my_uuid_end();
524 my_end(MY_CHECK_ERROR);
525
526 return (0);
527 err:
528 printf("got error: %3d when using maria-database\n",my_errno);
529 return 1; /* skip warning */
530 }
531
532
create_key_part(uchar * key,uint rownr)533 static void create_key_part(uchar *key,uint rownr)
534 {
535 if (!unique_key)
536 rownr&=7; /* Some identical keys */
537 if (keyinfo[0].seg[0].type == HA_KEYTYPE_NUM)
538 {
539 sprintf((char*) key,"%*d",keyinfo[0].seg[0].length,rownr);
540 }
541 else if (keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT1 ||
542 keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT2)
543 { /* Alpha record */
544 /* Create a key that may be easily packed */
545 bfill(key,keyinfo[0].seg[0].length,rownr < 10 ? 'A' : 'B');
546 sprintf((char*) key+keyinfo[0].seg[0].length-2,"%-2d",rownr);
547 if ((rownr & 7) == 0)
548 {
549 /* Change the key to force a unpack of the next key */
550 bfill(key+3,keyinfo[0].seg[0].length-5,rownr < 10 ? 'a' : 'b');
551 }
552 }
553 else
554 { /* Alpha record */
555 if (keyinfo[0].seg[0].flag & HA_SPACE_PACK)
556 sprintf((char*) key,"%-*d",keyinfo[0].seg[0].length,rownr);
557 else
558 {
559 /* Create a key that may be easily packed */
560 bfill(key,keyinfo[0].seg[0].length,rownr < 10 ? 'A' : 'B');
561 sprintf((char*) key+keyinfo[0].seg[0].length-2,"%-2d",rownr);
562 if ((rownr & 7) == 0)
563 {
564 /* Change the key to force a unpack of the next key */
565 key[1]= (rownr < 10 ? 'a' : 'b');
566 }
567 }
568 }
569 }
570
571
create_key(uchar * key,uint rownr)572 static void create_key(uchar *key,uint rownr)
573 {
574 if (keyinfo[0].seg[0].null_bit)
575 {
576 if (rownr == 0)
577 {
578 key[0]=1; /* null key */
579 key[1]=0; /* For easy print of key */
580 return;
581 }
582 *key++=0;
583 }
584 if (keyinfo[0].seg[0].flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
585 {
586 size_t tmp;
587 create_key_part(key+2,rownr);
588 tmp=strlen((char*) key+2);
589 int2store(key,tmp);
590 }
591 else
592 create_key_part(key,rownr);
593 }
594
595
596 static uchar blob_key[MAX_REC_LENGTH];
597 static uchar blob_record[MAX_REC_LENGTH+20*20];
598
599
create_record(uchar * record,uint rownr)600 static void create_record(uchar *record,uint rownr)
601 {
602 uchar *pos;
603 bzero((char*) record,MAX_REC_LENGTH);
604 record[0]=1; /* delete marker */
605 if (rownr == 0 && keyinfo[0].seg[0].null_bit)
606 record[0]|=keyinfo[0].seg[0].null_bit; /* Null key */
607
608 pos=record+1;
609 if (recinfo[0].type == FIELD_BLOB)
610 {
611 size_t tmp;
612 uchar *ptr;
613 create_key_part(blob_key,rownr);
614 tmp=strlen((char*) blob_key);
615 int4store(pos,tmp);
616 ptr=blob_key;
617 memcpy(pos+4,&ptr,sizeof(char*));
618 pos+=recinfo[0].length;
619 }
620 else if (recinfo[0].type == FIELD_VARCHAR)
621 {
622 size_t tmp, pack_length= HA_VARCHAR_PACKLENGTH(recinfo[0].length-1);
623 create_key_part(pos+pack_length,rownr);
624 tmp= strlen((char*) pos+pack_length);
625 if (pack_length == 1)
626 *(uchar*) pos= (uchar) tmp;
627 else
628 int2store(pos,tmp);
629 pos+= recinfo[0].length;
630 }
631 else
632 {
633 create_key_part(pos,rownr);
634 pos+=recinfo[0].length;
635 }
636 if (recinfo[1].type == FIELD_BLOB)
637 {
638 size_t tmp;
639 uchar *ptr;;
640 sprintf((char*) blob_record,"... row: %d", rownr);
641 strappend((char*) blob_record,MY_MAX(MAX_REC_LENGTH-rownr,10),' ');
642 tmp=strlen((char*) blob_record);
643 int4store(pos,tmp);
644 ptr=blob_record;
645 memcpy(pos+4,&ptr,sizeof(char*));
646 }
647 else if (recinfo[1].type == FIELD_VARCHAR)
648 {
649 size_t tmp, pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1);
650 sprintf((char*) pos+pack_length, "... row: %d", rownr);
651 tmp= strlen((char*) pos+pack_length);
652 if (pack_length == 1)
653 *pos= (uchar) tmp;
654 else
655 int2store(pos,tmp);
656 }
657 else
658 {
659 sprintf((char*) pos,"... row: %d", rownr);
660 strappend((char*) pos,recinfo[1].length,' ');
661 }
662 }
663
664 /* change row to test re-packing of rows and reallocation of keys */
665
update_record(uchar * record)666 static void update_record(uchar *record)
667 {
668 uchar *pos=record+1;
669 if (recinfo[0].type == FIELD_BLOB)
670 {
671 uchar *column,*ptr;
672 int length;
673 length=uint4korr(pos); /* Long blob */
674 memcpy(&column,pos+4,sizeof(char*));
675 memcpy(blob_key,column,length); /* Move old key */
676 ptr=blob_key;
677 memcpy(pos+4,&ptr,sizeof(char*)); /* Store pointer to new key */
678 if (keyinfo[0].seg[0].type != HA_KEYTYPE_NUM)
679 my_ci_casedn(default_charset_info, (char*) blob_key, length,
680 (char*) blob_key, length);
681 pos+=recinfo[0].length;
682 }
683 else if (recinfo[0].type == FIELD_VARCHAR)
684 {
685 uint pack_length= HA_VARCHAR_PACKLENGTH(recinfo[0].length-1);
686 uint length= pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos);
687 my_ci_casedn(default_charset_info, (char*) pos + pack_length, length,
688 (char*) pos + pack_length, length);
689 pos+=recinfo[0].length;
690 }
691 else
692 {
693 if (keyinfo[0].seg[0].type != HA_KEYTYPE_NUM)
694 my_ci_casedn(default_charset_info, (char*) pos, keyinfo[0].seg[0].length,
695 (char*) pos, keyinfo[0].seg[0].length);
696 pos+=recinfo[0].length;
697 }
698
699 if (recinfo[1].type == FIELD_BLOB)
700 {
701 uchar *column;
702 int length;
703 length=uint4korr(pos);
704 memcpy(&column,pos+4,sizeof(char*));
705 memcpy(blob_record,column,length);
706 bfill(blob_record+length,20,'.'); /* Make it larger */
707 length+=20;
708 int4store(pos,length);
709 column=blob_record;
710 memcpy(pos+4,&column,sizeof(char*));
711 }
712 else if (recinfo[1].type == FIELD_VARCHAR)
713 {
714 /* Second field is longer than 10 characters */
715 uint pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1);
716 uint length= pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos);
717 pos= record+ recinfo[1].offset;
718 bfill(pos+pack_length+length,recinfo[1].length-length-pack_length,'.');
719 length=recinfo[1].length-pack_length;
720 if (pack_length == 1)
721 *(uchar*) pos= (uchar) length;
722 else
723 int2store(pos,length);
724 }
725 else
726 {
727 bfill(pos+recinfo[1].length-10,10,'.');
728 }
729 }
730
731
732 static struct my_option my_long_options[] =
733 {
734 {"checkpoint", 'H', "Checkpoint at specified stage", (uchar**) &checkpoint,
735 (uchar**) &checkpoint, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
736 {"checksum", 'c', "Undocumented",
737 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
738 #ifndef DBUG_OFF
739 {"debug", '#', "Undocumented",
740 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
741 #endif
742 {"datadir", 'h', "Path to the database root.", (char**) &maria_data_root,
743 (char**) &maria_data_root, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
744 {"delete-rows", 'd', "Abort after this many rows has been deleted",
745 (uchar**) &remove_count, (uchar**) &remove_count, 0, GET_UINT, REQUIRED_ARG,
746 1000, 0, 0, 0, 0, 0},
747 {"help", '?', "Display help and exit",
748 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
749 {"insert-rows", 'i', "Undocumented", (uchar**) &insert_count,
750 (uchar**) &insert_count, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0},
751 {"key-alpha", 'a', "Use a key of type HA_KEYTYPE_TEXT",
752 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
753 {"key-binary-pack", 'B', "Undocumented",
754 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
755 {"key-blob", 'b', "Undocumented",
756 (uchar**) &blob_length, (uchar**) &blob_length,
757 0, GET_ULONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
758 {"key-cache", 'K', "Undocumented", (uchar**) &pagecacheing,
759 (uchar**) &pagecacheing, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
760 {"key-length", 'k', "Undocumented", (uchar**) &key_length,
761 (uchar**) &key_length, 0, GET_UINT, REQUIRED_ARG, 6, 0, 0, 0, 0, 0},
762 {"key-multiple", 'm', "Don't use unique keys",
763 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
764 {"key-prefix_pack", 'P', "Undocumented",
765 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
766 {"key-space_pack", 'p', "Undocumented",
767 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
768 {"key-varchar", 'w', "Test VARCHAR keys",
769 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
770 {"null-fields", 'N', "Define fields with NULL",
771 (uchar**) &null_fields, (uchar**) &null_fields, 0, GET_BOOL, NO_ARG,
772 0, 0, 0, 0, 0, 0},
773 {"row-fixed-size", 'S', "Fixed size records",
774 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
775 {"rows-in-block", 'M', "Store rows in block format",
776 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
777 {"rows-no-data", 'n', "Don't store any data, only keys",
778 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
779 {"row-pointer-size", 'R', "Undocumented", (uchar**) &rec_pointer_size,
780 (uchar**) &rec_pointer_size, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
781 {"silent", 's', "Undocumented",
782 (uchar**) &silent, (uchar**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
783 0, 0},
784 {"skip-delete", 'D', "Don't test deletes", (uchar**) &skip_delete,
785 (uchar**) &skip_delete, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
786 {"skip-update", 'U', "Don't test updates", (uchar**) &skip_update,
787 (uchar**) &skip_update, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
788 {"testflag", 't', "Stop test at specified stage", (uchar**) &testflag,
789 (uchar**) &testflag, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
790 {"test-undo", 'A',
791 "Abort hard. Used for testing recovery with undo",
792 (uchar**) &die_in_middle_of_transaction,
793 (uchar**) &die_in_middle_of_transaction,
794 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
795 {"transactional", 'T',
796 "Test in transactional mode. (Only works with block format)",
797 (uchar**) &transactional, (uchar**) &transactional, 0, GET_BOOL, NO_ARG,
798 0, 0, 0, 0, 0, 0},
799 {"unique", 'E', "Check unique handling", (uchar**) &opt_unique,
800 (uchar**) &opt_unique, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
801 {"update-rows", 'u', "Max number of rows to update", (uchar**) &update_count,
802 (uchar**) &update_count, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0},
803 {"verbose", 'v', "Be more verbose", (uchar**) &verbose,
804 (uchar**) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
805 {"version", 'V', "Print version number and exit",
806 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
807 {"versioning", 'C', "Use row versioning (only works with block format)",
808 (uchar**) &opt_versioning, (uchar**) &opt_versioning, 0, GET_BOOL,
809 NO_ARG, 0, 0, 0, 0, 0, 0},
810 { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
811 };
812
813
814 static my_bool
get_one_option(const struct my_option * opt,const char * argument,const char * filename)815 get_one_option(const struct my_option *opt,
816 const char *argument __attribute__((unused)),
817 const char *filename __attribute__((unused)))
818 {
819 switch(opt->id) {
820 case 'a':
821 key_type= HA_KEYTYPE_TEXT;
822 break;
823 case 'c':
824 create_flag|= HA_CREATE_CHECKSUM | HA_CREATE_PAGE_CHECKSUM;
825 break;
826 case 'R': /* Length of record pointer */
827 if (rec_pointer_size > 3)
828 rec_pointer_size=0;
829 break;
830 case 'P':
831 pack_keys= HA_PACK_KEY; /* Use prefix compression */
832 break;
833 case 'B':
834 pack_keys= HA_BINARY_PACK_KEY; /* Use binary compression */
835 break;
836 case 'M':
837 record_type= BLOCK_RECORD;
838 break;
839 case 'n':
840 record_type= NO_RECORD;
841 break;
842 case 'S':
843 if (key_field == FIELD_VARCHAR)
844 {
845 create_flag=0; /* Static sized varchar */
846 record_type= STATIC_RECORD;
847 }
848 else if (key_field != FIELD_BLOB)
849 {
850 key_field=FIELD_NORMAL; /* static-size record */
851 extra_field=FIELD_NORMAL;
852 record_type= STATIC_RECORD;
853 }
854 break;
855 case 'p':
856 pack_keys=HA_PACK_KEY; /* Use prefix + space packing */
857 pack_seg=HA_SPACE_PACK;
858 key_type=HA_KEYTYPE_TEXT;
859 break;
860 case 'm':
861 unique_key=0;
862 break;
863 case 'b':
864 key_field=FIELD_BLOB; /* blob key */
865 extra_field= FIELD_BLOB;
866 pack_seg|= HA_BLOB_PART;
867 key_type= HA_KEYTYPE_VARTEXT1;
868 if (record_type == STATIC_RECORD)
869 record_type= DYNAMIC_RECORD;
870 break;
871 case 'k':
872 if (key_length < 4 || key_length > MARIA_MAX_KEY_LENGTH)
873 {
874 fprintf(stderr,"Wrong key length\n");
875 exit(1);
876 }
877 break;
878 case 'w':
879 key_field=FIELD_VARCHAR; /* varchar keys */
880 extra_field= FIELD_VARCHAR;
881 key_type= HA_KEYTYPE_VARTEXT1;
882 pack_seg|= HA_VAR_LENGTH_PART;
883 if (record_type == STATIC_RECORD)
884 record_type= DYNAMIC_RECORD;
885 break;
886 case 'K': /* Use key cacheing */
887 pagecacheing=1;
888 break;
889 case 'V':
890 printf("test1 Ver 1.2 \n");
891 exit(0);
892 case '#':
893 DBUG_PUSH(argument);
894 break;
895 case '?':
896 usage();
897 exit(1);
898 }
899 return 0;
900 }
901
902
903 /* Read options */
904
get_options(int argc,char * argv[])905 static void get_options(int argc, char *argv[])
906 {
907 int ho_error;
908
909 if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
910 exit(ho_error);
911 if (transactional)
912 record_type= BLOCK_RECORD;
913 if (record_type == NO_RECORD)
914 skip_update= skip_delete= 1;
915
916
917 return;
918 } /* get options */
919
920
usage()921 static void usage()
922 {
923 printf("Usage: %s [options]\n\n", my_progname);
924 my_print_help(my_long_options);
925 my_print_variables(my_long_options);
926 }
927
928 #include "ma_check_standalone.h"
929
930