19 #include "my_default.h"
23 #include <my_getopt.h>
25 #ifdef HAVE_SYS_VADVICE_H
26 #include <sys/vadvise.h>
28 #ifdef HAVE_SYS_MMAN_H
32 static uint decode_bits;
33 static char **default_argv;
34 static const char *load_default_groups[]= {
"myisamchk", 0 };
35 static const char *set_collation_name, *opt_tmpdir;
37 static long opt_myisam_block_size;
38 static long opt_key_cache_block_size;
39 static const char *my_progname_short;
40 static int stopwords_inited= 0;
43 static const char *type_names[]=
44 {
"impossible",
"char",
"binary",
"short",
"long",
"float",
45 "double",
"number",
"unsigned short",
46 "unsigned long",
"longlong",
"ulonglong",
"int24",
47 "uint24",
"int8",
"varchar",
"varbin",
"?",
50 static const char *prefix_packed_txt=
"packed ",
51 *bin_packed_txt=
"prefix ",
52 *diff_txt=
"stripped ",
56 static const char *field_pack[]=
57 {
"",
"no endspace",
"no prespace",
58 "no zeros",
"blob",
"constant",
"table-lockup",
59 "always zero",
"varchar",
"unique-hash",
"?",
"?"};
61 static const char *myisam_stats_method_str=
"nulls_unequal";
63 static void get_options(
int *argc,
char * * *argv);
64 static void print_version(
void);
65 static void usage(
void);
66 static int myisamchk(
MI_CHECK *param,
char *filename);
69 char *
name, uint sort_key,
70 my_bool write_info, my_bool update_index);
73 my_off_t
page,uchar *buff,uint sortkey,
74 File new_file, my_bool update_index);
80 int main(
int argc,
char **argv)
84 my_progname_short= my_progname+dirname_length(my_progname);
86 myisamchk_init(&check_param);
87 check_param.opt_lock_memory=1;
88 check_param.using_global_keycache = 0;
89 get_options(&argc,(
char***) &argv);
90 myisam_quick_table_bits=decode_bits;
94 int new_error=myisamchk(&check_param, *(argv++));
95 if ((check_param.testflag & T_REP_ANY) != T_REP)
96 check_param.testflag&= ~T_REP;
97 (void) fflush(stdout);
98 (void) fflush(stderr);
99 if ((check_param.error_printed | check_param.warning_printed) &&
100 (check_param.testflag & T_FORCE_CREATE) &&
101 (!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
104 uint old_testflag=check_param.testflag;
105 if (!(check_param.testflag & T_REP))
106 check_param.testflag|= T_REP_BY_SORT;
107 check_param.testflag&= ~T_EXTEND;
108 error|=myisamchk(&check_param, argv[-1]);
109 check_param.testflag= old_testflag;
110 (void) fflush(stdout);
111 (void) fflush(stderr);
115 if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
117 puts(
"\n---------\n");
118 (void) fflush(stdout);
121 if (check_param.total_files > 1)
123 char buff[22],buff2[22];
124 if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
125 puts(
"\n---------\n");
126 printf(
"\nTotal of all %d MyISAM-files:\nData records: %9s Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
127 llstr(check_param.total_deleted,buff2));
129 free_defaults(default_argv);
130 free_tmpdir(&myisamchk_tmpdir);
132 my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
140 OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
141 OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE,
142 OPT_KEY_CACHE_BLOCK_SIZE, OPT_MYISAM_BLOCK_SIZE,
143 OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
144 OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN,
145 OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE,
146 OPT_MAX_RECORD_LENGTH, OPT_STATS_METHOD
149 static struct my_option my_long_options[] =
152 "Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
153 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
154 {
"block-search",
'b',
155 "No help available.",
156 0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
158 "Make a backup of the .MYD file as 'filename-time.BAK'.",
159 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
160 {
"character-sets-dir", OPT_CHARSETS_DIR,
161 "Directory where character sets are.",
162 &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
164 "Check table for errors.",
165 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
166 {
"check-only-changed",
'C',
167 "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).",
168 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
169 {
"correct-checksum", OPT_CORRECT_CHECKSUM,
170 "Correct checksum information for table.",
171 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
174 "Output debug log. Often this is 'd:t:o,filename'.",
175 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
178 "Prints some information about table.",
179 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
180 {
"data-file-length",
'D',
181 "Max length of data file (when recreating data-file when it's full).",
182 &check_param.max_data_file_length,
183 &check_param.max_data_file_length,
184 0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
185 {
"extend-check",
'e',
186 "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.",
187 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
189 "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).",
190 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
192 "Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
193 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
195 "Display this help and exit.",
196 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
198 "Display this help and exit.",
199 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
201 "Print statistics information about table that is checked.",
202 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
204 "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.",
205 &check_param.keys_in_use,
206 &check_param.keys_in_use,
207 0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
208 {
"max-record-length", OPT_MAX_RECORD_LENGTH,
209 "Skip rows bigger than this if myisamchk can't allocate memory to hold it",
210 &check_param.max_record_length,
211 &check_param.max_record_length,
212 0, GET_ULL, REQUIRED_ARG, LONGLONG_MAX, 0, LONGLONG_MAX, 0, 0, 0},
213 {
"medium-check",
'm',
214 "Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
215 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
216 {
"quick",
'q',
"Faster repair by not modifying the data file.",
217 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
219 "Don't mark table as checked.",
220 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
222 "Can fix almost anything except unique keys that aren't unique.",
223 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
224 {
"parallel-recover",
'p',
225 "Same as '-r' but creates all the keys in parallel.",
226 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
227 {
"safe-recover",
'o',
228 "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.",
229 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
230 {
"sort-recover",
'n',
231 "Force recovering with sorting even if the temporary file was very big.",
232 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
234 {
"start-check-pos", OPT_START_CHECK_POS,
235 "No help available.",
236 0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
238 {
"set-auto-increment",
'A',
239 "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.",
240 &check_param.auto_increment_value,
241 &check_param.auto_increment_value,
242 0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
243 {
"set-collation", OPT_SET_COLLATION,
244 "Change the collation used by the index",
245 &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
247 "Only print errors. One can use two -s to make myisamchk very silent.",
248 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
250 "Sort index blocks. This speeds up 'read-next' in applications.",
251 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
252 {
"sort-records",
'R',
253 "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!)",
254 &check_param.opt_sort_key,
255 &check_param.opt_sort_key,
256 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
258 "Path for temporary files.",
260 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
261 {
"update-state",
'U',
262 "Mark tables as crashed if any errors were found.",
263 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
265 "Unpack file packed with myisampack.",
266 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
268 "Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
269 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
271 "Print version and exit.",
272 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
274 "Wait if table is locked.",
275 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
276 {
"key_buffer_size", OPT_KEY_BUFFER_SIZE,
"",
277 &check_param.use_buffers, &check_param.use_buffers, 0,
278 GET_ULL, REQUIRED_ARG, USE_BUFFER_INIT, MALLOC_OVERHEAD,
279 SIZE_T_MAX, MALLOC_OVERHEAD, IO_SIZE, 0},
280 {
"key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE,
"",
281 &opt_key_cache_block_size,
282 &opt_key_cache_block_size, 0,
283 GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
284 MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
285 {
"myisam_block_size", OPT_MYISAM_BLOCK_SIZE,
"",
286 &opt_myisam_block_size, &opt_myisam_block_size, 0,
287 GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
288 MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
289 {
"read_buffer_size", OPT_READ_BUFFER_SIZE,
"",
290 &check_param.read_buffer_length,
291 &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
292 (long) READ_BUFFER_INIT, (
long) MALLOC_OVERHEAD,
293 INT_MAX32, (long) MALLOC_OVERHEAD, (
long) 1L, 0},
294 {
"write_buffer_size", OPT_WRITE_BUFFER_SIZE,
"",
295 &check_param.write_buffer_length,
296 &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
297 (long) READ_BUFFER_INIT, (
long) MALLOC_OVERHEAD,
298 INT_MAX32, (long) MALLOC_OVERHEAD, (
long) 1L, 0},
299 {
"sort_buffer_size", OPT_SORT_BUFFER_SIZE,
300 "Deprecated. myisam_sort_buffer_size alias is being used",
301 &check_param.sort_buffer_length,
302 &check_param.sort_buffer_length, 0, GET_ULL, REQUIRED_ARG,
303 (long) SORT_BUFFER_INIT, (
long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
304 SIZE_T_MAX, (
long) MALLOC_OVERHEAD, (long) 1L, 0},
305 {
"myisam_sort_buffer_size", OPT_SORT_BUFFER_SIZE,
306 "Alias of sort_buffer_size parameter",
307 &check_param.sort_buffer_length,
308 &check_param.sort_buffer_length, 0, GET_ULL, REQUIRED_ARG,
309 (long) SORT_BUFFER_INIT, (
long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
310 SIZE_T_MAX, (
long) MALLOC_OVERHEAD, (long) 1L, 0},
311 {
"sort_key_blocks", OPT_SORT_KEY_BLOCKS,
"",
312 &check_param.sort_key_blocks,
313 &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
314 BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
315 {
"decode_bits", OPT_DECODE_BITS,
"", &decode_bits,
316 &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
317 {
"ft_min_word_len", OPT_FT_MIN_WORD_LEN,
"", &ft_min_word_len,
318 &ft_min_word_len, 0, GET_ULONG, REQUIRED_ARG, 4, 1, HA_FT_MAXCHARLEN,
320 {
"ft_max_word_len", OPT_FT_MAX_WORD_LEN,
"", &ft_max_word_len,
321 &ft_max_word_len, 0, GET_ULONG, REQUIRED_ARG, HA_FT_MAXCHARLEN, 10,
322 HA_FT_MAXCHARLEN, 0, 1, 0},
323 {
"ft_stopword_file", OPT_FT_STOPWORD_FILE,
324 "Use stopwords from this file instead of built-in list.",
325 &ft_stopword_file, &ft_stopword_file, 0, GET_STR,
326 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
327 {
"stats_method", OPT_STATS_METHOD,
328 "Specifies how index statistics collection code should treat NULLs. "
329 "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
330 "\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
331 &myisam_stats_method_str, &myisam_stats_method_str, 0,
332 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
333 { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
337 static void print_version(
void)
339 printf(
"%s Ver 2.7 for %s at %s\n", my_progname, SYSTEM_TYPE,
344 static void usage(
void)
347 puts(
"By Monty, for your professional use");
348 puts(
"This software comes with NO WARRANTY: see the PUBLIC for details.\n");
349 puts(
"Description, check and repair of MyISAM tables.");
350 puts(
"Used without options all tables on the command will be checked for errors");
351 printf(
"Usage: %s [OPTIONS] tables[.MYI]\n", my_progname_short);
352 printf(
"\nGlobal options:\n");
355 -#, --debug=... Output debug log. Often this is 'd:t:o,filename'.\n");
358 -H, --HELP Display this help and exit.\n\
359 -?, --help Display this help and exit.\n\
360 -t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
361 specified, separated by ");
362 #if defined( __WIN__)
363 printf(
"semicolon (;)");
367 printf(
", they will be used\n\
368 in a round-robin fashion.\n\
369 -s, --silent Only print errors. One can use two -s to make\n\
370 myisamchk very silent.\n\
371 -v, --verbose Print more information. This can be used with\n\
372 --description and --check. Use many -v for more verbosity.\n\
373 -V, --version Print version and exit.\n\
374 -w, --wait Wait if table is locked.\n\n");
376 puts(
" --start-check-pos=# Start reading file at given offset.\n");
379 puts(
"Check options (check is the default action for myisamchk):\n\
380 -c, --check Check table for errors.\n\
381 -e, --extend-check Check the table VERY throughly. Only use this in\n\
382 extreme cases as myisamchk should normally be able to\n\
383 find out if the table is ok even without this switch.\n\
384 -F, --fast Check only tables that haven't been closed properly.\n\
385 -C, --check-only-changed\n\
386 Check only tables that have changed since last check.\n\
387 -f, --force Restart with '-r' if there are any errors in the table.\n\
388 States will be updated as with '--update-state'.\n\
389 -i, --information Print statistics information about table that is checked.\n\
390 -m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
391 all errors. Should be good enough for most cases.\n\
392 -U --update-state Mark tables as crashed if you find any errors.\n\
393 -T, --read-only Don't mark table as checked.\n");
395 puts(
"Repair options (When using '-r' or '-o'):\n\
396 -B, --backup Make a backup of the .MYD file as 'filename-time.BAK'.\n\
397 --correct-checksum Correct checksum information for table.\n\
398 -D, --data-file-length=# Max length of data file (when recreating data\n\
399 file when it's full).\n\
400 -e, --extend-check Try to recover every possible row from the data file\n\
401 Normally this will also find a lot of garbage rows;\n\
402 Don't use this option if you are not totally desperate.\n\
403 -f, --force Overwrite old temporary files.\n\
404 -k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\
405 bit mask of which keys to use. This can be used to\n\
406 get faster inserts.\n\
407 --max-record-length=#\n\
408 Skip rows bigger than this if myisamchk can't allocate\n\
409 memory to hold it.\n\
410 -r, --recover Can fix almost anything except unique keys that aren't\n\
412 -n, --sort-recover Forces recovering with sorting even if the temporary\n\
413 file would be very big.\n\
414 -p, --parallel-recover\n\
415 Uses the same technique as '-r' and '-n', but creates\n\
416 all the keys in parallel, in different threads.\n\
417 -o, --safe-recover Uses old recovery method; Slower than '-r' but can\n\
418 handle a couple of cases where '-r' reports that it\n\
419 can't fix the data file.\n\
420 --character-sets-dir=...\n\
421 Directory where character sets are.\n\
422 --set-collation=name\n\
423 Change the collation used by the index.\n\
424 -q, --quick Faster repair by not modifying the data file.\n\
425 One can give a second '-q' to force myisamchk to\n\
426 modify the original datafile in case of duplicate keys.\n\
427 NOTE: Tables where the data file is currupted can't be\n\
428 fixed with this option.\n\
429 -u, --unpack Unpack file packed with myisampack.\n\
432 puts(
"Other actions:\n\
433 -a, --analyze Analyze distribution of keys. Will make some joins in\n\
434 MySQL faster. You can check the calculated distribution\n\
435 by using '--description --verbose table_name'.\n\
436 --stats_method=name Specifies how index statistics collection code should\n\
437 treat NULLs. Possible values of name are \"nulls_unequal\"\n\
438 (default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
439 \"nulls_ignored\".\n\
440 -d, --description Prints some information about table.\n\
441 -A, --set-auto-increment[=value]\n\
442 Force auto_increment to start at this or higher value\n\
443 If no value is given, then sets the next auto_increment\n\
444 value to the highest used value for the auto key + 1.\n\
445 -S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
447 -R, --sort-records=#\n\
448 Sort records according to an index. This makes your\n\
449 data much more localized and may speed up things\n\
450 (It may be VERY slow to do a sort the first time!).\n\
451 -b, --block-search=#\n\
452 Find a record, a block at given offset belongs to.");
454 print_defaults(
"my", load_default_groups);
455 my_print_variables(my_long_options);
459 const char *myisam_stats_method_names[] = {
"nulls_unequal",
"nulls_equal",
460 "nulls_ignored", NullS};
461 TYPELIB myisam_stats_method_typelib= {
462 array_elements(myisam_stats_method_names) - 1,
"",
463 myisam_stats_method_names, NULL};
468 get_one_option(
int optid,
469 const struct my_option *opt __attribute__((unused)),
474 if (argument == disabled_my_option)
475 check_param.testflag&= ~T_STATISTICS;
477 check_param.testflag|= T_STATISTICS;
481 check_param.auto_increment_value= strtoull(argument, NULL, 0);
483 check_param.auto_increment_value= 0;
484 check_param.testflag|= T_AUTO_INC;
487 check_param.search_after_block= strtoul(argument, NULL, 10);
490 if (argument == disabled_my_option)
491 check_param.testflag&= ~T_BACKUP_DATA;
493 check_param.testflag|= T_BACKUP_DATA;
496 if (argument == disabled_my_option)
497 check_param.testflag&= ~T_CHECK;
499 check_param.testflag|= T_CHECK;
502 if (argument == disabled_my_option)
503 check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
505 check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
508 check_param.max_data_file_length=strtoll(argument, NULL, 10);
511 if (argument == disabled_my_option)
512 check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
515 if (check_param.testflag & T_SILENT)
516 check_param.testflag|= T_VERY_SILENT;
517 check_param.testflag|= T_SILENT;
518 check_param.testflag&= ~T_WRITE_LOOP;
522 if (argument == disabled_my_option)
523 check_param.testflag&= ~T_WAIT_FOREVER;
525 check_param.testflag|= T_WAIT_FOREVER;
528 if (argument == disabled_my_option)
529 check_param.testflag&= ~T_DESCRIPT;
531 check_param.testflag|= T_DESCRIPT;
534 if (argument == disabled_my_option)
535 check_param.testflag&= ~T_EXTEND;
537 check_param.testflag|= T_EXTEND;
540 if (argument == disabled_my_option)
541 check_param.testflag&= ~T_INFO;
543 check_param.testflag|= T_INFO;
546 if (argument == disabled_my_option)
548 check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
549 check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
553 check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
554 check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
558 if (argument == disabled_my_option)
559 check_param.testflag&= ~T_FAST;
561 check_param.testflag|= T_FAST;
564 check_param.keys_in_use= (ulonglong) strtoll(argument, NULL, 10);
567 if (argument == disabled_my_option)
568 check_param.testflag&= ~T_MEDIUM;
570 check_param.testflag|= T_MEDIUM;
573 check_param.testflag&= ~T_REP_ANY;
574 if (argument != disabled_my_option)
575 check_param.testflag|= T_REP_BY_SORT;
578 check_param.testflag&= ~T_REP_ANY;
579 if (argument != disabled_my_option)
580 check_param.testflag|= T_REP_PARALLEL;
583 check_param.testflag&= ~T_REP_ANY;
584 check_param.force_sort= 0;
585 if (argument != disabled_my_option)
587 check_param.testflag|= T_REP;
588 my_disable_async_io= 1;
592 check_param.testflag&= ~T_REP_ANY;
593 if (argument == disabled_my_option)
594 check_param.force_sort= 0;
597 check_param.testflag|= T_REP_BY_SORT;
598 check_param.force_sort= 1;
602 if (argument == disabled_my_option)
603 check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
605 check_param.testflag|=
606 (check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
609 if (argument == disabled_my_option)
610 check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
612 check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
615 if (argument == disabled_my_option)
617 check_param.testflag&= ~T_VERBOSE;
618 check_param.verbose=0;
622 check_param.testflag|= T_VERBOSE;
623 check_param.verbose++;
627 if (argument == disabled_my_option)
628 check_param.testflag&= ~T_SORT_RECORDS;
631 check_param.testflag|= T_SORT_RECORDS;
632 check_param.opt_sort_key= (uint) atoi(argument) - 1;
633 if (check_param.opt_sort_key >= MI_MAX_KEY)
636 "The value of the sort key is bigger than max key: %d.\n",
643 if (argument == disabled_my_option)
644 check_param.testflag&= ~T_SORT_INDEX;
646 check_param.testflag|= T_SORT_INDEX;
649 if (argument == disabled_my_option)
650 check_param.testflag&= ~T_READONLY;
652 check_param.testflag|= T_READONLY;
655 if (argument == disabled_my_option)
656 check_param.testflag&= ~T_UPDATE_STATE;
658 check_param.testflag|= T_UPDATE_STATE;
661 if (argument == disabled_my_option)
667 DBUG_PUSH(argument ? argument :
"d:t:o,/tmp/myisamchk.trace");
673 case OPT_CORRECT_CHECKSUM:
674 if (argument == disabled_my_option)
675 check_param.testflag&= ~T_CALC_CHECKSUM;
677 check_param.testflag|= T_CALC_CHECKSUM;
679 case OPT_STATS_METHOD:
682 enum_mi_stats_method UNINIT_VAR(method_conv);
683 myisam_stats_method_str= argument;
684 if ((method= find_type(argument, &myisam_stats_method_typelib,
685 FIND_TYPE_BASIC)) <= 0)
687 fprintf(stderr,
"Invalid value of stats_method: %s.\n", argument);
692 method_conv= MI_STATS_METHOD_NULLS_EQUAL;
695 method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
698 method_conv= MI_STATS_METHOD_IGNORE_NULLS;
702 check_param.stats_method= method_conv;
706 case OPT_START_CHECK_POS:
707 check_param.start_check_pos= strtoull(argument, NULL, 0);
711 my_print_help(my_long_options);
721 static void get_options(
register int *argc,
register char ***argv)
725 if (load_defaults(
"my", load_default_groups, argc, argv))
729 if (isatty(fileno(stdout)))
730 check_param.testflag|=T_WRITE_LOOP;
732 if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
736 if ((check_param.testflag & T_UPDATE_STATE) &&
737 (check_param.testflag & T_REP_ANY))
738 check_param.testflag|= T_CALC_CHECKSUM;
746 if ((check_param.testflag & T_UNPACK) &&
747 (check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
749 (void) fprintf(stderr,
750 "%s: --unpack can't be used with --quick or --sort-records\n",
754 if ((check_param.testflag & T_READONLY) &&
755 (check_param.testflag &
756 (T_REP_ANY | T_STATISTICS | T_AUTO_INC |
757 T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
759 (void) fprintf(stderr,
760 "%s: Can't use --readonly when repairing or sorting\n",
765 if (init_tmpdir(&myisamchk_tmpdir, opt_tmpdir))
768 check_param.tmpdir=&myisamchk_tmpdir;
769 check_param.key_cache_block_size= opt_key_cache_block_size;
771 if (set_collation_name)
772 if (!(set_collation= get_charset_by_name(set_collation_name,
776 myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
783 static int myisamchk(
MI_CHECK *param,
char * filename)
785 int error,lock_type,recreate;
786 int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
789 char llbuff[22],llbuff2[22];
790 my_bool state_updated=0;
792 DBUG_ENTER(
"myisamchk");
794 param->out_flag=error=param->warning_printed=param->error_printed=
797 param->isam_file_name=filename;
798 if (!(info=mi_open(filename,
799 (param->testflag & (T_DESCRIPT | T_READONLY)) ?
802 ((param->testflag & T_WAIT_FOREVER) ?
803 HA_OPEN_WAIT_IF_LOCKED :
804 (param->testflag & T_DESCRIPT) ?
805 HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
808 param->error_printed=1;
811 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);
813 case HA_ERR_NOT_A_TABLE:
814 mi_check_print_error(param,
"'%s' is not a MyISAM-table",filename);
816 case HA_ERR_CRASHED_ON_USAGE:
817 mi_check_print_error(param,
"'%s' is marked as crashed",filename);
819 case HA_ERR_CRASHED_ON_REPAIR:
820 mi_check_print_error(param,
"'%s' is marked as crashed after last repair",filename);
822 case HA_ERR_OLD_FILE:
823 mi_check_print_error(param,
"'%s' is an old type of MyISAM-table", filename);
825 case HA_ERR_END_OF_FILE:
826 mi_check_print_error(param,
"Couldn't read complete header from '%s'", filename);
829 mi_check_print_error(param,
"'%s' is locked. Use -w to wait until unlocked",filename);
832 mi_check_print_error(param,
"File '%s' doesn't exist",filename);
835 mi_check_print_error(param,
"You don't have permission to use '%s'",filename);
838 mi_check_print_error(param,
"%d when opening MyISAM-table '%s'",
845 share->options&= ~HA_OPTION_READ_ONLY_DATA;
846 share->tot_locks-= share->r_locks;
854 if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
856 my_bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
858 if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
859 ((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
860 STATE_CRASHED_ON_REPAIR) ||
861 !(param->testflag & T_CHECK_ONLY_CHANGED))))
864 if (info->s->base.keys && info->state->records)
866 if ((param->testflag & T_STATISTICS) &&
867 (share->state.changed & STATE_NOT_ANALYZED))
869 if ((param->testflag & T_SORT_INDEX) &&
870 (share->state.changed & STATE_NOT_SORTED_PAGES))
872 if ((param->testflag & T_REP_BY_SORT) &&
873 (share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
876 if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
877 (share->state.changed & (STATE_CHANGED | STATE_CRASHED |
878 STATE_CRASHED_ON_REPAIR)))
882 if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
883 printf(
"MyISAM file: %s is already checked\n",filename);
886 mi_check_print_error(param,
"%d when closing MyISAM-table '%s'",
893 if ((param->testflag & (T_REP_ANY | T_STATISTICS |
894 T_SORT_RECORDS | T_SORT_INDEX)) &&
895 (((param->testflag & T_UNPACK) &&
896 share->data_file_type == COMPRESSED_RECORD) ||
897 mi_uint2korr(share->state.header.state_info_length) !=
898 MI_STATE_INFO_SIZE ||
899 mi_uint2korr(share->state.header.base_info_length) !=
901 mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
902 ~share->state.key_map) ||
903 test_if_almost_full(info) ||
904 info->s->state.header.file_version[3] != myisam_file_magic[3] ||
906 set_collation->number != share->state.header.language) ||
907 myisam_block_size != MI_KEY_BLOCK_LENGTH))
910 param->language= set_collation->number;
911 if (recreate_table(param, &info,filename))
913 (void) fprintf(stderr,
914 "MyISAM-table '%s' is not fixed because of errors\n",
919 if (!(param->testflag & T_REP_ANY))
921 param->testflag|=T_REP_BY_SORT;
922 if (!(param->testflag & T_SILENT))
923 printf(
"- '%s' has old table-format. Recreating index\n",filename);
927 share->tot_locks-= share->r_locks;
931 if (param->testflag & T_DESCRIPT)
933 param->total_files++;
934 param->total_records+=info->state->records;
935 param->total_deleted+=info->state->del;
936 descript(param, info, filename);
940 if (!stopwords_inited++)
943 if (!(param->testflag & T_READONLY))
947 if (info->lock_type == F_RDLCK)
948 info->lock_type=F_UNLCK;
949 if (_mi_readinfo(info,lock_type,0))
951 mi_check_print_error(param,
"Can't lock indexfile of '%s', error: %d",
953 param->error_printed=0;
961 mi_lock_database(info, F_EXTRA_LCK);
962 datafile=info->dfile;
964 if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
966 if (param->testflag & T_REP_ANY)
968 ulonglong tmp=share->state.key_map;
969 mi_copy_keys_active(share->state.key_map, share->base.keys,
971 if (tmp != share->state.key_map)
972 info->update|=HA_STATE_CHANGED;
974 if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
976 if (param->testflag & T_FORCE_CREATE)
979 mi_check_print_info(param,
"Creating new data file\n");
984 mi_check_print_error(param,
985 "Quick-recover aborted; Run recovery without switch 'q'");
990 if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
991 (mi_is_any_key_active(share->state.key_map) ||
992 (rep_quick && !param->keys_in_use && !recreate)) &&
993 mi_test_if_sort_rep(info, info->state->records,
994 info->s->state.key_map,
997 if (param->testflag & T_REP_BY_SORT)
998 error=mi_repair_by_sort(param,info,filename,rep_quick);
1000 error=mi_repair_parallel(param,info,filename,rep_quick);
1003 else if (param->testflag & T_REP_ANY)
1004 error=mi_repair(param, info,filename,rep_quick);
1006 if (!error && param->testflag & T_SORT_RECORDS)
1012 #ifndef TO_BE_REMOVED
1013 if (param->out_flag & O_NEW_DATA)
1015 (void) my_close(info->dfile,MYF(MY_WME));
1016 error|=change_to_newfile(filename, MI_NAME_DEXT, DATA_TMP_EXT, MYF(0));
1017 if (mi_open_datafile(info,info->s, NULL, -1))
1019 param->out_flag&= ~O_NEW_DATA;
1020 param->read_cache.file=info->dfile;
1030 my_bool update_index=1;
1031 for (key=0 ; key < share->base.keys; key++)
1032 if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY|HA_FULLTEXT))
1035 error=mi_sort_records(param,info,filename,param->opt_sort_key,
1037 (my_bool) !(param->testflag & T_REP),
1039 datafile=info->dfile;
1040 if (!error && !update_index)
1043 puts(
"Table had a compressed index; We must now recreate the index");
1044 error=mi_repair_by_sort(param,info,filename,1);
1048 if (!error && param->testflag & T_SORT_INDEX)
1049 error=mi_sort_index(param,info,filename);
1051 share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1052 STATE_CRASHED_ON_REPAIR);
1054 mi_mark_crashed(info);
1056 else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
1058 if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1059 printf(
"Checking MyISAM file: %s\n",filename);
1060 if (!(param->testflag & T_SILENT))
1061 printf(
"Data records: %7s Deleted blocks: %7s\n",
1062 llstr(info->state->records,llbuff),
1063 llstr(info->state->del,llbuff2));
1064 error =chk_status(param,info);
1065 mi_intersect_keys_active(share->state.key_map, param->keys_in_use);
1066 error =chk_size(param,info);
1067 if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1068 error|=chk_del(param, info,param->testflag);
1069 if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1070 !param->start_check_pos)))
1072 error|=chk_key(param, info);
1073 if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1074 error=update_state_info(param, info,
1075 ((param->testflag & T_STATISTICS) ?
1077 ((param->testflag & T_AUTO_INC) ?
1078 UPDATE_AUTO_INC : 0));
1080 if ((!rep_quick && !error) ||
1081 !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1083 if (param->testflag & (T_EXTEND | T_MEDIUM))
1084 (void) init_key_cache(dflt_key_cache,opt_key_cache_block_size,
1085 param->use_buffers, 0, 0);
1086 (void) init_io_cache(¶m->read_cache,datafile,
1087 (uint) param->read_buffer_length,
1089 (param->start_check_pos ?
1090 param->start_check_pos :
1091 share->pack.header_length),
1095 if ((info->s->options & (HA_OPTION_PACK_RECORD |
1096 HA_OPTION_COMPRESS_RECORD)) ||
1097 (param->testflag & (T_EXTEND | T_MEDIUM)))
1098 error|=chk_data_link(param, info, param->testflag & T_EXTEND);
1099 error|=flush_blocks(param, share->key_cache, share->kfile);
1100 (void) end_io_cache(¶m->read_cache);
1104 if ((share->state.changed & STATE_CHANGED) &&
1105 (param->testflag & T_UPDATE_STATE))
1106 info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1107 share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1108 STATE_CRASHED_ON_REPAIR);
1110 else if (!mi_is_crashed(info) &&
1111 (param->testflag & T_UPDATE_STATE))
1113 mi_mark_crashed(info);
1114 info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1118 if ((param->testflag & T_AUTO_INC) ||
1119 ((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1120 update_auto_increment_key(param, info,
1121 (my_bool) !
test(param->testflag & T_AUTO_INC));
1123 if (!(param->testflag & T_DESCRIPT))
1125 if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1126 error|=update_state_info(param, info,
1128 (((param->testflag & T_REP_ANY) ?
1130 (state_updated ? UPDATE_STAT : 0) |
1131 ((param->testflag & T_SORT_RECORDS) ?
1133 (void) lock_file(param, share->kfile,0L,F_UNLCK,
"indexfile",filename);
1134 info->update&= ~HA_STATE_CHANGED;
1136 mi_lock_database(info, F_UNLCK);
1140 mi_check_print_error(param,
"%d when closing MyISAM-table '%s'",my_errno,filename);
1145 if (param->out_flag & O_NEW_DATA)
1146 error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1147 ((param->testflag & T_BACKUP_DATA) ?
1148 MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1149 if (param->out_flag & O_NEW_INDEX)
1150 error|=change_to_newfile(filename, MI_NAME_IEXT, INDEX_TMP_EXT, MYF(0));
1152 (void) fflush(stdout); (void) fflush(stderr);
1153 if (param->error_printed)
1155 if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1157 (void) fprintf(stderr,
1158 "MyISAM-table '%s' is not fixed because of errors\n",
1160 if (param->testflag & T_REP_ANY)
1161 (void) fprintf(stderr,
1162 "Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n");
1164 else if (!(param->error_printed & 2) &&
1165 !(param->testflag & T_FORCE_CREATE))
1166 (void) fprintf(stderr,
1167 "MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
1170 else if (param->warning_printed &&
1171 ! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1173 (void) fprintf(stderr,
"MyISAM-table '%s' is usable but should be fixed\n",
1175 (void) fflush(stderr);
1184 uint key,keyseg_nr,field,start;
1187 reg4
const char *text;
1188 char buff[160],length[10],*pos,*end;
1189 enum en_fieldtype
type;
1191 char llbuff[22],llbuff2[22];
1192 DBUG_ENTER(
"describe");
1194 printf(
"\nMyISAM file: %s\n",name);
1195 fputs(
"Record format: ",stdout);
1196 if (share->options & HA_OPTION_COMPRESS_RECORD)
1198 else if (share->options & HA_OPTION_PACK_RECORD)
1201 puts(
"Fixed length");
1202 printf(
"Character set: %s (%d)\n",
1203 get_charset_name(share->state.header.language),
1204 share->state.header.language);
1206 if (param->testflag & T_VERBOSE)
1208 printf(
"File-version: %d\n",
1209 (
int) share->state.header.file_version[3]);
1210 if (share->state.create_time)
1212 get_date(buff,1,share->state.create_time);
1213 printf(
"Creation time: %s\n",buff);
1215 if (share->state.check_time)
1217 get_date(buff,1,share->state.check_time);
1218 printf(
"Recover time: %s\n",buff);
1221 if (share->state.changed & STATE_CRASHED)
1222 strmov(buff,
"crashed");
1225 if (share->state.open_count)
1226 pos=strmov(pos,
"open,");
1227 if (share->state.changed & STATE_CHANGED)
1228 pos=strmov(pos,
"changed,");
1230 pos=strmov(pos,
"checked,");
1231 if (!(share->state.changed & STATE_NOT_ANALYZED))
1232 pos=strmov(pos,
"analyzed,");
1233 if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1234 pos=strmov(pos,
"optimized keys,");
1235 if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1236 pos=strmov(pos,
"sorted index pages,");
1239 printf(
"Status: %s\n",buff);
1240 if (share->base.auto_key)
1242 printf(
"Auto increment key: %13d Last value: %13s\n",
1243 share->base.auto_key,
1244 llstr(share->state.auto_increment,llbuff));
1246 if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1247 printf(
"Checksum: %23s\n",llstr(info->state->checksum,llbuff));
1249 if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1250 printf(
"Keys are only flushed at close\n");
1253 printf(
"Data records: %13s Deleted blocks: %13s\n",
1254 llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1255 if (param->testflag & T_SILENT)
1258 if (param->testflag & T_VERBOSE)
1261 printf(
"Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
1263 printf(
"Datafile parts: %13s Deleted data: %13s\n",
1264 llstr(share->state.split,llbuff),
1265 llstr(info->state->empty,llbuff2));
1266 printf(
"Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
1267 share->rec_reflength,share->base.key_reflength);
1268 printf(
"Datafile length: %13s Keyfile length: %13s\n",
1269 llstr(info->state->data_file_length,llbuff),
1270 llstr(info->state->key_file_length,llbuff2));
1272 if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1273 puts(
"This is a one-record table");
1276 if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1277 share->base.max_key_file_length != HA_OFFSET_ERROR)
1278 printf(
"Max datafile length: %13s Max keyfile length: %13s\n",
1279 llstr(share->base.max_data_file_length-1,llbuff),
1280 ullstr(share->base.max_key_file_length - 1, llbuff2));
1284 printf(
"Recordlength: %13d\n",(
int) share->base.pack_reclength);
1285 if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1287 longlong2str(share->state.key_map,buff,2);
1288 printf(
"Using only keys '%s' of %d possibly keys\n",
1289 buff, share->base.keys);
1291 puts(
"\ntable description:");
1292 printf(
"Key Start Len Index Type");
1293 if (param->testflag & T_VERBOSE)
1294 printf(
" Rec/key Root Blocksize");
1295 (void) putchar(
'\n');
1297 for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1298 key < share->base.keys;
1301 keyseg=keyinfo->seg;
1302 if (keyinfo->flag & HA_NOSAME) text=
"unique ";
1303 else if (keyinfo->flag & HA_FULLTEXT) text=
"fulltext ";
1304 else text=
"multip.";
1307 if (keyseg->flag & HA_REVERSE_SORT)
1309 pos=strmov(pos,type_names[keyseg->type]);
1312 if (keyinfo->flag & HA_PACK_KEY)
1313 pos=strmov(pos,prefix_packed_txt);
1314 if (keyinfo->flag & HA_BINARY_PACK_KEY)
1315 pos=strmov(pos,bin_packed_txt);
1316 if (keyseg->flag & HA_SPACE_PACK)
1317 pos=strmov(pos,diff_txt);
1318 if (keyseg->flag & HA_BLOB_PART)
1319 pos=strmov(pos,blob_txt);
1320 if (keyseg->flag & HA_NULL_PART)
1321 pos=strmov(pos,null_txt);
1324 printf(
"%-4d%-6ld%-3d %-8s%-21s",
1325 key+1,(
long) keyseg->start+1,keyseg->length,text,buff);
1326 if (share->state.key_root[key] != HA_OFFSET_ERROR)
1327 llstr(share->state.key_root[key],buff);
1330 if (param->testflag & T_VERBOSE)
1331 printf(
"%11lu %12s %10d",
1332 share->state.rec_per_key_part[keyseg_nr++],
1333 buff,keyinfo->block_length);
1334 (void) putchar(
'\n');
1335 while ((++keyseg)->type != HA_KEYTYPE_END)
1338 if (keyseg->flag & HA_REVERSE_SORT)
1340 pos=strmov(pos,type_names[keyseg->type]);
1342 if (keyseg->flag & HA_SPACE_PACK)
1343 pos=strmov(pos,diff_txt);
1344 if (keyseg->flag & HA_BLOB_PART)
1345 pos=strmov(pos,blob_txt);
1346 if (keyseg->flag & HA_NULL_PART)
1347 pos=strmov(pos,null_txt);
1349 printf(
" %-6ld%-3d %-21s",
1350 (
long) keyseg->start+1,keyseg->length,buff);
1351 if (param->testflag & T_VERBOSE)
1352 printf(
"%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1353 (void) putchar(
'\n');
1357 if (share->state.header.uniques)
1360 puts(
"\nUnique Key Start Len Nullpos Nullbit Type");
1361 for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1362 key < share->state.header.uniques; key++, uniqueinfo++)
1365 char null_bit[8],null_pos[8];
1366 printf(
"%-8d%-5d",key+1,uniqueinfo->key+1);
1367 for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1371 null_bit[0]=null_pos[0]=0;
1372 if (keyseg->null_bit)
1374 sprintf(null_bit,
"%d",keyseg->null_bit);
1375 sprintf(null_pos,
"%ld",(
long) keyseg->null_pos+1);
1377 printf(
"%-7ld%-5d%-9s%-10s%-30s\n",
1378 (
long) keyseg->start+1,keyseg->length,
1380 type_names[keyseg->type]);
1385 if (param->verbose > 1)
1387 char null_bit[8],null_pos[8];
1388 printf(
"\nField Start Length Nullpos Nullbit Type");
1389 if (share->options & HA_OPTION_COMPRESS_RECORD)
1390 printf(
" Huff tree Bits");
1391 (void) putchar(
'\n');
1393 for (field=0 ; field < share->base.fields ; field++)
1395 if (share->options & HA_OPTION_COMPRESS_RECORD)
1396 type=share->rec[field].base_type;
1398 type=(
enum en_fieldtype) share->rec[field].type;
1399 end=strmov(buff,field_pack[type]);
1400 if (share->options & HA_OPTION_COMPRESS_RECORD)
1402 if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1403 end=strmov(end,
", not_always");
1404 if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1405 end=strmov(end,
", no empty");
1406 if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1408 sprintf(end,
", zerofill(%d)",share->rec[field].space_length_bits);
1413 strmov(buff,buff+2);
1414 int10_to_str((
long) share->rec[field].length,length,10);
1415 null_bit[0]=null_pos[0]=0;
1416 if (share->rec[field].null_bit)
1418 sprintf(null_bit,
"%d",share->rec[field].null_bit);
1419 sprintf(null_pos,
"%d",share->rec[field].null_pos+1);
1421 printf(
"%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1422 null_pos, null_bit, buff);
1423 if (share->options & HA_OPTION_COMPRESS_RECORD)
1425 if (share->rec[field].huff_tree)
1427 (uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1428 share->rec[field].huff_tree->quick_table_bits);
1430 (void) putchar(
'\n');
1431 start+=share->rec[field].length;
1440 static int mi_sort_records(
MI_CHECK *param,
1441 register MI_INFO *info,
char * name,
1444 my_bool update_index)
1451 ha_rows old_record_count;
1453 char llbuff[22],llbuff2[22];
1456 DBUG_ENTER(
"sort_records");
1458 memset(&sort_info, 0,
sizeof(sort_info));
1459 memset(&sort_param, 0,
sizeof(sort_param));
1460 sort_param.sort_info=&sort_info;
1461 sort_info.param=param;
1462 keyinfo= &share->keyinfo[sort_key];
1467 if (! mi_is_key_active(share->state.key_map, sort_key))
1469 mi_check_print_warning(param,
1470 "Can't sort table '%s' on key %d; No such key",
1472 param->error_printed=0;
1475 if (keyinfo->flag & HA_FULLTEXT)
1477 mi_check_print_warning(param,
"Can't sort table '%s' on FULLTEXT key %d",
1479 param->error_printed=0;
1482 if (share->data_file_type == COMPRESSED_RECORD)
1484 mi_check_print_warning(param,
"Can't sort read-only table '%s'", name);
1485 param->error_printed=0;
1488 if (!(param->testflag & T_SILENT))
1490 printf(
"- Sorting records for MyISAM-table '%s'\n",name);
1492 printf(
"Data records: %9s Deleted: %9s\n",
1493 llstr(info->state->records,llbuff),
1494 llstr(info->state->del,llbuff2));
1496 if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1499 init_key_cache(dflt_key_cache, opt_key_cache_block_size,
1500 (
size_t) param->use_buffers, 0, 0);
1501 if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1502 WRITE_CACHE,share->pack.header_length,1,
1503 MYF(MY_WME | MY_WAIT_IF_FULL)))
1505 info->opt_flag|=WRITE_CACHE_USED;
1507 if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
1509 mi_check_print_error(param,
"Not enough memory for key block");
1513 if (!mi_alloc_rec_buff(info, -1, &sort_param.record))
1515 mi_check_print_error(param,
"Not enough memory for record");
1518 fn_format(param->temp_filename,name,
"", MI_NAME_DEXT,2+4+32);
1519 new_file= my_create(fn_format(param->temp_filename,
1520 param->temp_filename,
"",
1522 0, param->tmpfile_createflag,
1526 mi_check_print_error(param,
"Can't create new tempfile: '%s'",
1527 param->temp_filename);
1530 if (share->pack.header_length)
1531 if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1534 info->rec_cache.file=new_file;
1537 for (key=0 ; key < share->base.keys ; key++)
1538 share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1540 if (my_pread(share->kfile,(uchar*) temp_buff,
1541 (uint) keyinfo->block_length,
1542 share->state.key_root[sort_key],
1543 MYF(MY_NABP+MY_WME)))
1545 mi_check_print_error(param,
"Can't read indexpage from filepos: %s",
1546 (ulong) share->state.key_root[sort_key]);
1551 sort_info.info=info;
1552 sort_info.new_data_file_type=share->data_file_type;
1553 sort_param.fix_datafile=1;
1554 sort_param.master=1;
1555 sort_param.filepos=share->pack.header_length;
1556 old_record_count=info->state->records;
1557 info->state->records=0;
1558 if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1559 info->state->checksum=0;
1561 if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1562 temp_buff, sort_key,new_file,update_index) ||
1563 write_data_suffix(&sort_info,1) ||
1564 flush_io_cache(&info->rec_cache))
1567 if (info->state->records != old_record_count)
1569 mi_check_print_error(param,
"found %s of %s records",
1570 llstr(info->state->records,llbuff),
1571 llstr(old_record_count,llbuff2));
1575 (void) my_close(info->dfile,MYF(MY_WME));
1576 param->out_flag|=O_NEW_DATA;
1577 info->dfile=new_file;
1579 info->state->empty=0;
1580 share->state.dellink= HA_OFFSET_ERROR;
1581 info->state->data_file_length=sort_param.filepos;
1582 share->state.split=info->state->records;
1583 share->state.version=(ulong) time((time_t*) 0);
1585 info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1587 if (param->testflag & T_WRITE_LOOP)
1589 (void) fputs(
" \r",stdout); (void) fflush(stdout);
1594 if (got_error && new_file >= 0)
1596 (void) end_io_cache(&info->rec_cache);
1597 (void) my_close(new_file,MYF(MY_WME));
1598 (void) my_delete(param->temp_filename, MYF(MY_WME));
1602 my_afree((uchar*) temp_buff);
1604 my_free(mi_get_rec_buff_ptr(info, sort_param.record));
1605 info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1606 (void) end_io_cache(&info->rec_cache);
1607 my_free(sort_info.buff);
1609 share->state.sortkey=sort_key;
1610 DBUG_RETURN(flush_blocks(param, share->key_cache, share->kfile) |
1619 my_off_t
page, uchar *buff, uint sort_key,
1620 File new_file,my_bool update_index)
1622 uint nod_flag,used_length,key_length;
1623 uchar *temp_buff,*keypos,*endpos;
1624 my_off_t next_page,rec_pos;
1625 uchar lastkey[MI_MAX_KEY_BUFF];
1627 SORT_INFO *sort_info= sort_param->sort_info;
1629 DBUG_ENTER(
"sort_record_index");
1631 nod_flag=mi_test_if_nod(buff);
1636 if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
1638 mi_check_print_error(param,
"Not Enough memory");
1642 used_length=mi_getint(buff);
1643 keypos=buff+2+nod_flag;
1644 endpos=buff+used_length;
1649 next_page=_mi_kpos(nod_flag,keypos);
1650 if (my_pread(info->s->kfile,(uchar*) temp_buff,
1651 (uint) keyinfo->block_length, next_page,
1652 MYF(MY_NABP+MY_WME)))
1654 mi_check_print_error(param,
"Can't read keys from filepos: %s",
1655 llstr(next_page,llbuff));
1658 if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1659 new_file, update_index))
1662 if (keypos >= endpos ||
1663 (key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1666 rec_pos= _mi_dpos(info,0,lastkey+key_length);
1668 if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1670 mi_check_print_error(param,
"%d when reading datafile",my_errno);
1673 if (rec_pos != sort_param->filepos && update_index)
1675 _mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1676 sort_param->filepos);
1677 if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1680 mi_check_print_error(param,
"%d when updating key-pointers",my_errno);
1684 if (sort_write_record(sort_param))
1688 memset(buff+used_length, 0, keyinfo->block_length-used_length);
1689 if (my_pwrite(info->s->kfile,(uchar*) buff,(uint) keyinfo->block_length,
1690 page,param->myf_rw))
1692 mi_check_print_error(param,
"%d when updating keyblock",my_errno);
1696 my_afree((uchar*) temp_buff);
1700 my_afree((uchar*) temp_buff);
1712 static int not_killed= 0;
1714 volatile int *killed_ptr(
MI_CHECK *param __attribute__((unused)))
1722 void mi_check_print_info(
MI_CHECK *param __attribute__((unused)),
1723 const char *
fmt,...)
1728 (void) vfprintf(stdout, fmt, args);
1729 (void) fputc(
'\n',stdout);
1735 void mi_check_print_warning(
MI_CHECK *param,
const char *fmt,...)
1738 DBUG_ENTER(
"mi_check_print_warning");
1741 if (!param->warning_printed && !param->error_printed)
1743 if (param->testflag & T_SILENT)
1744 fprintf(stderr,
"%s: MyISAM file %s\n",my_progname_short,
1745 param->isam_file_name);
1746 param->out_flag|= O_DATA_LOST;
1748 param->warning_printed=1;
1750 fprintf(stderr,
"%s: warning: ",my_progname_short);
1751 (void) vfprintf(stderr, fmt, args);
1752 (void) fputc(
'\n',stderr);
1760 void mi_check_print_error(
MI_CHECK *param,
const char *fmt,...)
1763 DBUG_ENTER(
"mi_check_print_error");
1764 DBUG_PRINT(
"enter",(
"format: %s",fmt));
1767 if (!param->warning_printed && !param->error_printed)
1769 if (param->testflag & T_SILENT)
1770 fprintf(stderr,
"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1771 param->out_flag|= O_DATA_LOST;
1773 param->error_printed|=1;
1775 fprintf(stderr,
"%s: error: ",my_progname_short);
1776 (void) vfprintf(stderr, fmt, args);
1777 (void) fputc(
'\n',stderr);
1783 #include "mi_extrafunc.h"