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 */
22
#include <my_getopt.h>
24
#ifdef HAVE_SYS_VADVICE_H
25
#include <sys/vadvise.h>
27
#ifdef HAVE_SYS_MMAN_H
30
SET_STACK_SIZE(9000) /* Minimum stack size for program */
33
#define my_raid_create(A,B,C,D,E,F,G) my_create(A,B,C,G)
34
#define my_raid_delete(A,B,C) my_delete(A,B)
37
static uint decode_bits;
38
static char **default_argv;
39
static const char *load_default_groups[]= { "myisamchk", 0 };
40
static const char *set_collation_name, *opt_tmpdir;
41
static CHARSET_INFO *set_collation;
42
static long opt_myisam_block_size;
43
static long opt_key_cache_block_size;
44
static const char *my_progname_short;
45
static int stopwords_inited= 0;
46
static MY_TMPDIR myisamchk_tmpdir;
48
static const char *type_names[]=
49
{ "impossible","char","binary", "short", "long", "float",
50
"double","number","unsigned short",
51
"unsigned long","longlong","ulonglong","int24",
52
"uint24","int8","varchar", "varbin","?",
55
static const char *prefix_packed_txt="packed ",
56
*bin_packed_txt="prefix ",
57
*diff_txt="stripped ",
61
static const char *field_pack[]=
62
{"","no endspace", "no prespace",
63
"no zeros", "blob", "constant", "table-lockup",
64
"always zero","varchar","unique-hash","?","?"};
66
static const char *myisam_stats_method_str="nulls_unequal";
68
static void get_options(int *argc,char * * *argv);
69
static void print_version(void);
70
static void usage(void);
71
static int myisamchk(MI_CHECK *param, char *filename);
72
static void descript(MI_CHECK *param, register MI_INFO *info, char * name);
73
static int mi_sort_records(MI_CHECK *param, register MI_INFO *info,
74
char * name, uint sort_key,
75
my_bool write_info, my_bool update_index);
76
static int sort_record_index(MI_SORT_PARAM *sort_param, MI_INFO *info,
78
my_off_t page,uchar *buff,uint sortkey,
79
File new_file, my_bool update_index);
85
int main(int argc, char **argv)
89
my_progname_short= my_progname+dirname_length(my_progname);
91
myisamchk_init(&check_param);
92
check_param.opt_lock_memory=1; /* Lock memory if possible */
93
check_param.using_global_keycache = 0;
94
get_options(&argc,(char***) &argv);
95
myisam_quick_table_bits=decode_bits;
99
int new_error=myisamchk(&check_param, *(argv++));
100
if ((check_param.testflag & T_REP_ANY) != T_REP)
101
check_param.testflag&= ~T_REP;
102
VOID(fflush(stdout));
103
VOID(fflush(stderr));
104
if ((check_param.error_printed | check_param.warning_printed) &&
105
(check_param.testflag & T_FORCE_CREATE) &&
106
(!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
109
uint old_testflag=check_param.testflag;
110
if (!(check_param.testflag & T_REP))
111
check_param.testflag|= T_REP_BY_SORT;
112
check_param.testflag&= ~T_EXTEND; /* Don't needed */
113
error|=myisamchk(&check_param, argv[-1]);
114
check_param.testflag= old_testflag;
115
VOID(fflush(stdout));
116
VOID(fflush(stderr));
120
if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
122
puts("\n---------\n");
123
VOID(fflush(stdout));
126
if (check_param.total_files > 1)
127
{ /* Only if descript */
128
char buff[22],buff2[22];
129
if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
130
puts("\n---------\n");
131
printf("\nTotal of all %d MyISAM-files:\nData records: %9s Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
132
llstr(check_param.total_deleted,buff2));
134
free_defaults(default_argv);
135
free_tmpdir(&myisamchk_tmpdir);
137
my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
140
return 0; /* No compiler warning */
145
OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
146
OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE,
147
OPT_KEY_CACHE_BLOCK_SIZE, OPT_MYISAM_BLOCK_SIZE,
148
OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
149
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN,
150
OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE,
151
OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD
154
static struct my_option my_long_options[] =
157
"Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
158
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
160
{"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
161
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
163
{"block-search", 'b',
164
"No help available.",
165
0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
167
"Make a backup of the .MYD file as 'filename-time.BAK'.",
168
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
169
{"character-sets-dir", OPT_CHARSETS_DIR,
170
"Directory where character sets are.",
171
(uchar**) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
173
"Check table for errors.",
174
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
175
{"check-only-changed", 'C',
176
"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).",
177
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
178
{"correct-checksum", OPT_CORRECT_CHECKSUM,
179
"Correct checksum information for table.",
180
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
183
"Output debug log. Often this is 'd:t:o,filename'.",
184
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
187
"Prints some information about table.",
188
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
189
{"data-file-length", 'D',
190
"Max length of data file (when recreating data-file when it's full).",
191
(uchar**) &check_param.max_data_file_length,
192
(uchar**) &check_param.max_data_file_length,
193
0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
194
{"extend-check", 'e',
195
"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.",
196
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
198
"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).",
199
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
201
"Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
202
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
204
"Display this help and exit.",
205
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
207
"Display this help and exit.",
208
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
210
"Print statistics information about table that is checked.",
211
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
213
"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.",
214
(uchar**) &check_param.keys_in_use,
215
(uchar**) &check_param.keys_in_use,
216
0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
217
{"max-record-length", OPT_MAX_RECORD_LENGTH,
218
"Skip rows bigger than this if myisamchk can't allocate memory to hold it",
219
(uchar**) &check_param.max_record_length,
220
(uchar**) &check_param.max_record_length,
221
0, GET_ULL, REQUIRED_ARG, LONGLONG_MAX, 0, LONGLONG_MAX, 0, 0, 0},
222
{"medium-check", 'm',
223
"Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
224
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
225
{"quick", 'q', "Faster repair by not modifying the data file.",
226
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
228
"Don't mark table as checked.",
229
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
231
"Can fix almost anything except unique keys that aren't unique.",
232
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
233
{"parallel-recover", 'p',
234
"Same as '-r' but creates all the keys in parallel.",
235
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
236
{"safe-recover", 'o',
237
"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.",
238
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
239
{"sort-recover", 'n',
240
"Force recovering with sorting even if the temporary file was very big.",
241
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
243
{"start-check-pos", OPT_START_CHECK_POS,
244
"No help available.",
245
0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
247
{"set-auto-increment", 'A',
248
"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.",
249
(uchar**) &check_param.auto_increment_value,
250
(uchar**) &check_param.auto_increment_value,
251
0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
252
{"set-collation", OPT_SET_COLLATION,
253
"Change the collation used by the index",
254
(uchar**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
255
{"set-variable", 'O',
256
"Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
257
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
259
"Only print errors. One can use two -s to make myisamchk very silent.",
260
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
262
"Sort index blocks. This speeds up 'read-next' in applications.",
263
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
264
{"sort-records", 'R',
265
"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!)",
266
(uchar**) &check_param.opt_sort_key,
267
(uchar**) &check_param.opt_sort_key,
268
0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
270
"Path for temporary files.",
271
(uchar**) &opt_tmpdir,
272
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
273
{"update-state", 'U',
274
"Mark tables as crashed if any errors were found.",
275
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
277
"Unpack file packed with myisampack.",
278
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
280
"Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
281
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
283
"Print version and exit.",
284
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
286
"Wait if table is locked.",
287
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
288
{ "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
289
(uchar**) &check_param.use_buffers, (uchar**) &check_param.use_buffers, 0,
290
GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
291
(long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
292
{ "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "",
293
(uchar**) &opt_key_cache_block_size,
294
(uchar**) &opt_key_cache_block_size, 0,
295
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
296
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
297
{ "myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "",
298
(uchar**) &opt_myisam_block_size, (uchar**) &opt_myisam_block_size, 0,
299
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
300
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
301
{ "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
302
(uchar**) &check_param.read_buffer_length,
303
(uchar**) &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
304
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
305
(long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
306
{ "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
307
(uchar**) &check_param.write_buffer_length,
308
(uchar**) &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
309
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
310
(long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
311
{ "sort_buffer_size", OPT_SORT_BUFFER_SIZE, "",
312
(uchar**) &check_param.sort_buffer_length,
313
(uchar**) &check_param.sort_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
314
(long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
315
(long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
316
{ "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
317
(uchar**) &check_param.sort_key_blocks,
318
(uchar**) &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
319
BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
320
{ "decode_bits", OPT_DECODE_BITS, "", (uchar**) &decode_bits,
321
(uchar**) &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
322
{ "ft_min_word_len", OPT_FT_MIN_WORD_LEN, "", (uchar**) &ft_min_word_len,
323
(uchar**) &ft_min_word_len, 0, GET_ULONG, REQUIRED_ARG, 4, 1, HA_FT_MAXCHARLEN,
325
{ "ft_max_word_len", OPT_FT_MAX_WORD_LEN, "", (uchar**) &ft_max_word_len,
326
(uchar**) &ft_max_word_len, 0, GET_ULONG, REQUIRED_ARG, HA_FT_MAXCHARLEN, 10,
327
HA_FT_MAXCHARLEN, 0, 1, 0},
328
{ "ft_stopword_file", OPT_FT_STOPWORD_FILE,
329
"Use stopwords from this file instead of built-in list.",
330
(uchar**) &ft_stopword_file, (uchar**) &ft_stopword_file, 0, GET_STR,
331
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
332
{"stats_method", OPT_STATS_METHOD,
333
"Specifies how index statistics collection code should treat NULLs. "
334
"Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
335
"\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
336
(uchar**) &myisam_stats_method_str, (uchar**) &myisam_stats_method_str, 0,
337
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
338
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
342
#include <help_start.h>
344
static void print_version(void)
346
printf("%s Ver 2.7 for %s at %s\n", my_progname, SYSTEM_TYPE,
348
NETWARE_SET_SCREEN_MODE(1);
352
static void usage(void)
355
puts("By Monty, for your professional use");
356
puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
357
puts("Description, check and repair of MyISAM tables.");
358
puts("Used without options all tables on the command will be checked for errors");
359
printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname_short);
360
printf("\nGlobal options:\n");
363
-#, --debug=... Output debug log. Often this is 'd:t:o,filename'.\n");
366
-?, --help Display this help and exit.\n\
367
-O, --set-variable var=option.\n\
368
Change the value of a variable. Please note that\n\
369
this option is deprecated; you can set variables\n\
370
directly with '--variable-name=value'.\n\
371
-t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
372
specified, separated by ");
373
#if defined( __WIN__) || defined(__NETWARE__)
374
printf("semicolon (;)");
378
printf(", they will be used\n\
379
in a round-robin fashion.\n\
380
-s, --silent Only print errors. One can use two -s to make\n\
381
myisamchk very silent.\n\
382
-v, --verbose Print more information. This can be used with\n\
383
--description and --check. Use many -v for more verbosity.\n\
384
-V, --version Print version and exit.\n\
385
-w, --wait Wait if table is locked.\n\n");
387
puts(" --start-check-pos=# Start reading file at given offset.\n");
390
puts("Check options (check is the default action for myisamchk):\n\
391
-c, --check Check table for errors.\n\
392
-e, --extend-check Check the table VERY throughly. Only use this in\n\
393
extreme cases as myisamchk should normally be able to\n\
394
find out if the table is ok even without this switch.\n\
395
-F, --fast Check only tables that haven't been closed properly.\n\
396
-C, --check-only-changed\n\
397
Check only tables that have changed since last check.\n\
398
-f, --force Restart with '-r' if there are any errors in the table.\n\
399
States will be updated as with '--update-state'.\n\
400
-i, --information Print statistics information about table that is checked.\n\
401
-m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
402
all errors. Should be good enough for most cases.\n\
403
-U --update-state Mark tables as crashed if you find any errors.\n\
404
-T, --read-only Don't mark table as checked.\n");
406
puts("Repair options (When using '-r' or '-o'):\n\
407
-B, --backup Make a backup of the .MYD file as 'filename-time.BAK'.\n\
408
--correct-checksum Correct checksum information for table.\n\
409
-D, --data-file-length=# Max length of data file (when recreating data\n\
410
file when it's full).\n\
411
-e, --extend-check Try to recover every possible row from the data file\n\
412
Normally this will also find a lot of garbage rows;\n\
413
Don't use this option if you are not totally desperate.\n\
414
-f, --force Overwrite old temporary files.\n\
415
-k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\
416
bit mask of which keys to use. This can be used to\n\
417
get faster inserts.\n\
418
--max-record-length=#\n\
419
Skip rows bigger than this if myisamchk can't allocate\n\
420
memory to hold it.\n\
421
-r, --recover Can fix almost anything except unique keys that aren't\n\
423
-n, --sort-recover Forces recovering with sorting even if the temporary\n\
424
file would be very big.\n\
425
-p, --parallel-recover\n\
426
Uses the same technique as '-r' and '-n', but creates\n\
427
all the keys in parallel, in different threads.\n\
428
-o, --safe-recover Uses old recovery method; Slower than '-r' but can\n\
429
handle a couple of cases where '-r' reports that it\n\
430
can't fix the data file.\n\
431
--character-sets-dir=...\n\
432
Directory where character sets are.\n\
433
--set-collation=name\n\
434
Change the collation used by the index.\n\
435
-q, --quick Faster repair by not modifying the data file.\n\
436
One can give a second '-q' to force myisamchk to\n\
437
modify the original datafile in case of duplicate keys.\n\
438
NOTE: Tables where the data file is currupted can't be\n\
439
fixed with this option.\n\
440
-u, --unpack Unpack file packed with myisampack.\n\
443
puts("Other actions:\n\
444
-a, --analyze Analyze distribution of keys. Will make some joins in\n\
445
MySQL faster. You can check the calculated distribution\n\
446
by using '--description --verbose table_name'.\n\
447
--stats_method=name Specifies how index statistics collection code should\n\
448
treat NULLs. Possible values of name are \"nulls_unequal\"\n\
449
(default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
450
\"nulls_ignored\".\n\
451
-d, --description Prints some information about table.\n\
452
-A, --set-auto-increment[=value]\n\
453
Force auto_increment to start at this or higher value\n\
454
If no value is given, then sets the next auto_increment\n\
455
value to the highest used value for the auto key + 1.\n\
456
-S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
458
-R, --sort-records=#\n\
459
Sort records according to an index. This makes your\n\
460
data much more localized and may speed up things\n\
461
(It may be VERY slow to do a sort the first time!).\n\
462
-b, --block-search=#\n\
463
Find a record, a block at given offset belongs to.");
465
print_defaults("my", load_default_groups);
466
my_print_variables(my_long_options);
469
#include <help_end.h>
471
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
472
"nulls_ignored", NullS};
473
TYPELIB myisam_stats_method_typelib= {
474
array_elements(myisam_stats_method_names) - 1, "",
475
myisam_stats_method_names, NULL};
480
get_one_option(int optid,
481
const struct my_option *opt __attribute__((unused)),
487
setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
491
if (argument == disabled_my_option)
492
check_param.testflag&= ~T_STATISTICS;
494
check_param.testflag|= T_STATISTICS;
498
check_param.auto_increment_value= strtoull(argument, NULL, 0);
500
check_param.auto_increment_value= 0; /* Set to max used value */
501
check_param.testflag|= T_AUTO_INC;
504
check_param.search_after_block= strtoul(argument, NULL, 10);
507
if (argument == disabled_my_option)
508
check_param.testflag&= ~T_BACKUP_DATA;
510
check_param.testflag|= T_BACKUP_DATA;
513
if (argument == disabled_my_option)
514
check_param.testflag&= ~T_CHECK;
516
check_param.testflag|= T_CHECK;
519
if (argument == disabled_my_option)
520
check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
522
check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
525
check_param.max_data_file_length=strtoll(argument, NULL, 10);
527
case 's': /* silent */
528
if (argument == disabled_my_option)
529
check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
532
if (check_param.testflag & T_SILENT)
533
check_param.testflag|= T_VERY_SILENT;
534
check_param.testflag|= T_SILENT;
535
check_param.testflag&= ~T_WRITE_LOOP;
539
if (argument == disabled_my_option)
540
check_param.testflag&= ~T_WAIT_FOREVER;
542
check_param.testflag|= T_WAIT_FOREVER;
544
case 'd': /* description if isam-file */
545
if (argument == disabled_my_option)
546
check_param.testflag&= ~T_DESCRIPT;
548
check_param.testflag|= T_DESCRIPT;
550
case 'e': /* extend check */
551
if (argument == disabled_my_option)
552
check_param.testflag&= ~T_EXTEND;
554
check_param.testflag|= T_EXTEND;
557
if (argument == disabled_my_option)
558
check_param.testflag&= ~T_INFO;
560
check_param.testflag|= T_INFO;
563
if (argument == disabled_my_option)
565
check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
566
check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
570
check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
571
check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
575
if (argument == disabled_my_option)
576
check_param.testflag&= ~T_FAST;
578
check_param.testflag|= T_FAST;
581
check_param.keys_in_use= (ulonglong) strtoll(argument, NULL, 10);
584
if (argument == disabled_my_option)
585
check_param.testflag&= ~T_MEDIUM;
587
check_param.testflag|= T_MEDIUM; /* Medium check */
589
case 'r': /* Repair table */
590
check_param.testflag&= ~T_REP_ANY;
591
if (argument != disabled_my_option)
592
check_param.testflag|= T_REP_BY_SORT;
595
check_param.testflag&= ~T_REP_ANY;
596
if (argument != disabled_my_option)
597
check_param.testflag|= T_REP_PARALLEL;
600
check_param.testflag&= ~T_REP_ANY;
601
check_param.force_sort= 0;
602
if (argument != disabled_my_option)
604
check_param.testflag|= T_REP;
605
my_disable_async_io= 1; /* More safety */
609
check_param.testflag&= ~T_REP_ANY;
610
if (argument == disabled_my_option)
611
check_param.force_sort= 0;
614
check_param.testflag|= T_REP_BY_SORT;
615
check_param.force_sort= 1;
619
if (argument == disabled_my_option)
620
check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
622
check_param.testflag|=
623
(check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
626
if (argument == disabled_my_option)
627
check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
629
check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
631
case 'v': /* Verbose */
632
if (argument == disabled_my_option)
634
check_param.testflag&= ~T_VERBOSE;
635
check_param.verbose=0;
639
check_param.testflag|= T_VERBOSE;
640
check_param.verbose++;
643
case 'R': /* Sort records */
644
if (argument == disabled_my_option)
645
check_param.testflag&= ~T_SORT_RECORDS;
648
check_param.testflag|= T_SORT_RECORDS;
649
check_param.opt_sort_key= (uint) atoi(argument) - 1;
650
if (check_param.opt_sort_key >= MI_MAX_KEY)
653
"The value of the sort key is bigger than max key: %d.\n",
659
case 'S': /* Sort index */
660
if (argument == disabled_my_option)
661
check_param.testflag&= ~T_SORT_INDEX;
663
check_param.testflag|= T_SORT_INDEX;
666
if (argument == disabled_my_option)
667
check_param.testflag&= ~T_READONLY;
669
check_param.testflag|= T_READONLY;
672
if (argument == disabled_my_option)
673
check_param.testflag&= ~T_UPDATE_STATE;
675
check_param.testflag|= T_UPDATE_STATE;
678
if (argument == disabled_my_option)
684
DBUG_PUSH(argument ? argument : "d:t:o,/tmp/myisamchk.trace");
690
case OPT_CORRECT_CHECKSUM:
691
if (argument == disabled_my_option)
692
check_param.testflag&= ~T_CALC_CHECKSUM;
694
check_param.testflag|= T_CALC_CHECKSUM;
696
case OPT_STATS_METHOD:
699
enum_mi_stats_method method_conv;
700
myisam_stats_method_str= argument;
701
if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
703
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
708
method_conv= MI_STATS_METHOD_NULLS_EQUAL;
711
method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
714
method_conv= MI_STATS_METHOD_IGNORE_NULLS;
716
default: assert(0); /* Impossible */
718
check_param.stats_method= method_conv;
721
#ifdef DEBUG /* Only useful if debugging */
722
case OPT_START_CHECK_POS:
723
check_param.start_check_pos= strtoull(argument, NULL, 0);
727
my_print_help(my_long_options);
737
static void get_options(register int *argc,register char ***argv)
741
load_defaults("my", load_default_groups, argc, argv);
743
if (isatty(fileno(stdout)))
744
check_param.testflag|=T_WRITE_LOOP;
746
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
749
/* If using repair, then update checksum if one uses --update-state */
750
if ((check_param.testflag & T_UPDATE_STATE) &&
751
(check_param.testflag & T_REP_ANY))
752
check_param.testflag|= T_CALC_CHECKSUM;
760
if ((check_param.testflag & T_UNPACK) &&
761
(check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
764
"%s: --unpack can't be used with --quick or --sort-records\n",
768
if ((check_param.testflag & T_READONLY) &&
769
(check_param.testflag &
770
(T_REP_ANY | T_STATISTICS | T_AUTO_INC |
771
T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
774
"%s: Can't use --readonly when repairing or sorting\n",
779
if (init_tmpdir(&myisamchk_tmpdir, opt_tmpdir))
782
check_param.tmpdir=&myisamchk_tmpdir;
783
check_param.key_cache_block_size= opt_key_cache_block_size;
785
if (set_collation_name)
786
if (!(set_collation= get_charset_by_name(set_collation_name,
790
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
797
static int myisamchk(MI_CHECK *param, char * filename)
799
int error,lock_type,recreate;
800
int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
804
char llbuff[22],llbuff2[22];
805
my_bool state_updated=0;
807
DBUG_ENTER("myisamchk");
809
param->out_flag=error=param->warning_printed=param->error_printed=
812
param->isam_file_name=filename; /* For error messages */
813
if (!(info=mi_open(filename,
814
(param->testflag & (T_DESCRIPT | T_READONLY)) ?
817
((param->testflag & T_WAIT_FOREVER) ?
818
HA_OPEN_WAIT_IF_LOCKED :
819
(param->testflag & T_DESCRIPT) ?
820
HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
822
/* Avoid twice printing of isam file name */
823
param->error_printed=1;
826
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);
828
case HA_ERR_NOT_A_TABLE:
829
mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
831
case HA_ERR_CRASHED_ON_USAGE:
832
mi_check_print_error(param,"'%s' is marked as crashed",filename);
834
case HA_ERR_CRASHED_ON_REPAIR:
835
mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
837
case HA_ERR_OLD_FILE:
838
mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
840
case HA_ERR_END_OF_FILE:
841
mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
844
mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
847
mi_check_print_error(param,"File '%s' doesn't exist",filename);
850
mi_check_print_error(param,"You don't have permission to use '%s'",filename);
853
mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
860
share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
861
share->tot_locks-= share->r_locks;
863
raid_chunks=share->base.raid_chunks;
866
Skip the checking of the file if:
867
We are using --fast and the table is closed properly
868
We are using --check-only-changed-tables and the table hasn't changed
870
if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
872
my_bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
874
if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
875
((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
876
STATE_CRASHED_ON_REPAIR) ||
877
!(param->testflag & T_CHECK_ONLY_CHANGED))))
880
if (info->s->base.keys && info->state->records)
882
if ((param->testflag & T_STATISTICS) &&
883
(share->state.changed & STATE_NOT_ANALYZED))
885
if ((param->testflag & T_SORT_INDEX) &&
886
(share->state.changed & STATE_NOT_SORTED_PAGES))
888
if ((param->testflag & T_REP_BY_SORT) &&
889
(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
892
if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
893
(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
894
STATE_CRASHED_ON_REPAIR)))
898
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
899
printf("MyISAM file: %s is already checked\n",filename);
902
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
909
if ((param->testflag & (T_REP_ANY | T_STATISTICS |
910
T_SORT_RECORDS | T_SORT_INDEX)) &&
911
(((param->testflag & T_UNPACK) &&
912
share->data_file_type == COMPRESSED_RECORD) ||
913
mi_uint2korr(share->state.header.state_info_length) !=
914
MI_STATE_INFO_SIZE ||
915
mi_uint2korr(share->state.header.base_info_length) !=
917
mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
918
~share->state.key_map) ||
919
test_if_almost_full(info) ||
920
info->s->state.header.file_version[3] != myisam_file_magic[3] ||
922
set_collation->number != share->state.header.language) ||
923
myisam_block_size != MI_KEY_BLOCK_LENGTH))
926
param->language= set_collation->number;
927
if (recreate_table(param, &info,filename))
930
"MyISAM-table '%s' is not fixed because of errors\n",
935
if (!(param->testflag & T_REP_ANY))
937
param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
938
if (!(param->testflag & T_SILENT))
939
printf("- '%s' has old table-format. Recreating index\n",filename);
943
share->tot_locks-= share->r_locks;
947
if (param->testflag & T_DESCRIPT)
949
param->total_files++;
950
param->total_records+=info->state->records;
951
param->total_deleted+=info->state->del;
952
descript(param, info, filename);
956
if (!stopwords_inited++)
959
if (!(param->testflag & T_READONLY))
960
lock_type = F_WRLCK; /* table is changed */
963
if (info->lock_type == F_RDLCK)
964
info->lock_type=F_UNLCK; /* Read only table */
965
if (_mi_readinfo(info,lock_type,0))
967
mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
969
param->error_printed=0;
973
_mi_readinfo() has locked the table.
974
We mark the table as locked (without doing file locks) to be able to
975
use functions that only works on locked tables (like row caching).
977
mi_lock_database(info, F_EXTRA_LCK);
978
datafile=info->dfile;
980
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
982
if (param->testflag & T_REP_ANY)
984
ulonglong tmp=share->state.key_map;
985
mi_copy_keys_active(share->state.key_map, share->base.keys,
987
if (tmp != share->state.key_map)
988
info->update|=HA_STATE_CHANGED;
990
if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
992
if (param->testflag & T_FORCE_CREATE)
995
mi_check_print_info(param,"Creating new data file\n");
1000
mi_check_print_error(param,
1001
"Quick-recover aborted; Run recovery without switch 'q'");
1006
if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
1007
(mi_is_any_key_active(share->state.key_map) ||
1008
(rep_quick && !param->keys_in_use && !recreate)) &&
1009
mi_test_if_sort_rep(info, info->state->records,
1010
info->s->state.key_map,
1013
if (param->testflag & T_REP_BY_SORT)
1014
error=mi_repair_by_sort(param,info,filename,rep_quick);
1016
error=mi_repair_parallel(param,info,filename,rep_quick);
1019
else if (param->testflag & T_REP_ANY)
1020
error=mi_repair(param, info,filename,rep_quick);
1022
if (!error && param->testflag & T_SORT_RECORDS)
1025
The data file is nowadays reopened in the repair code so we should
1026
soon remove the following reopen-code
1028
#ifndef TO_BE_REMOVED
1029
if (param->out_flag & O_NEW_DATA)
1030
{ /* Change temp file to org file */
1031
VOID(my_close(info->dfile,MYF(MY_WME))); /* Close new file */
1032
error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1035
if (mi_open_datafile(info,info->s, -1))
1037
param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */
1038
param->read_cache.file=info->dfile;
1045
We can't update the index in mi_sort_records if we have a
1046
prefix compressed or fulltext index
1048
my_bool update_index=1;
1049
for (key=0 ; key < share->base.keys; key++)
1050
if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY|HA_FULLTEXT))
1053
error=mi_sort_records(param,info,filename,param->opt_sort_key,
1054
/* what is the following parameter for ? */
1055
(my_bool) !(param->testflag & T_REP),
1057
datafile=info->dfile; /* This is now locked */
1058
if (!error && !update_index)
1061
puts("Table had a compressed index; We must now recreate the index");
1062
error=mi_repair_by_sort(param,info,filename,1);
1066
if (!error && param->testflag & T_SORT_INDEX)
1067
error=mi_sort_index(param,info,filename);
1069
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1070
STATE_CRASHED_ON_REPAIR);
1072
mi_mark_crashed(info);
1074
else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
1076
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1077
printf("Checking MyISAM file: %s\n",filename);
1078
if (!(param->testflag & T_SILENT))
1079
printf("Data records: %7s Deleted blocks: %7s\n",
1080
llstr(info->state->records,llbuff),
1081
llstr(info->state->del,llbuff2));
1082
error =chk_status(param,info);
1083
mi_intersect_keys_active(share->state.key_map, param->keys_in_use);
1084
error =chk_size(param,info);
1085
if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1086
error|=chk_del(param, info,param->testflag);
1087
if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1088
!param->start_check_pos)))
1090
error|=chk_key(param, info);
1091
if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1092
error=update_state_info(param, info,
1093
((param->testflag & T_STATISTICS) ?
1095
((param->testflag & T_AUTO_INC) ?
1096
UPDATE_AUTO_INC : 0));
1098
if ((!rep_quick && !error) ||
1099
!(param->testflag & (T_FAST | T_FORCE_CREATE)))
1101
if (param->testflag & (T_EXTEND | T_MEDIUM))
1102
VOID(init_key_cache(dflt_key_cache,opt_key_cache_block_size,
1103
param->use_buffers, 0, 0));
1104
VOID(init_io_cache(¶m->read_cache,datafile,
1105
(uint) param->read_buffer_length,
1107
(param->start_check_pos ?
1108
param->start_check_pos :
1109
share->pack.header_length),
1113
if ((info->s->options & (HA_OPTION_PACK_RECORD |
1114
HA_OPTION_COMPRESS_RECORD)) ||
1115
(param->testflag & (T_EXTEND | T_MEDIUM)))
1116
error|=chk_data_link(param, info, param->testflag & T_EXTEND);
1117
error|=flush_blocks(param, share->key_cache, share->kfile);
1118
VOID(end_io_cache(¶m->read_cache));
1122
if ((share->state.changed & STATE_CHANGED) &&
1123
(param->testflag & T_UPDATE_STATE))
1124
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1125
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1126
STATE_CRASHED_ON_REPAIR);
1128
else if (!mi_is_crashed(info) &&
1129
(param->testflag & T_UPDATE_STATE))
1130
{ /* Mark crashed */
1131
mi_mark_crashed(info);
1132
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1136
if ((param->testflag & T_AUTO_INC) ||
1137
((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1138
update_auto_increment_key(param, info,
1139
(my_bool) !test(param->testflag & T_AUTO_INC));
1141
if (!(param->testflag & T_DESCRIPT))
1143
if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1144
error|=update_state_info(param, info,
1146
(((param->testflag & T_REP_ANY) ?
1148
(state_updated ? UPDATE_STAT : 0) |
1149
((param->testflag & T_SORT_RECORDS) ?
1151
VOID(lock_file(param, share->kfile,0L,F_UNLCK,"indexfile",filename));
1152
info->update&= ~HA_STATE_CHANGED;
1154
mi_lock_database(info, F_UNLCK);
1158
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
1163
if (param->out_flag & O_NEW_DATA)
1164
error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1166
((param->testflag & T_BACKUP_DATA) ?
1167
MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1168
if (param->out_flag & O_NEW_INDEX)
1169
error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1172
VOID(fflush(stdout)); VOID(fflush(stderr));
1173
if (param->error_printed)
1175
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1177
VOID(fprintf(stderr,
1178
"MyISAM-table '%s' is not fixed because of errors\n",
1180
if (param->testflag & T_REP_ANY)
1181
VOID(fprintf(stderr,
1182
"Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n"));
1184
else if (!(param->error_printed & 2) &&
1185
!(param->testflag & T_FORCE_CREATE))
1186
VOID(fprintf(stderr,
1187
"MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
1190
else if (param->warning_printed &&
1191
! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1193
VOID(fprintf(stderr, "MyISAM-table '%s' is usable but should be fixed\n",
1195
VOID(fflush(stderr));
1200
/* Write info about table */
1202
static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
1204
uint key,keyseg_nr,field,start;
1205
register MI_KEYDEF *keyinfo;
1206
register HA_KEYSEG *keyseg;
1207
register const char *text;
1208
char buff[160],length[10],*pos,*end;
1209
enum en_fieldtype type;
1210
MYISAM_SHARE *share=info->s;
1211
char llbuff[22],llbuff2[22];
1212
DBUG_ENTER("describe");
1214
printf("\nMyISAM file: %s\n",name);
1215
fputs("Record format: ",stdout);
1216
if (share->options & HA_OPTION_COMPRESS_RECORD)
1218
else if (share->options & HA_OPTION_PACK_RECORD)
1221
puts("Fixed length");
1222
printf("Character set: %s (%d)\n",
1223
get_charset_name(share->state.header.language),
1224
share->state.header.language);
1226
if (param->testflag & T_VERBOSE)
1228
printf("File-version: %d\n",
1229
(int) share->state.header.file_version[3]);
1230
if (share->state.create_time)
1232
get_date(buff,1,share->state.create_time);
1233
printf("Creation time: %s\n",buff);
1235
if (share->state.check_time)
1237
get_date(buff,1,share->state.check_time);
1238
printf("Recover time: %s\n",buff);
1241
if (share->state.changed & STATE_CRASHED)
1242
strmov(buff,"crashed");
1245
if (share->state.open_count)
1246
pos=strmov(pos,"open,");
1247
if (share->state.changed & STATE_CHANGED)
1248
pos=strmov(pos,"changed,");
1250
pos=strmov(pos,"checked,");
1251
if (!(share->state.changed & STATE_NOT_ANALYZED))
1252
pos=strmov(pos,"analyzed,");
1253
if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1254
pos=strmov(pos,"optimized keys,");
1255
if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1256
pos=strmov(pos,"sorted index pages,");
1257
pos[-1]=0; /* Remove extra ',' */
1259
printf("Status: %s\n",buff);
1260
if (share->base.auto_key)
1262
printf("Auto increment key: %13d Last value: %13s\n",
1263
share->base.auto_key,
1264
llstr(share->state.auto_increment,llbuff));
1266
if (share->base.raid_type)
1268
printf("RAID: Type: %u Chunks: %u Chunksize: %lu\n",
1269
share->base.raid_type,
1270
share->base.raid_chunks,
1271
share->base.raid_chunksize);
1273
if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1274
printf("Checksum: %23s\n",llstr(info->state->checksum,llbuff));
1276
if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1277
printf("Keys are only flushed at close\n");
1280
printf("Data records: %13s Deleted blocks: %13s\n",
1281
llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1282
if (param->testflag & T_SILENT)
1283
DBUG_VOID_RETURN; /* This is enough */
1285
if (param->testflag & T_VERBOSE)
1288
printf("Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
1290
printf("Datafile parts: %13s Deleted data: %13s\n",
1291
llstr(share->state.split,llbuff),
1292
llstr(info->state->empty,llbuff2));
1293
printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
1294
share->rec_reflength,share->base.key_reflength);
1295
printf("Datafile length: %13s Keyfile length: %13s\n",
1296
llstr(info->state->data_file_length,llbuff),
1297
llstr(info->state->key_file_length,llbuff2));
1299
if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1300
puts("This is a one-record table");
1303
if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1304
share->base.max_key_file_length != HA_OFFSET_ERROR)
1305
printf("Max datafile length: %13s Max keyfile length: %13s\n",
1306
llstr(share->base.max_data_file_length-1,llbuff),
1307
llstr(share->base.max_key_file_length-1,llbuff2));
1311
printf("Recordlength: %13d\n",(int) share->base.pack_reclength);
1312
if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1314
longlong2str(share->state.key_map,buff,2);
1315
printf("Using only keys '%s' of %d possibly keys\n",
1316
buff, share->base.keys);
1318
puts("\ntable description:");
1319
printf("Key Start Len Index Type");
1320
if (param->testflag & T_VERBOSE)
1321
printf(" Rec/key Root Blocksize");
1322
VOID(putchar('\n'));
1324
for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1325
key < share->base.keys;
1328
keyseg=keyinfo->seg;
1329
if (keyinfo->flag & HA_NOSAME) text="unique ";
1330
else if (keyinfo->flag & HA_FULLTEXT) text="fulltext ";
1331
else text="multip.";
1334
if (keyseg->flag & HA_REVERSE_SORT)
1336
pos=strmov(pos,type_names[keyseg->type]);
1339
if (keyinfo->flag & HA_PACK_KEY)
1340
pos=strmov(pos,prefix_packed_txt);
1341
if (keyinfo->flag & HA_BINARY_PACK_KEY)
1342
pos=strmov(pos,bin_packed_txt);
1343
if (keyseg->flag & HA_SPACE_PACK)
1344
pos=strmov(pos,diff_txt);
1345
if (keyseg->flag & HA_BLOB_PART)
1346
pos=strmov(pos,blob_txt);
1347
if (keyseg->flag & HA_NULL_PART)
1348
pos=strmov(pos,null_txt);
1351
printf("%-4d%-6ld%-3d %-8s%-21s",
1352
key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1353
if (share->state.key_root[key] != HA_OFFSET_ERROR)
1354
llstr(share->state.key_root[key],buff);
1357
if (param->testflag & T_VERBOSE)
1358
printf("%11lu %12s %10d",
1359
share->state.rec_per_key_part[keyseg_nr++],
1360
buff,keyinfo->block_length);
1361
VOID(putchar('\n'));
1362
while ((++keyseg)->type != HA_KEYTYPE_END)
1365
if (keyseg->flag & HA_REVERSE_SORT)
1367
pos=strmov(pos,type_names[keyseg->type]);
1369
if (keyseg->flag & HA_SPACE_PACK)
1370
pos=strmov(pos,diff_txt);
1371
if (keyseg->flag & HA_BLOB_PART)
1372
pos=strmov(pos,blob_txt);
1373
if (keyseg->flag & HA_NULL_PART)
1374
pos=strmov(pos,null_txt);
1376
printf(" %-6ld%-3d %-21s",
1377
(long) keyseg->start+1,keyseg->length,buff);
1378
if (param->testflag & T_VERBOSE)
1379
printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1380
VOID(putchar('\n'));
1384
if (share->state.header.uniques)
1386
MI_UNIQUEDEF *uniqueinfo;
1387
puts("\nUnique Key Start Len Nullpos Nullbit Type");
1388
for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1389
key < share->state.header.uniques; key++, uniqueinfo++)
1392
char null_bit[8],null_pos[8];
1393
printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1394
for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1398
null_bit[0]=null_pos[0]=0;
1399
if (keyseg->null_bit)
1401
sprintf(null_bit,"%d",keyseg->null_bit);
1402
sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1404
printf("%-7ld%-5d%-9s%-10s%-30s\n",
1405
(long) keyseg->start+1,keyseg->length,
1407
type_names[keyseg->type]);
1412
if (param->verbose > 1)
1414
char null_bit[8],null_pos[8];
1415
printf("\nField Start Length Nullpos Nullbit Type");
1416
if (share->options & HA_OPTION_COMPRESS_RECORD)
1417
printf(" Huff tree Bits");
1418
VOID(putchar('\n'));
1420
for (field=0 ; field < share->base.fields ; field++)
1422
if (share->options & HA_OPTION_COMPRESS_RECORD)
1423
type=share->rec[field].base_type;
1425
type=(enum en_fieldtype) share->rec[field].type;
1426
end=strmov(buff,field_pack[type]);
1427
if (share->options & HA_OPTION_COMPRESS_RECORD)
1429
if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1430
end=strmov(end,", not_always");
1431
if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1432
end=strmov(end,", no empty");
1433
if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1435
sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
1440
strmov(buff,buff+2);
1441
int10_to_str((long) share->rec[field].length,length,10);
1442
null_bit[0]=null_pos[0]=0;
1443
if (share->rec[field].null_bit)
1445
sprintf(null_bit,"%d",share->rec[field].null_bit);
1446
sprintf(null_pos,"%d",share->rec[field].null_pos+1);
1448
printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1449
null_pos, null_bit, buff);
1450
if (share->options & HA_OPTION_COMPRESS_RECORD)
1452
if (share->rec[field].huff_tree)
1454
(uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1455
share->rec[field].huff_tree->quick_table_bits);
1457
VOID(putchar('\n'));
1458
start+=share->rec[field].length;
1465
/* Sort records according to one key */
1467
static int mi_sort_records(MI_CHECK *param,
1468
register MI_INFO *info, char * name,
1471
my_bool update_index)
1478
ha_rows old_record_count;
1479
MYISAM_SHARE *share=info->s;
1480
char llbuff[22],llbuff2[22];
1481
SORT_INFO sort_info;
1482
MI_SORT_PARAM sort_param;
1483
DBUG_ENTER("sort_records");
1485
bzero((char*)&sort_info,sizeof(sort_info));
1486
bzero((char*)&sort_param,sizeof(sort_param));
1487
sort_param.sort_info=&sort_info;
1488
sort_info.param=param;
1489
keyinfo= &share->keyinfo[sort_key];
1494
if (! mi_is_key_active(share->state.key_map, sort_key))
1496
mi_check_print_warning(param,
1497
"Can't sort table '%s' on key %d; No such key",
1499
param->error_printed=0;
1500
DBUG_RETURN(0); /* Nothing to do */
1502
if (keyinfo->flag & HA_FULLTEXT)
1504
mi_check_print_warning(param,"Can't sort table '%s' on FULLTEXT key %d",
1506
param->error_printed=0;
1507
DBUG_RETURN(0); /* Nothing to do */
1509
if (share->data_file_type == COMPRESSED_RECORD)
1511
mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
1512
param->error_printed=0;
1513
DBUG_RETURN(0); /* Nothing to do */
1515
if (!(param->testflag & T_SILENT))
1517
printf("- Sorting records for MyISAM-table '%s'\n",name);
1519
printf("Data records: %9s Deleted: %9s\n",
1520
llstr(info->state->records,llbuff),
1521
llstr(info->state->del,llbuff2));
1523
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1524
DBUG_RETURN(0); /* Nothing to do */
1526
init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers,
1528
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1529
WRITE_CACHE,share->pack.header_length,1,
1530
MYF(MY_WME | MY_WAIT_IF_FULL)))
1532
info->opt_flag|=WRITE_CACHE_USED;
1534
if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
1536
mi_check_print_error(param,"Not enough memory for key block");
1540
if (!mi_alloc_rec_buff(info, -1, &sort_param.record))
1542
mi_check_print_error(param,"Not enough memory for record");
1545
fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
1546
new_file=my_raid_create(fn_format(param->temp_filename,
1547
param->temp_filename,"",
1549
0,param->tmpfile_createflag,
1550
share->base.raid_type,
1551
share->base.raid_chunks,
1552
share->base.raid_chunksize,
1556
mi_check_print_error(param,"Can't create new tempfile: '%s'",
1557
param->temp_filename);
1560
if (share->pack.header_length)
1561
if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1564
info->rec_cache.file=new_file; /* Use this file for cacheing*/
1567
for (key=0 ; key < share->base.keys ; key++)
1568
share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1570
if (my_pread(share->kfile,(uchar*) temp_buff,
1571
(uint) keyinfo->block_length,
1572
share->state.key_root[sort_key],
1573
MYF(MY_NABP+MY_WME)))
1575
mi_check_print_error(param,"Can't read indexpage from filepos: %s",
1576
(ulong) share->state.key_root[sort_key]);
1580
/* Setup param for sort_write_record */
1581
sort_info.info=info;
1582
sort_info.new_data_file_type=share->data_file_type;
1583
sort_param.fix_datafile=1;
1584
sort_param.master=1;
1585
sort_param.filepos=share->pack.header_length;
1586
old_record_count=info->state->records;
1587
info->state->records=0;
1588
if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1589
info->state->checksum=0;
1591
if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1592
temp_buff, sort_key,new_file,update_index) ||
1593
write_data_suffix(&sort_info,1) ||
1594
flush_io_cache(&info->rec_cache))
1597
if (info->state->records != old_record_count)
1599
mi_check_print_error(param,"found %s of %s records",
1600
llstr(info->state->records,llbuff),
1601
llstr(old_record_count,llbuff2));
1605
VOID(my_close(info->dfile,MYF(MY_WME)));
1606
param->out_flag|=O_NEW_DATA; /* Data in new file */
1607
info->dfile=new_file; /* Use new datafile */
1609
info->state->empty=0;
1610
share->state.dellink= HA_OFFSET_ERROR;
1611
info->state->data_file_length=sort_param.filepos;
1612
share->state.split=info->state->records; /* Only hole records */
1613
share->state.version=(ulong) time((time_t*) 0);
1615
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1617
if (param->testflag & T_WRITE_LOOP)
1619
VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
1624
if (got_error && new_file >= 0)
1626
VOID(end_io_cache(&info->rec_cache));
1627
(void) my_close(new_file,MYF(MY_WME));
1628
(void) my_raid_delete(param->temp_filename, share->base.raid_chunks,
1633
my_afree((uchar*) temp_buff);
1635
my_free(mi_get_rec_buff_ptr(info, sort_param.record),
1636
MYF(MY_ALLOW_ZERO_PTR));
1637
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1638
VOID(end_io_cache(&info->rec_cache));
1639
my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
1641
share->state.sortkey=sort_key;
1642
DBUG_RETURN(flush_blocks(param, share->key_cache, share->kfile) |
1644
} /* sort_records */
1647
/* Sort records recursive using one index */
1649
static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
1651
my_off_t page, uchar *buff, uint sort_key,
1652
File new_file,my_bool update_index)
1654
uint nod_flag,used_length,key_length;
1655
uchar *temp_buff,*keypos,*endpos;
1656
my_off_t next_page,rec_pos;
1657
uchar lastkey[MI_MAX_KEY_BUFF];
1659
SORT_INFO *sort_info= sort_param->sort_info;
1660
MI_CHECK *param=sort_info->param;
1661
DBUG_ENTER("sort_record_index");
1663
nod_flag=mi_test_if_nod(buff);
1668
if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
1670
mi_check_print_error(param,"Not Enough memory");
1674
used_length=mi_getint(buff);
1675
keypos=buff+2+nod_flag;
1676
endpos=buff+used_length;
1681
next_page=_mi_kpos(nod_flag,keypos);
1682
if (my_pread(info->s->kfile,(uchar*) temp_buff,
1683
(uint) keyinfo->block_length, next_page,
1684
MYF(MY_NABP+MY_WME)))
1686
mi_check_print_error(param,"Can't read keys from filepos: %s",
1687
llstr(next_page,llbuff));
1690
if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1691
new_file, update_index))
1694
if (keypos >= endpos ||
1695
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1698
rec_pos= _mi_dpos(info,0,lastkey+key_length);
1700
if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1702
mi_check_print_error(param,"%d when reading datafile",my_errno);
1705
if (rec_pos != sort_param->filepos && update_index)
1707
_mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1708
sort_param->filepos);
1709
if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1712
mi_check_print_error(param,"%d when updating key-pointers",my_errno);
1716
if (sort_write_record(sort_param))
1719
/* Clear end of block to get better compression if the table is backuped */
1720
bzero((uchar*) buff+used_length,keyinfo->block_length-used_length);
1721
if (my_pwrite(info->s->kfile,(uchar*) buff,(uint) keyinfo->block_length,
1722
page,param->myf_rw))
1724
mi_check_print_error(param,"%d when updating keyblock",my_errno);
1728
my_afree((uchar*) temp_buff);
1732
my_afree((uchar*) temp_buff);
1734
} /* sort_record_index */
1739
Check if myisamchk was killed by a signal
1740
This is overloaded by other programs that want to be able to abort
1744
static int not_killed= 0;
1746
volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
1748
return ¬_killed; /* always NULL */
1751
/* print warnings and errors */
1754
void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
1755
const char *fmt,...)
1760
VOID(vfprintf(stdout, fmt, args));
1761
VOID(fputc('\n',stdout));
1767
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
1770
DBUG_ENTER("mi_check_print_warning");
1773
if (!param->warning_printed && !param->error_printed)
1775
if (param->testflag & T_SILENT)
1776
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,
1777
param->isam_file_name);
1778
param->out_flag|= O_DATA_LOST;
1780
param->warning_printed=1;
1782
fprintf(stderr,"%s: warning: ",my_progname_short);
1783
VOID(vfprintf(stderr, fmt, args));
1784
VOID(fputc('\n',stderr));
1792
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
1795
DBUG_ENTER("mi_check_print_error");
1796
DBUG_PRINT("enter",("format: %s",fmt));
1799
if (!param->warning_printed && !param->error_printed)
1801
if (param->testflag & T_SILENT)
1802
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1803
param->out_flag|= O_DATA_LOST;
1805
param->error_printed|=1;
1807
fprintf(stderr,"%s: error: ",my_progname_short);
1808
VOID(vfprintf(stderr, fmt, args));
1809
VOID(fputc('\n',stderr));
1815
#include "mi_extrafunc.h"