1
/* Copyright (C) 2000-2003 MySQL AB
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.
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.
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 */
16
/* Describe, check and repair of MyISAM tables */
18
#include <drizzled/global.h>
20
#include <mystrings/m_ctype.h>
23
#include <mysys/my_getopt.h>
24
#include <mysys/my_bit.h>
26
#include <mystrings/m_string.h>
27
#ifdef HAVE_SYS_VADVICE_H
28
#include <sys/vadvise.h>
30
#ifdef HAVE_SYS_MMAN_H
33
#include <drizzled/util/test.h>
35
#include "myisamdef.h"
37
pthread_mutex_t THR_LOCK_myisam= PTHREAD_MUTEX_INITIALIZER;
39
static uint32_t decode_bits;
40
static char **default_argv;
41
static const char *load_default_groups[]= { "myisamchk", 0 };
42
static const char *set_collation_name, *opt_tmpdir;
43
static const CHARSET_INFO *set_collation;
44
static long opt_myisam_block_size;
45
static long opt_key_cache_block_size;
46
static const char *my_progname_short;
47
static MY_TMPDIR myisamchk_tmpdir;
49
static const char *type_names[]=
50
{ "impossible","char","binary", "short", "long", "float",
51
"double","number","unsigned short",
52
"unsigned long","int64_t","uint64_t","int24",
53
"uint24","int8","varchar", "varbin","?",
56
static const char *prefix_packed_txt="packed ",
57
*bin_packed_txt="prefix ",
58
*diff_txt="stripped ",
62
static const char *field_pack[]=
63
{"","no endspace", "no prespace",
64
"no zeros", "blob", "constant", "table-lockup",
65
"always zero","varchar","unique-hash","?","?"};
67
static const char *myisam_stats_method_str="nulls_unequal";
69
static void get_options(int *argc,char * * *argv);
70
static void print_version(void);
71
static void usage(void);
72
static int myisamchk(MI_CHECK *param, char *filename);
73
static void descript(MI_CHECK *param, register MI_INFO *info, char * name);
74
static int mi_sort_records(MI_CHECK *param, register MI_INFO *info,
75
char * name, uint32_t sort_key,
76
bool write_info, bool update_index);
77
static int sort_record_index(MI_SORT_PARAM *sort_param, MI_INFO *info,
79
my_off_t page,unsigned char *buff,uint32_t sortkey,
80
File new_file, bool update_index);
86
int main(int argc, char **argv)
90
my_progname_short= my_progname+dirname_length(my_progname);
92
myisamchk_init(&check_param);
93
check_param.opt_lock_memory=1; /* Lock memory if possible */
94
check_param.using_global_keycache = 0;
95
get_options(&argc,(char***) &argv);
96
myisam_quick_table_bits=decode_bits;
100
int new_error=myisamchk(&check_param, *(argv++));
101
if ((check_param.testflag & T_REP_ANY) != T_REP)
102
check_param.testflag&= ~T_REP;
105
if ((check_param.error_printed | check_param.warning_printed) &&
106
(check_param.testflag & T_FORCE_CREATE) &&
107
(!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
110
uint32_t old_testflag=check_param.testflag;
111
if (!(check_param.testflag & T_REP))
112
check_param.testflag|= T_REP_BY_SORT;
113
check_param.testflag&= ~T_EXTEND; /* Don't needed */
114
error|=myisamchk(&check_param, argv[-1]);
115
check_param.testflag= old_testflag;
121
if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
123
puts("\n---------\n");
127
if (check_param.total_files > 1)
128
{ /* Only if descript */
129
char buff[22],buff2[22];
130
if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
131
puts("\n---------\n");
132
printf("\nTotal of all %d MyISAM-files:\nData records: %9s Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
133
llstr(check_param.total_deleted,buff2));
136
pthread_mutex_destroy(&THR_LOCK_myisam);
138
free_defaults(default_argv);
139
free_tmpdir(&myisamchk_tmpdir);
140
my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
143
return 0; /* No compiler warning */
148
OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
149
OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE,
150
OPT_KEY_CACHE_BLOCK_SIZE, OPT_MYISAM_BLOCK_SIZE,
151
OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
152
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS,
153
OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD
156
static struct my_option my_long_options[] =
159
"Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
160
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
161
{"block-search", 'b',
162
"No help available.",
163
0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
165
"Make a backup of the .MYD file as 'filename-time.BAK'.",
166
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
167
{"character-sets-dir", OPT_CHARSETS_DIR,
168
"Directory where character sets are.",
169
(char**) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
171
"Check table for errors.",
172
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
173
{"check-only-changed", 'C',
174
"Check only tables that have changed since last check. It also applies to other requested actions (e.g. --analyze will be ignored if the table is already analyzed).",
175
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
176
{"correct-checksum", OPT_CORRECT_CHECKSUM,
177
"Correct checksum information for table.",
178
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
180
"Prints some information about table.",
181
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
182
{"data-file-length", 'D',
183
"Max length of data file (when recreating data-file when it's full).",
184
(char**) &check_param.max_data_file_length,
185
(char**) &check_param.max_data_file_length,
186
0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
187
{"extend-check", 'e',
188
"If used when checking a table, ensure that the table is 100 percent consistent, which will take a long time. If used when repairing a table, try to recover every possible row from the data file. Normally this will also find a lot of garbage rows; Don't use this option with repair if you are not totally desperate.",
189
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
191
"Check only tables that haven't been closed properly. It also applies to other requested actions (e.g. --analyze will be ignored if the table is already analyzed).",
192
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
194
"Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
195
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
197
"Display this help and exit.",
198
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
200
"Display this help and exit.",
201
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
203
"Print statistics information about table that is checked.",
204
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
206
"Tell MyISAM to update only some specific keys. # is a bit mask of which keys to use. This can be used to get faster inserts.",
207
(char**) &check_param.keys_in_use,
208
(char**) &check_param.keys_in_use,
209
0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
210
{"max-record-length", OPT_MAX_RECORD_LENGTH,
211
"Skip rows bigger than this if myisamchk can't allocate memory to hold it",
212
(char**) &check_param.max_record_length,
213
(char**) &check_param.max_record_length,
214
0, GET_ULL, REQUIRED_ARG, INT64_MAX, 0, INT64_MAX, 0, 0, 0},
215
{"medium-check", 'm',
216
"Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
217
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
218
{"quick", 'q', "Faster repair by not modifying the data file.",
219
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
221
"Don't mark table as checked.",
222
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
224
"Can fix almost anything except unique keys that aren't unique.",
225
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
226
{"parallel-recover", 'p',
227
"Same as '-r' but creates all the keys in parallel.",
228
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
229
{"safe-recover", 'o',
230
"Uses old recovery method; Slower than '-r' but can handle a couple of cases where '-r' reports that it can't fix the data file.",
231
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
232
{"sort-recover", 'n',
233
"Force recovering with sorting even if the temporary file was very big.",
234
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
236
{"start-check-pos", OPT_START_CHECK_POS,
237
"No help available.",
238
0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
240
{"set-auto-increment", 'A',
241
"Force auto_increment to start at this or higher value. If no value is given, then sets the next auto_increment value to the highest used value for the auto key + 1.",
242
(char**) &check_param.auto_increment_value,
243
(char**) &check_param.auto_increment_value,
244
0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
245
{"set-collation", OPT_SET_COLLATION,
246
"Change the collation used by the index",
247
(char**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
248
{"set-variable", 'O',
249
"Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
250
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
252
"Only print errors. One can use two -s to make myisamchk very silent.",
253
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
255
"Sort index blocks. This speeds up 'read-next' in applications.",
256
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
257
{"sort-records", 'R',
258
"Sort records according to an index. This makes your data much more localized and may speed up things. (It may be VERY slow to do a sort the first time!)",
259
(char**) &check_param.opt_sort_key,
260
(char**) &check_param.opt_sort_key,
261
0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
263
"Path for temporary files.",
264
(char**) &opt_tmpdir,
265
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
266
{"update-state", 'U',
267
"Mark tables as crashed if any errors were found.",
268
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
270
"Unpack file packed with myisampack.",
271
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
273
"Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
274
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
276
"Print version and exit.",
277
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
279
"Wait if table is locked.",
280
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
281
{ "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
282
(char**) &check_param.use_buffers, (char**) &check_param.use_buffers, 0,
283
GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
284
INT32_MAX, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
285
{ "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "",
286
(char**) &opt_key_cache_block_size,
287
(char**) &opt_key_cache_block_size, 0,
288
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
289
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
290
{ "myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "",
291
(char**) &opt_myisam_block_size, (char**) &opt_myisam_block_size, 0,
292
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
293
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
294
{ "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
295
(char**) &check_param.read_buffer_length,
296
(char**) &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
297
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
298
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
299
{ "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
300
(char**) &check_param.write_buffer_length,
301
(char**) &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
302
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
303
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
304
{ "sort_buffer_size", OPT_SORT_BUFFER_SIZE, "",
305
(char**) &check_param.sort_buffer_length,
306
(char**) &check_param.sort_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
307
(long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
308
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
309
{ "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
310
(char**) &check_param.sort_key_blocks,
311
(char**) &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
312
BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
313
{ "decode_bits", OPT_DECODE_BITS, "", (char**) &decode_bits,
314
(char**) &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
315
{"stats_method", OPT_STATS_METHOD,
316
"Specifies how index statistics collection code should treat NULLs. "
317
"Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
318
"\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
319
(char**) &myisam_stats_method_str, (char**) &myisam_stats_method_str, 0,
320
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
321
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
325
static void print_version(void)
327
printf("%s Ver 2.7 for %s at %s\n", my_progname, SYSTEM_TYPE,
332
static void usage(void)
335
puts("By Monty, for your professional use");
336
puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
337
puts("Description, check and repair of MyISAM tables.");
338
puts("Used without options all tables on the command will be checked for errors");
339
printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname_short);
340
printf("\nGlobal options:\n");
342
-?, --help Display this help and exit.\n\
343
-O, --set-variable var=option.\n\
344
Change the value of a variable. Please note that\n\
345
this option is deprecated; you can set variables\n\
346
directly with '--variable-name=value'.\n\
347
-t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
348
specified, separated by ");
349
#if defined( __WIN__)
350
printf("semicolon (;)");
354
printf(", they will be used\n\
355
in a round-robin fashion.\n\
356
-s, --silent Only print errors. One can use two -s to make\n\
357
myisamchk very silent.\n\
358
-v, --verbose Print more information. This can be used with\n\
359
--description and --check. Use many -v for more verbosity.\n\
360
-V, --version Print version and exit.\n\
361
-w, --wait Wait if table is locked.\n\n");
363
puts(" --start-check-pos=# Start reading file at given offset.\n");
366
puts("Check options (check is the default action for myisamchk):\n\
367
-c, --check Check table for errors.\n\
368
-e, --extend-check Check the table VERY throughly. Only use this in\n\
369
extreme cases as myisamchk should normally be able to\n\
370
find out if the table is ok even without this switch.\n\
371
-F, --fast Check only tables that haven't been closed properly.\n\
372
-C, --check-only-changed\n\
373
Check only tables that have changed since last check.\n\
374
-f, --force Restart with '-r' if there are any errors in the table.\n\
375
States will be updated as with '--update-state'.\n\
376
-i, --information Print statistics information about table that is checked.\n\
377
-m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
378
all errors. Should be good enough for most cases.\n\
379
-U --update-state Mark tables as crashed if you find any errors.\n\
380
-T, --read-only Don't mark table as checked.\n");
382
puts("Repair options (When using '-r' or '-o'):\n\
383
-B, --backup Make a backup of the .MYD file as 'filename-time.BAK'.\n\
384
--correct-checksum Correct checksum information for table.\n\
385
-D, --data-file-length=# Max length of data file (when recreating data\n\
386
file when it's full).\n\
387
-e, --extend-check Try to recover every possible row from the data file\n\
388
Normally this will also find a lot of garbage rows;\n\
389
Don't use this option if you are not totally desperate.\n\
390
-f, --force Overwrite old temporary files.\n\
391
-k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\
392
bit mask of which keys to use. This can be used to\n\
393
get faster inserts.\n\
394
--max-record-length=#\n\
395
Skip rows bigger than this if myisamchk can't allocate\n\
396
memory to hold it.\n\
397
-r, --recover Can fix almost anything except unique keys that aren't\n\
399
-n, --sort-recover Forces recovering with sorting even if the temporary\n\
400
file would be very big.\n\
401
-p, --parallel-recover\n\
402
Uses the same technique as '-r' and '-n', but creates\n\
403
all the keys in parallel, in different threads.\n\
404
-o, --safe-recover Uses old recovery method; Slower than '-r' but can\n\
405
handle a couple of cases where '-r' reports that it\n\
406
can't fix the data file.\n\
407
--character-sets-dir=...\n\
408
Directory where character sets are.\n\
409
--set-collation=name\n\
410
Change the collation used by the index.\n\
411
-q, --quick Faster repair by not modifying the data file.\n\
412
One can give a second '-q' to force myisamchk to\n\
413
modify the original datafile in case of duplicate keys.\n\
414
NOTE: Tables where the data file is currupted can't be\n\
415
fixed with this option.\n\
416
-u, --unpack Unpack file packed with myisampack.\n\
419
puts("Other actions:\n\
420
-a, --analyze Analyze distribution of keys. Will make some joins in\n\
421
MySQL faster. You can check the calculated distribution\n\
422
by using '--description --verbose table_name'.\n\
423
--stats_method=name Specifies how index statistics collection code should\n\
424
treat NULLs. Possible values of name are \"nulls_unequal\"\n\
425
(default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
426
\"nulls_ignored\".\n\
427
-d, --description Prints some information about table.\n\
428
-A, --set-auto-increment[=value]\n\
429
Force auto_increment to start at this or higher value\n\
430
If no value is given, then sets the next auto_increment\n\
431
value to the highest used value for the auto key + 1.\n\
432
-S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
434
-R, --sort-records=#\n\
435
Sort records according to an index. This makes your\n\
436
data much more localized and may speed up things\n\
437
(It may be VERY slow to do a sort the first time!).\n\
438
-b, --block-search=#\n\
439
Find a record, a block at given offset belongs to.");
441
print_defaults("drizzle", load_default_groups);
442
my_print_variables(my_long_options);
445
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
446
"nulls_ignored", NULL};
447
TYPELIB myisam_stats_method_typelib= {
448
array_elements(myisam_stats_method_names) - 1, "",
449
myisam_stats_method_names, NULL};
454
get_one_option(int optid,
455
const struct my_option *opt __attribute__((unused)),
460
if (argument == disabled_my_option)
461
check_param.testflag&= ~T_STATISTICS;
463
check_param.testflag|= T_STATISTICS;
467
check_param.auto_increment_value= strtoull(argument, NULL, 0);
469
check_param.auto_increment_value= 0; /* Set to max used value */
470
check_param.testflag|= T_AUTO_INC;
473
check_param.search_after_block= strtoul(argument, NULL, 10);
476
if (argument == disabled_my_option)
477
check_param.testflag&= ~T_BACKUP_DATA;
479
check_param.testflag|= T_BACKUP_DATA;
482
if (argument == disabled_my_option)
483
check_param.testflag&= ~T_CHECK;
485
check_param.testflag|= T_CHECK;
488
if (argument == disabled_my_option)
489
check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
491
check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
494
check_param.max_data_file_length=strtoll(argument, NULL, 10);
496
case 's': /* silent */
497
if (argument == disabled_my_option)
498
check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
501
if (check_param.testflag & T_SILENT)
502
check_param.testflag|= T_VERY_SILENT;
503
check_param.testflag|= T_SILENT;
504
check_param.testflag&= ~T_WRITE_LOOP;
508
if (argument == disabled_my_option)
509
check_param.testflag&= ~T_WAIT_FOREVER;
511
check_param.testflag|= T_WAIT_FOREVER;
513
case 'd': /* description if isam-file */
514
if (argument == disabled_my_option)
515
check_param.testflag&= ~T_DESCRIPT;
517
check_param.testflag|= T_DESCRIPT;
519
case 'e': /* extend check */
520
if (argument == disabled_my_option)
521
check_param.testflag&= ~T_EXTEND;
523
check_param.testflag|= T_EXTEND;
526
if (argument == disabled_my_option)
527
check_param.testflag&= ~T_INFO;
529
check_param.testflag|= T_INFO;
532
if (argument == disabled_my_option)
534
check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
535
check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
539
check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
540
check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
544
if (argument == disabled_my_option)
545
check_param.testflag&= ~T_FAST;
547
check_param.testflag|= T_FAST;
550
check_param.keys_in_use= (uint64_t) strtoll(argument, NULL, 10);
553
if (argument == disabled_my_option)
554
check_param.testflag&= ~T_MEDIUM;
556
check_param.testflag|= T_MEDIUM; /* Medium check */
558
case 'r': /* Repair table */
559
check_param.testflag&= ~T_REP_ANY;
560
if (argument != disabled_my_option)
561
check_param.testflag|= T_REP_BY_SORT;
564
check_param.testflag&= ~T_REP_ANY;
565
if (argument != disabled_my_option)
566
check_param.testflag|= T_REP_PARALLEL;
569
check_param.testflag&= ~T_REP_ANY;
570
check_param.force_sort= 0;
571
if (argument != disabled_my_option)
573
check_param.testflag|= T_REP;
574
my_disable_async_io= 1; /* More safety */
578
check_param.testflag&= ~T_REP_ANY;
579
if (argument == disabled_my_option)
580
check_param.force_sort= 0;
583
check_param.testflag|= T_REP_BY_SORT;
584
check_param.force_sort= 1;
588
if (argument == disabled_my_option)
589
check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
591
check_param.testflag|=
592
(check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
595
if (argument == disabled_my_option)
596
check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
598
check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
600
case 'v': /* Verbose */
601
if (argument == disabled_my_option)
603
check_param.testflag&= ~T_VERBOSE;
604
check_param.verbose=0;
608
check_param.testflag|= T_VERBOSE;
609
check_param.verbose++;
612
case 'R': /* Sort records */
613
if (argument == disabled_my_option)
614
check_param.testflag&= ~T_SORT_RECORDS;
617
check_param.testflag|= T_SORT_RECORDS;
618
check_param.opt_sort_key= (uint) atoi(argument) - 1;
619
if (check_param.opt_sort_key >= MI_MAX_KEY)
622
"The value of the sort key is bigger than max key: %d.\n",
628
case 'S': /* Sort index */
629
if (argument == disabled_my_option)
630
check_param.testflag&= ~T_SORT_INDEX;
632
check_param.testflag|= T_SORT_INDEX;
635
if (argument == disabled_my_option)
636
check_param.testflag&= ~T_READONLY;
638
check_param.testflag|= T_READONLY;
641
if (argument == disabled_my_option)
642
check_param.testflag&= ~T_UPDATE_STATE;
644
check_param.testflag|= T_UPDATE_STATE;
649
case OPT_CORRECT_CHECKSUM:
650
if (argument == disabled_my_option)
651
check_param.testflag&= ~T_CALC_CHECKSUM;
653
check_param.testflag|= T_CALC_CHECKSUM;
655
case OPT_STATS_METHOD:
658
enum_mi_stats_method method_conv;
659
myisam_stats_method_str= argument;
660
if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
662
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
667
method_conv= MI_STATS_METHOD_NULLS_EQUAL;
670
method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
673
method_conv= MI_STATS_METHOD_IGNORE_NULLS;
675
default: assert(0); /* Impossible */
676
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
679
check_param.stats_method= method_conv;
682
#ifdef DEBUG /* Only useful if debugging */
683
case OPT_START_CHECK_POS:
684
check_param.start_check_pos= strtoull(argument, NULL, 0);
688
my_print_help(my_long_options);
698
static void get_options(register int *argc,register char ***argv)
702
load_defaults("drizzle", load_default_groups, argc, argv);
704
if (isatty(fileno(stdout)))
705
check_param.testflag|=T_WRITE_LOOP;
707
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
710
/* If using repair, then update checksum if one uses --update-state */
711
if ((check_param.testflag & T_UPDATE_STATE) &&
712
(check_param.testflag & T_REP_ANY))
713
check_param.testflag|= T_CALC_CHECKSUM;
721
if ((check_param.testflag & T_UNPACK) &&
722
(check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
725
"%s: --unpack can't be used with --quick or --sort-records\n",
729
if ((check_param.testflag & T_READONLY) &&
730
(check_param.testflag &
731
(T_REP_ANY | T_STATISTICS | T_AUTO_INC |
732
T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
735
"%s: Can't use --readonly when repairing or sorting\n",
740
if (init_tmpdir(&myisamchk_tmpdir, opt_tmpdir))
743
check_param.tmpdir=&myisamchk_tmpdir;
744
check_param.key_cache_block_size= opt_key_cache_block_size;
746
if (set_collation_name)
747
if (!(set_collation= get_charset_by_name(set_collation_name,
751
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
758
static int myisamchk(MI_CHECK *param, char * filename)
760
int error,lock_type,recreate;
761
int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
762
uint32_t raid_chunks;
765
char llbuff[22],llbuff2[22];
766
bool state_updated=0;
769
param->out_flag=error=param->warning_printed=param->error_printed=
772
param->isam_file_name=filename; /* For error messages */
773
if (!(info=mi_open(filename,
774
(param->testflag & (T_DESCRIPT | T_READONLY)) ?
777
((param->testflag & T_WAIT_FOREVER) ?
778
HA_OPEN_WAIT_IF_LOCKED :
779
(param->testflag & T_DESCRIPT) ?
780
HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
782
/* Avoid twice printing of isam file name */
783
param->error_printed=1;
786
mi_check_print_error(param,"'%s' doesn't have a correct index definition. You need to recreate it before you can do a repair",filename);
788
case HA_ERR_NOT_A_TABLE:
789
mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
791
case HA_ERR_CRASHED_ON_USAGE:
792
mi_check_print_error(param,"'%s' is marked as crashed",filename);
794
case HA_ERR_CRASHED_ON_REPAIR:
795
mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
797
case HA_ERR_OLD_FILE:
798
mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
800
case HA_ERR_END_OF_FILE:
801
mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
804
mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
807
mi_check_print_error(param,"File '%s' doesn't exist",filename);
810
mi_check_print_error(param,"You don't have permission to use '%s'",filename);
813
mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
820
share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
821
share->tot_locks-= share->r_locks;
823
raid_chunks=share->base.raid_chunks;
826
Skip the checking of the file if:
827
We are using --fast and the table is closed properly
828
We are using --check-only-changed-tables and the table hasn't changed
830
if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
832
bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
834
if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
835
((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
836
STATE_CRASHED_ON_REPAIR) ||
837
!(param->testflag & T_CHECK_ONLY_CHANGED))))
840
if (info->s->base.keys && info->state->records)
842
if ((param->testflag & T_STATISTICS) &&
843
(share->state.changed & STATE_NOT_ANALYZED))
845
if ((param->testflag & T_SORT_INDEX) &&
846
(share->state.changed & STATE_NOT_SORTED_PAGES))
848
if ((param->testflag & T_REP_BY_SORT) &&
849
(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
852
if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
853
(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
854
STATE_CRASHED_ON_REPAIR)))
858
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
859
printf("MyISAM file: %s is already checked\n",filename);
862
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
869
if ((param->testflag & (T_REP_ANY | T_STATISTICS |
870
T_SORT_RECORDS | T_SORT_INDEX)) &&
871
(((param->testflag & T_UNPACK) &&
872
share->data_file_type == COMPRESSED_RECORD) ||
873
mi_uint2korr(share->state.header.state_info_length) !=
874
MI_STATE_INFO_SIZE ||
875
mi_uint2korr(share->state.header.base_info_length) !=
877
mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
878
~share->state.key_map) ||
879
test_if_almost_full(info) ||
880
info->s->state.header.file_version[3] != myisam_file_magic[3] ||
882
set_collation->number != share->state.header.language) ||
883
myisam_block_size != MI_KEY_BLOCK_LENGTH))
886
param->language= set_collation->number;
887
if (recreate_table(param, &info,filename))
890
"MyISAM-table '%s' is not fixed because of errors\n",
895
if (!(param->testflag & T_REP_ANY))
897
param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
898
if (!(param->testflag & T_SILENT))
899
printf("- '%s' has old table-format. Recreating index\n",filename);
903
share->tot_locks-= share->r_locks;
907
if (param->testflag & T_DESCRIPT)
909
param->total_files++;
910
param->total_records+=info->state->records;
911
param->total_deleted+=info->state->del;
912
descript(param, info, filename);
917
if (!(param->testflag & T_READONLY))
918
lock_type = F_WRLCK; /* table is changed */
921
if (info->lock_type == F_RDLCK)
922
info->lock_type=F_UNLCK; /* Read only table */
923
if (_mi_readinfo(info,lock_type,0))
925
mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
927
param->error_printed=0;
931
_mi_readinfo() has locked the table.
932
We mark the table as locked (without doing file locks) to be able to
933
use functions that only works on locked tables (like row caching).
935
mi_lock_database(info, F_EXTRA_LCK);
936
datafile=info->dfile;
938
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
940
if (param->testflag & T_REP_ANY)
942
uint64_t tmp=share->state.key_map;
943
mi_copy_keys_active(share->state.key_map, share->base.keys,
945
if (tmp != share->state.key_map)
946
info->update|=HA_STATE_CHANGED;
948
if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
950
if (param->testflag & T_FORCE_CREATE)
953
mi_check_print_info(param,"Creating new data file\n");
958
mi_check_print_error(param,
959
"Quick-recover aborted; Run recovery without switch 'q'");
964
if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
965
(mi_is_any_key_active(share->state.key_map) ||
966
(rep_quick && !param->keys_in_use && !recreate)) &&
967
mi_test_if_sort_rep(info, info->state->records,
968
info->s->state.key_map,
971
if (param->testflag & T_REP_BY_SORT)
972
error=mi_repair_by_sort(param,info,filename,rep_quick);
974
error=mi_repair_parallel(param,info,filename,rep_quick);
977
else if (param->testflag & T_REP_ANY)
978
error=mi_repair(param, info,filename,rep_quick);
980
if (!error && param->testflag & T_SORT_RECORDS)
984
We can't update the index in mi_sort_records if we have a
985
prefix compressed or fulltext index
988
for (key=0 ; key < share->base.keys; key++)
989
if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY))
992
error=mi_sort_records(param,info,filename,param->opt_sort_key,
993
/* what is the following parameter for ? */
994
(bool) !(param->testflag & T_REP),
996
datafile=info->dfile; /* This is now locked */
997
if (!error && !update_index)
1000
puts("Table had a compressed index; We must now recreate the index");
1001
error=mi_repair_by_sort(param,info,filename,1);
1004
if (!error && param->testflag & T_SORT_INDEX)
1005
error=mi_sort_index(param,info,filename);
1007
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1008
STATE_CRASHED_ON_REPAIR);
1010
mi_mark_crashed(info);
1012
else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
1014
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1015
printf("Checking MyISAM file: %s\n",filename);
1016
if (!(param->testflag & T_SILENT))
1017
printf("Data records: %7s Deleted blocks: %7s\n",
1018
llstr(info->state->records,llbuff),
1019
llstr(info->state->del,llbuff2));
1020
error =chk_status(param,info);
1021
mi_intersect_keys_active(share->state.key_map, param->keys_in_use);
1022
error =chk_size(param,info);
1023
if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1024
error|=chk_del(param, info,param->testflag);
1025
if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1026
!param->start_check_pos)))
1028
error|=chk_key(param, info);
1029
if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1030
error=update_state_info(param, info,
1031
((param->testflag & T_STATISTICS) ?
1033
((param->testflag & T_AUTO_INC) ?
1034
UPDATE_AUTO_INC : 0));
1036
if ((!rep_quick && !error) ||
1037
!(param->testflag & (T_FAST | T_FORCE_CREATE)))
1039
if (param->testflag & (T_EXTEND | T_MEDIUM))
1040
init_key_cache(dflt_key_cache,opt_key_cache_block_size,
1041
param->use_buffers, 0, 0);
1042
init_io_cache(¶m->read_cache,datafile,
1043
(uint) param->read_buffer_length,
1045
(param->start_check_pos ?
1046
param->start_check_pos :
1047
share->pack.header_length),
1051
if ((info->s->options & (HA_OPTION_PACK_RECORD |
1052
HA_OPTION_COMPRESS_RECORD)) ||
1053
(param->testflag & (T_EXTEND | T_MEDIUM)))
1054
error|=chk_data_link(param, info, param->testflag & T_EXTEND);
1055
error|=flush_blocks(param, share->key_cache, share->kfile);
1056
end_io_cache(¶m->read_cache);
1060
if ((share->state.changed & STATE_CHANGED) &&
1061
(param->testflag & T_UPDATE_STATE))
1062
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1063
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1064
STATE_CRASHED_ON_REPAIR);
1066
else if (!mi_is_crashed(info) &&
1067
(param->testflag & T_UPDATE_STATE))
1068
{ /* Mark crashed */
1069
mi_mark_crashed(info);
1070
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1074
if ((param->testflag & T_AUTO_INC) ||
1075
((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1076
update_auto_increment_key(param, info,
1077
(bool) !test(param->testflag & T_AUTO_INC));
1079
if (!(param->testflag & T_DESCRIPT))
1081
if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1082
error|=update_state_info(param, info,
1084
(((param->testflag & T_REP_ANY) ?
1086
(state_updated ? UPDATE_STAT : 0) |
1087
((param->testflag & T_SORT_RECORDS) ?
1089
info->update&= ~HA_STATE_CHANGED;
1091
mi_lock_database(info, F_UNLCK);
1095
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
1100
if (param->out_flag & O_NEW_DATA)
1101
error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1103
((param->testflag & T_BACKUP_DATA) ?
1104
MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1105
if (param->out_flag & O_NEW_INDEX)
1106
error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1109
fflush(stdout); fflush(stderr);
1110
if (param->error_printed)
1112
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1115
"MyISAM-table '%s' is not fixed because of errors\n",
1117
if (param->testflag & T_REP_ANY)
1119
"Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n");
1121
else if (!(param->error_printed & 2) &&
1122
!(param->testflag & T_FORCE_CREATE))
1124
"MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
1127
else if (param->warning_printed &&
1128
! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1130
fprintf(stderr, "MyISAM-table '%s' is usable but should be fixed\n",
1137
/* Write info about table */
1139
static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
1141
uint32_t key,keyseg_nr,field,start;
1142
register MI_KEYDEF *keyinfo;
1143
register HA_KEYSEG *keyseg;
1144
register const char *text;
1145
char buff[160],length[10],*pos,*end;
1146
enum en_fieldtype type;
1147
MYISAM_SHARE *share=info->s;
1148
char llbuff[22],llbuff2[22];
1150
printf("\nMyISAM file: %s\n",name);
1151
fputs("Record format: ",stdout);
1152
if (share->options & HA_OPTION_COMPRESS_RECORD)
1154
else if (share->options & HA_OPTION_PACK_RECORD)
1157
puts("Fixed length");
1158
printf("Character set: %s (%d)\n",
1159
get_charset_name(share->state.header.language),
1160
share->state.header.language);
1162
if (param->testflag & T_VERBOSE)
1164
printf("File-version: %d\n",
1165
(int) share->state.header.file_version[3]);
1166
if (share->state.create_time)
1168
get_date(buff,1,share->state.create_time);
1169
printf("Creation time: %s\n",buff);
1171
if (share->state.check_time)
1173
get_date(buff,1,share->state.check_time);
1174
printf("Recover time: %s\n",buff);
1177
if (share->state.changed & STATE_CRASHED)
1178
strcpy(buff,"crashed");
1181
if (share->state.open_count)
1182
pos= strcpy(pos,"open,")+5;
1183
if (share->state.changed & STATE_CHANGED)
1184
pos= strcpy(pos,"changed,")+8;
1186
pos= strcpy(pos,"checked,")+8;
1187
if (!(share->state.changed & STATE_NOT_ANALYZED))
1188
pos= strcpy(pos,"analyzed,")+9;
1189
if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1190
pos= strcpy(pos,"optimized keys,")+15;
1191
if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1192
pos= strcpy(pos,"sorted index pages,")+19;
1193
pos[-1]=0; /* Remove extra ',' */
1195
printf("Status: %s\n",buff);
1196
if (share->base.auto_key)
1198
printf("Auto increment key: %13d Last value: %13s\n",
1199
share->base.auto_key,
1200
llstr(share->state.auto_increment,llbuff));
1202
if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1203
printf("Checksum: %23s\n",llstr(info->state->checksum,llbuff));
1205
if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1206
printf("Keys are only flushed at close\n");
1209
printf("Data records: %13s Deleted blocks: %13s\n",
1210
llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1211
if (param->testflag & T_SILENT)
1212
return; /* This is enough */
1214
if (param->testflag & T_VERBOSE)
1217
printf("Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
1219
printf("Datafile parts: %13s Deleted data: %13s\n",
1220
llstr(share->state.split,llbuff),
1221
llstr(info->state->empty,llbuff2));
1222
printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
1223
share->rec_reflength,share->base.key_reflength);
1224
printf("Datafile length: %13s Keyfile length: %13s\n",
1225
llstr(info->state->data_file_length,llbuff),
1226
llstr(info->state->key_file_length,llbuff2));
1228
if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1229
puts("This is a one-record table");
1232
if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1233
share->base.max_key_file_length != HA_OFFSET_ERROR)
1234
printf("Max datafile length: %13s Max keyfile length: %13s\n",
1235
llstr(share->base.max_data_file_length-1,llbuff),
1236
llstr(share->base.max_key_file_length-1,llbuff2));
1240
printf("Recordlength: %13d\n",(int) share->base.pack_reclength);
1241
if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1243
int64_t2str(share->state.key_map,buff,2);
1244
printf("Using only keys '%s' of %d possibly keys\n",
1245
buff, share->base.keys);
1247
puts("\ntable description:");
1248
printf("Key Start Len Index Type");
1249
if (param->testflag & T_VERBOSE)
1250
printf(" Rec/key Root Blocksize");
1253
for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1254
key < share->base.keys;
1257
keyseg=keyinfo->seg;
1258
if (keyinfo->flag & HA_NOSAME) text="unique ";
1259
else text="multip.";
1262
if (keyseg->flag & HA_REVERSE_SORT)
1264
pos= strcpy(pos,type_names[keyseg->type]);
1265
pos+= strlen(type_names[keyseg->type]);
1268
if (keyinfo->flag & HA_PACK_KEY)
1269
pos= strcpy(pos,prefix_packed_txt) + strlen(prefix_packed_txt);
1270
if (keyinfo->flag & HA_BINARY_PACK_KEY)
1271
pos= strcpy(pos,bin_packed_txt) + strlen(bin_packed_txt);
1272
if (keyseg->flag & HA_SPACE_PACK)
1273
pos= strcpy(pos,diff_txt) + strlen(diff_txt);
1274
if (keyseg->flag & HA_BLOB_PART)
1275
pos= strcpy(pos,blob_txt) + strlen(blob_txt);
1276
if (keyseg->flag & HA_NULL_PART)
1277
pos= strcpy(pos,null_txt) + strlen(null_txt);
1280
printf("%-4d%-6ld%-3d %-8s%-21s",
1281
key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1282
if (share->state.key_root[key] != HA_OFFSET_ERROR)
1283
llstr(share->state.key_root[key],buff);
1286
if (param->testflag & T_VERBOSE)
1287
printf("%11lu %12s %10d",
1288
share->state.rec_per_key_part[keyseg_nr++],
1289
buff,keyinfo->block_length);
1291
while ((++keyseg)->type != HA_KEYTYPE_END)
1294
if (keyseg->flag & HA_REVERSE_SORT)
1296
pos= strcpy(pos,type_names[keyseg->type]);
1297
pos+= strlen(type_names[keyseg->type]);
1299
if (keyseg->flag & HA_SPACE_PACK)
1300
pos= strcpy(pos,diff_txt) + strlen(diff_txt);
1301
if (keyseg->flag & HA_BLOB_PART)
1302
pos= strcpy(pos,blob_txt) + strlen(blob_txt);
1303
if (keyseg->flag & HA_NULL_PART)
1304
pos= strcpy(pos,null_txt) + strlen(null_txt);
1306
printf(" %-6ld%-3d %-21s",
1307
(long) keyseg->start+1,keyseg->length,buff);
1308
if (param->testflag & T_VERBOSE)
1309
printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1314
if (share->state.header.uniques)
1316
MI_UNIQUEDEF *uniqueinfo;
1317
puts("\nUnique Key Start Len Nullpos Nullbit Type");
1318
for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1319
key < share->state.header.uniques; key++, uniqueinfo++)
1322
char null_bit[8],null_pos[8];
1323
printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1324
for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1328
null_bit[0]=null_pos[0]=0;
1329
if (keyseg->null_bit)
1331
sprintf(null_bit,"%d",keyseg->null_bit);
1332
sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1334
printf("%-7ld%-5d%-9s%-10s%-30s\n",
1335
(long) keyseg->start+1,keyseg->length,
1337
type_names[keyseg->type]);
1342
if (param->verbose > 1)
1344
char null_bit[8],null_pos[8];
1345
printf("\nField Start Length Nullpos Nullbit Type");
1346
if (share->options & HA_OPTION_COMPRESS_RECORD)
1347
printf(" Huff tree Bits");
1350
for (field=0 ; field < share->base.fields ; field++)
1352
if (share->options & HA_OPTION_COMPRESS_RECORD)
1353
type=share->rec[field].base_type;
1355
type=(enum en_fieldtype) share->rec[field].type;
1356
end= strcpy(buff, field_pack[type]);
1357
end+= strlen(field_pack[type]);
1358
if (share->options & HA_OPTION_COMPRESS_RECORD)
1360
if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1361
end= strcpy(end,", not_always")+12;
1362
if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1363
end= strcpy(end,", no empty")+10;
1364
if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1366
sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
1367
end= strchr(end, '\0');
1371
strcpy(buff,buff+2);
1372
int10_to_str((long) share->rec[field].length,length,10);
1373
null_bit[0]=null_pos[0]=0;
1374
if (share->rec[field].null_bit)
1376
sprintf(null_bit,"%d",share->rec[field].null_bit);
1377
sprintf(null_pos,"%d",share->rec[field].null_pos+1);
1379
printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1380
null_pos, null_bit, buff);
1381
if (share->options & HA_OPTION_COMPRESS_RECORD)
1383
if (share->rec[field].huff_tree)
1385
(uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1386
share->rec[field].huff_tree->quick_table_bits);
1389
start+=share->rec[field].length;
1396
/* Sort records according to one key */
1398
static int mi_sort_records(MI_CHECK *param,
1399
register MI_INFO *info, char * name,
1408
unsigned char *temp_buff;
1409
ha_rows old_record_count;
1410
MYISAM_SHARE *share=info->s;
1411
char llbuff[22],llbuff2[22];
1412
SORT_INFO sort_info;
1413
MI_SORT_PARAM sort_param;
1415
memset(&sort_info, 0, sizeof(sort_info));
1416
memset(&sort_param, 0, sizeof(sort_param));
1417
sort_param.sort_info=&sort_info;
1418
sort_info.param=param;
1419
keyinfo= &share->keyinfo[sort_key];
1424
if (! mi_is_key_active(share->state.key_map, sort_key))
1426
mi_check_print_warning(param,
1427
"Can't sort table '%s' on key %d; No such key",
1429
param->error_printed=0;
1430
return(0); /* Nothing to do */
1432
if (share->data_file_type == COMPRESSED_RECORD)
1434
mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
1435
param->error_printed=0;
1436
return(0); /* Nothing to do */
1438
if (!(param->testflag & T_SILENT))
1440
printf("- Sorting records for MyISAM-table '%s'\n",name);
1442
printf("Data records: %9s Deleted: %9s\n",
1443
llstr(info->state->records,llbuff),
1444
llstr(info->state->del,llbuff2));
1446
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1447
return(0); /* Nothing to do */
1449
init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers,
1451
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1452
WRITE_CACHE,share->pack.header_length,1,
1453
MYF(MY_WME | MY_WAIT_IF_FULL)))
1455
info->opt_flag|=WRITE_CACHE_USED;
1457
if (!(temp_buff=(unsigned char*) malloc(keyinfo->block_length)))
1459
mi_check_print_error(param,"Not enough memory for key block");
1463
if (!mi_alloc_rec_buff(info, (ulong)-1, &sort_param.record))
1465
mi_check_print_error(param,"Not enough memory for record");
1468
fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
1469
new_file=my_create(fn_format(param->temp_filename,
1470
param->temp_filename,"",
1472
0,param->tmpfile_createflag,
1476
mi_check_print_error(param,"Can't create new tempfile: '%s'",
1477
param->temp_filename);
1480
if (share->pack.header_length)
1481
if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1484
info->rec_cache.file=new_file; /* Use this file for cacheing*/
1487
for (key=0 ; key < share->base.keys ; key++)
1488
share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1490
if (my_pread(share->kfile,(unsigned char*) temp_buff,
1491
(uint) keyinfo->block_length,
1492
share->state.key_root[sort_key],
1493
MYF(MY_NABP+MY_WME)))
1495
mi_check_print_error(param,"Can't read indexpage from filepos: %s",
1496
(ulong) share->state.key_root[sort_key]);
1500
/* Setup param for sort_write_record */
1501
sort_info.info=info;
1502
sort_info.new_data_file_type=share->data_file_type;
1503
sort_param.fix_datafile=1;
1504
sort_param.master=1;
1505
sort_param.filepos=share->pack.header_length;
1506
old_record_count=info->state->records;
1507
info->state->records=0;
1508
if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1509
info->state->checksum=0;
1511
if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1512
temp_buff, sort_key,new_file,update_index) ||
1513
write_data_suffix(&sort_info,1) ||
1514
flush_io_cache(&info->rec_cache))
1517
if (info->state->records != old_record_count)
1519
mi_check_print_error(param,"found %s of %s records",
1520
llstr(info->state->records,llbuff),
1521
llstr(old_record_count,llbuff2));
1525
my_close(info->dfile,MYF(MY_WME));
1526
param->out_flag|=O_NEW_DATA; /* Data in new file */
1527
info->dfile=new_file; /* Use new datafile */
1529
info->state->empty=0;
1530
share->state.dellink= HA_OFFSET_ERROR;
1531
info->state->data_file_length=sort_param.filepos;
1532
share->state.split=info->state->records; /* Only hole records */
1533
share->state.version=(ulong) time((time_t*) 0);
1535
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1537
if (param->testflag & T_WRITE_LOOP)
1539
fputs(" \r",stdout); fflush(stdout);
1544
if (got_error && new_file >= 0)
1546
end_io_cache(&info->rec_cache);
1547
(void) my_close(new_file,MYF(MY_WME));
1548
(void) my_delete(param->temp_filename, MYF(MY_WME));
1552
free((unsigned char*) temp_buff);
1554
void * rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
1555
if (rec_buff_ptr != NULL)
1558
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1559
end_io_cache(&info->rec_cache);
1560
free(sort_info.buff);
1562
share->state.sortkey=sort_key;
1563
return(flush_blocks(param, share->key_cache, share->kfile) |
1565
} /* sort_records */
1568
/* Sort records recursive using one index */
1570
static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
1572
my_off_t page, unsigned char *buff, uint32_t sort_key,
1573
File new_file,bool update_index)
1575
uint nod_flag,used_length,key_length;
1576
unsigned char *temp_buff,*keypos,*endpos;
1577
my_off_t next_page,rec_pos;
1578
unsigned char lastkey[MI_MAX_KEY_BUFF];
1580
SORT_INFO *sort_info= sort_param->sort_info;
1581
MI_CHECK *param=sort_info->param;
1583
nod_flag=mi_test_if_nod(buff);
1588
if (!(temp_buff=(unsigned char*) malloc(keyinfo->block_length)))
1590
mi_check_print_error(param,"Not Enough memory");
1594
used_length=mi_getint(buff);
1595
keypos=buff+2+nod_flag;
1596
endpos=buff+used_length;
1601
next_page=_mi_kpos(nod_flag,keypos);
1602
if (my_pread(info->s->kfile,(unsigned char*) temp_buff,
1603
(uint) keyinfo->block_length, next_page,
1604
MYF(MY_NABP+MY_WME)))
1606
mi_check_print_error(param,"Can't read keys from filepos: %s",
1607
llstr(next_page,llbuff));
1610
if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1611
new_file, update_index))
1614
if (keypos >= endpos ||
1615
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1618
rec_pos= _mi_dpos(info,0,lastkey+key_length);
1620
if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1622
mi_check_print_error(param,"%d when reading datafile",my_errno);
1625
if (rec_pos != sort_param->filepos && update_index)
1627
_mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1628
sort_param->filepos);
1629
if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1632
mi_check_print_error(param,"%d when updating key-pointers",my_errno);
1636
if (sort_write_record(sort_param))
1639
/* Clear end of block to get better compression if the table is backuped */
1640
memset(buff+used_length, 0, keyinfo->block_length-used_length);
1641
if (my_pwrite(info->s->kfile,(unsigned char*) buff,(uint) keyinfo->block_length,
1642
page,param->myf_rw))
1644
mi_check_print_error(param,"%d when updating keyblock",my_errno);
1648
free((unsigned char*) temp_buff);
1652
free((unsigned char*) temp_buff);
1654
} /* sort_record_index */
1659
Check if myisamchk was killed by a signal
1660
This is overloaded by other programs that want to be able to abort
1664
static int not_killed= 0;
1666
volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
1668
return ¬_killed; /* always NULL */
1671
/* print warnings and errors */
1674
void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
1675
const char *fmt,...)
1680
vfprintf(stdout, fmt, args);
1687
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
1692
if (!param->warning_printed && !param->error_printed)
1694
if (param->testflag & T_SILENT)
1695
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,
1696
param->isam_file_name);
1697
param->out_flag|= O_DATA_LOST;
1699
param->warning_printed=1;
1701
fprintf(stderr,"%s: warning: ",my_progname_short);
1702
vfprintf(stderr, fmt, args);
1711
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
1716
if (!param->warning_printed && !param->error_printed)
1718
if (param->testflag & T_SILENT)
1719
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1720
param->out_flag|= O_DATA_LOST;
1722
param->error_printed|=1;
1724
fprintf(stderr,"%s: error: ",my_progname_short);
1725
vfprintf(stderr, fmt, args);