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