1
/* Copyright (C) 2000-2003 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
/* Describe, check and repair of MyISAM tables */
18
#include <drizzled/global.h>
20
#include <mystrings/m_ctype.h>
22
#include <mysys/my_getopt.h>
23
#include <mysys/my_bit.h>
25
#include <mystrings/m_string.h>
26
#ifdef HAVE_SYS_VADVICE_H
27
#include <sys/vadvise.h>
29
#ifdef HAVE_SYS_MMAN_H
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)
36
#include "myisamdef.h"
38
static uint32_t decode_bits;
39
static char **default_argv;
40
static const char *load_default_groups[]= { "myisamchk", 0 };
41
static const char *set_collation_name, *opt_tmpdir;
42
static const CHARSET_INFO *set_collation;
43
static long opt_myisam_block_size;
44
static long opt_key_cache_block_size;
45
static const char *my_progname_short;
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","int64_t","uint64_t","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, uint32_t sort_key,
75
bool write_info, bool update_index);
76
static int sort_record_index(MI_SORT_PARAM *sort_param, MI_INFO *info,
78
my_off_t page,unsigned char *buff,uint32_t sortkey,
79
File new_file, 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;
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
uint32_t 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;
120
if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
122
puts("\n---------\n");
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);
136
my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
139
return 0; /* No compiler warning */
144
OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
145
OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE,
146
OPT_KEY_CACHE_BLOCK_SIZE, OPT_MYISAM_BLOCK_SIZE,
147
OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
148
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS,
149
OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD
152
static struct my_option my_long_options[] =
155
"Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
156
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
157
{"block-search", 'b',
158
"No help available.",
159
0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
161
"Make a backup of the .MYD file as 'filename-time.BAK'.",
162
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
163
{"character-sets-dir", OPT_CHARSETS_DIR,
164
"Directory where character sets are.",
165
(char**) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
167
"Check table for errors.",
168
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
169
{"check-only-changed", 'C',
170
"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).",
171
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
172
{"correct-checksum", OPT_CORRECT_CHECKSUM,
173
"Correct checksum information for table.",
174
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
176
"Prints some information about table.",
177
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
178
{"data-file-length", 'D',
179
"Max length of data file (when recreating data-file when it's full).",
180
(char**) &check_param.max_data_file_length,
181
(char**) &check_param.max_data_file_length,
182
0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
183
{"extend-check", 'e',
184
"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.",
185
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
187
"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).",
188
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
190
"Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
191
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
193
"Display this help and exit.",
194
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
196
"Display this help and exit.",
197
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
199
"Print statistics information about table that is checked.",
200
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
202
"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.",
203
(char**) &check_param.keys_in_use,
204
(char**) &check_param.keys_in_use,
205
0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
206
{"max-record-length", OPT_MAX_RECORD_LENGTH,
207
"Skip rows bigger than this if myisamchk can't allocate memory to hold it",
208
(char**) &check_param.max_record_length,
209
(char**) &check_param.max_record_length,
210
0, GET_ULL, REQUIRED_ARG, INT64_MAX, 0, INT64_MAX, 0, 0, 0},
211
{"medium-check", 'm',
212
"Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
213
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
214
{"quick", 'q', "Faster repair by not modifying the data file.",
215
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
217
"Don't mark table as checked.",
218
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
220
"Can fix almost anything except unique keys that aren't unique.",
221
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
222
{"parallel-recover", 'p',
223
"Same as '-r' but creates all the keys in parallel.",
224
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
225
{"safe-recover", 'o',
226
"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.",
227
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
228
{"sort-recover", 'n',
229
"Force recovering with sorting even if the temporary file was very big.",
230
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
232
{"start-check-pos", OPT_START_CHECK_POS,
233
"No help available.",
234
0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
236
{"set-auto-increment", 'A',
237
"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.",
238
(char**) &check_param.auto_increment_value,
239
(char**) &check_param.auto_increment_value,
240
0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
241
{"set-collation", OPT_SET_COLLATION,
242
"Change the collation used by the index",
243
(char**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
244
{"set-variable", 'O',
245
"Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
246
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
248
"Only print errors. One can use two -s to make myisamchk very silent.",
249
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
251
"Sort index blocks. This speeds up 'read-next' in applications.",
252
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
253
{"sort-records", 'R',
254
"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!)",
255
(char**) &check_param.opt_sort_key,
256
(char**) &check_param.opt_sort_key,
257
0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
259
"Path for temporary files.",
260
(char**) &opt_tmpdir,
261
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
262
{"update-state", 'U',
263
"Mark tables as crashed if any errors were found.",
264
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
266
"Unpack file packed with myisampack.",
267
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
269
"Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
270
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
272
"Print version and exit.",
273
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
275
"Wait if table is locked.",
276
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
277
{ "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
278
(char**) &check_param.use_buffers, (char**) &check_param.use_buffers, 0,
279
GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
280
INT32_MAX, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
281
{ "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "",
282
(char**) &opt_key_cache_block_size,
283
(char**) &opt_key_cache_block_size, 0,
284
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
285
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
286
{ "myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "",
287
(char**) &opt_myisam_block_size, (char**) &opt_myisam_block_size, 0,
288
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
289
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
290
{ "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
291
(char**) &check_param.read_buffer_length,
292
(char**) &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
293
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
294
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
295
{ "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
296
(char**) &check_param.write_buffer_length,
297
(char**) &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
298
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
299
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
300
{ "sort_buffer_size", OPT_SORT_BUFFER_SIZE, "",
301
(char**) &check_param.sort_buffer_length,
302
(char**) &check_param.sort_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
303
(long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
304
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
305
{ "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
306
(char**) &check_param.sort_key_blocks,
307
(char**) &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
308
BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
309
{ "decode_bits", OPT_DECODE_BITS, "", (char**) &decode_bits,
310
(char**) &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
311
{"stats_method", OPT_STATS_METHOD,
312
"Specifies how index statistics collection code should treat NULLs. "
313
"Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
314
"\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
315
(char**) &myisam_stats_method_str, (char**) &myisam_stats_method_str, 0,
316
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
317
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
321
static void print_version(void)
323
printf("%s Ver 2.7 for %s at %s\n", my_progname, SYSTEM_TYPE,
328
static void usage(void)
331
puts("By Monty, for your professional use");
332
puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
333
puts("Description, check and repair of MyISAM tables.");
334
puts("Used without options all tables on the command will be checked for errors");
335
printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname_short);
336
printf("\nGlobal options:\n");
338
-?, --help Display this help and exit.\n\
339
-O, --set-variable var=option.\n\
340
Change the value of a variable. Please note that\n\
341
this option is deprecated; you can set variables\n\
342
directly with '--variable-name=value'.\n\
343
-t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
344
specified, separated by ");
345
#if defined( __WIN__)
346
printf("semicolon (;)");
350
printf(", they will be used\n\
351
in a round-robin fashion.\n\
352
-s, --silent Only print errors. One can use two -s to make\n\
353
myisamchk very silent.\n\
354
-v, --verbose Print more information. This can be used with\n\
355
--description and --check. Use many -v for more verbosity.\n\
356
-V, --version Print version and exit.\n\
357
-w, --wait Wait if table is locked.\n\n");
359
puts(" --start-check-pos=# Start reading file at given offset.\n");
362
puts("Check options (check is the default action for myisamchk):\n\
363
-c, --check Check table for errors.\n\
364
-e, --extend-check Check the table VERY throughly. Only use this in\n\
365
extreme cases as myisamchk should normally be able to\n\
366
find out if the table is ok even without this switch.\n\
367
-F, --fast Check only tables that haven't been closed properly.\n\
368
-C, --check-only-changed\n\
369
Check only tables that have changed since last check.\n\
370
-f, --force Restart with '-r' if there are any errors in the table.\n\
371
States will be updated as with '--update-state'.\n\
372
-i, --information Print statistics information about table that is checked.\n\
373
-m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
374
all errors. Should be good enough for most cases.\n\
375
-U --update-state Mark tables as crashed if you find any errors.\n\
376
-T, --read-only Don't mark table as checked.\n");
378
puts("Repair options (When using '-r' or '-o'):\n\
379
-B, --backup Make a backup of the .MYD file as 'filename-time.BAK'.\n\
380
--correct-checksum Correct checksum information for table.\n\
381
-D, --data-file-length=# Max length of data file (when recreating data\n\
382
file when it's full).\n\
383
-e, --extend-check Try to recover every possible row from the data file\n\
384
Normally this will also find a lot of garbage rows;\n\
385
Don't use this option if you are not totally desperate.\n\
386
-f, --force Overwrite old temporary files.\n\
387
-k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\
388
bit mask of which keys to use. This can be used to\n\
389
get faster inserts.\n\
390
--max-record-length=#\n\
391
Skip rows bigger than this if myisamchk can't allocate\n\
392
memory to hold it.\n\
393
-r, --recover Can fix almost anything except unique keys that aren't\n\
395
-n, --sort-recover Forces recovering with sorting even if the temporary\n\
396
file would be very big.\n\
397
-p, --parallel-recover\n\
398
Uses the same technique as '-r' and '-n', but creates\n\
399
all the keys in parallel, in different threads.\n\
400
-o, --safe-recover Uses old recovery method; Slower than '-r' but can\n\
401
handle a couple of cases where '-r' reports that it\n\
402
can't fix the data file.\n\
403
--character-sets-dir=...\n\
404
Directory where character sets are.\n\
405
--set-collation=name\n\
406
Change the collation used by the index.\n\
407
-q, --quick Faster repair by not modifying the data file.\n\
408
One can give a second '-q' to force myisamchk to\n\
409
modify the original datafile in case of duplicate keys.\n\
410
NOTE: Tables where the data file is currupted can't be\n\
411
fixed with this option.\n\
412
-u, --unpack Unpack file packed with myisampack.\n\
415
puts("Other actions:\n\
416
-a, --analyze Analyze distribution of keys. Will make some joins in\n\
417
MySQL faster. You can check the calculated distribution\n\
418
by using '--description --verbose table_name'.\n\
419
--stats_method=name Specifies how index statistics collection code should\n\
420
treat NULLs. Possible values of name are \"nulls_unequal\"\n\
421
(default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
422
\"nulls_ignored\".\n\
423
-d, --description Prints some information about table.\n\
424
-A, --set-auto-increment[=value]\n\
425
Force auto_increment to start at this or higher value\n\
426
If no value is given, then sets the next auto_increment\n\
427
value to the highest used value for the auto key + 1.\n\
428
-S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
430
-R, --sort-records=#\n\
431
Sort records according to an index. This makes your\n\
432
data much more localized and may speed up things\n\
433
(It may be VERY slow to do a sort the first time!).\n\
434
-b, --block-search=#\n\
435
Find a record, a block at given offset belongs to.");
437
print_defaults("my", load_default_groups);
438
my_print_variables(my_long_options);
441
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
442
"nulls_ignored", NULL};
443
TYPELIB myisam_stats_method_typelib= {
444
array_elements(myisam_stats_method_names) - 1, "",
445
myisam_stats_method_names, NULL};
450
get_one_option(int optid,
451
const struct my_option *opt __attribute__((unused)),
456
if (argument == disabled_my_option)
457
check_param.testflag&= ~T_STATISTICS;
459
check_param.testflag|= T_STATISTICS;
463
check_param.auto_increment_value= strtoull(argument, NULL, 0);
465
check_param.auto_increment_value= 0; /* Set to max used value */
466
check_param.testflag|= T_AUTO_INC;
469
check_param.search_after_block= strtoul(argument, NULL, 10);
472
if (argument == disabled_my_option)
473
check_param.testflag&= ~T_BACKUP_DATA;
475
check_param.testflag|= T_BACKUP_DATA;
478
if (argument == disabled_my_option)
479
check_param.testflag&= ~T_CHECK;
481
check_param.testflag|= T_CHECK;
484
if (argument == disabled_my_option)
485
check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
487
check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
490
check_param.max_data_file_length=strtoll(argument, NULL, 10);
492
case 's': /* silent */
493
if (argument == disabled_my_option)
494
check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
497
if (check_param.testflag & T_SILENT)
498
check_param.testflag|= T_VERY_SILENT;
499
check_param.testflag|= T_SILENT;
500
check_param.testflag&= ~T_WRITE_LOOP;
504
if (argument == disabled_my_option)
505
check_param.testflag&= ~T_WAIT_FOREVER;
507
check_param.testflag|= T_WAIT_FOREVER;
509
case 'd': /* description if isam-file */
510
if (argument == disabled_my_option)
511
check_param.testflag&= ~T_DESCRIPT;
513
check_param.testflag|= T_DESCRIPT;
515
case 'e': /* extend check */
516
if (argument == disabled_my_option)
517
check_param.testflag&= ~T_EXTEND;
519
check_param.testflag|= T_EXTEND;
522
if (argument == disabled_my_option)
523
check_param.testflag&= ~T_INFO;
525
check_param.testflag|= T_INFO;
528
if (argument == disabled_my_option)
530
check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
531
check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
535
check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
536
check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
540
if (argument == disabled_my_option)
541
check_param.testflag&= ~T_FAST;
543
check_param.testflag|= T_FAST;
546
check_param.keys_in_use= (uint64_t) strtoll(argument, NULL, 10);
549
if (argument == disabled_my_option)
550
check_param.testflag&= ~T_MEDIUM;
552
check_param.testflag|= T_MEDIUM; /* Medium check */
554
case 'r': /* Repair table */
555
check_param.testflag&= ~T_REP_ANY;
556
if (argument != disabled_my_option)
557
check_param.testflag|= T_REP_BY_SORT;
560
check_param.testflag&= ~T_REP_ANY;
561
if (argument != disabled_my_option)
562
check_param.testflag|= T_REP_PARALLEL;
565
check_param.testflag&= ~T_REP_ANY;
566
check_param.force_sort= 0;
567
if (argument != disabled_my_option)
569
check_param.testflag|= T_REP;
570
my_disable_async_io= 1; /* More safety */
574
check_param.testflag&= ~T_REP_ANY;
575
if (argument == disabled_my_option)
576
check_param.force_sort= 0;
579
check_param.testflag|= T_REP_BY_SORT;
580
check_param.force_sort= 1;
584
if (argument == disabled_my_option)
585
check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
587
check_param.testflag|=
588
(check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
591
if (argument == disabled_my_option)
592
check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
594
check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
596
case 'v': /* Verbose */
597
if (argument == disabled_my_option)
599
check_param.testflag&= ~T_VERBOSE;
600
check_param.verbose=0;
604
check_param.testflag|= T_VERBOSE;
605
check_param.verbose++;
608
case 'R': /* Sort records */
609
if (argument == disabled_my_option)
610
check_param.testflag&= ~T_SORT_RECORDS;
613
check_param.testflag|= T_SORT_RECORDS;
614
check_param.opt_sort_key= (uint) atoi(argument) - 1;
615
if (check_param.opt_sort_key >= MI_MAX_KEY)
618
"The value of the sort key is bigger than max key: %d.\n",
624
case 'S': /* Sort index */
625
if (argument == disabled_my_option)
626
check_param.testflag&= ~T_SORT_INDEX;
628
check_param.testflag|= T_SORT_INDEX;
631
if (argument == disabled_my_option)
632
check_param.testflag&= ~T_READONLY;
634
check_param.testflag|= T_READONLY;
637
if (argument == disabled_my_option)
638
check_param.testflag&= ~T_UPDATE_STATE;
640
check_param.testflag|= T_UPDATE_STATE;
645
case OPT_CORRECT_CHECKSUM:
646
if (argument == disabled_my_option)
647
check_param.testflag&= ~T_CALC_CHECKSUM;
649
check_param.testflag|= T_CALC_CHECKSUM;
651
case OPT_STATS_METHOD:
654
enum_mi_stats_method method_conv;
655
myisam_stats_method_str= argument;
656
if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
658
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
663
method_conv= MI_STATS_METHOD_NULLS_EQUAL;
666
method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
669
method_conv= MI_STATS_METHOD_IGNORE_NULLS;
671
default: assert(0); /* Impossible */
673
check_param.stats_method= method_conv;
676
#ifdef DEBUG /* Only useful if debugging */
677
case OPT_START_CHECK_POS:
678
check_param.start_check_pos= strtoull(argument, NULL, 0);
682
my_print_help(my_long_options);
692
static void get_options(register int *argc,register char ***argv)
696
load_defaults("my", load_default_groups, argc, argv);
698
if (isatty(fileno(stdout)))
699
check_param.testflag|=T_WRITE_LOOP;
701
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
704
/* If using repair, then update checksum if one uses --update-state */
705
if ((check_param.testflag & T_UPDATE_STATE) &&
706
(check_param.testflag & T_REP_ANY))
707
check_param.testflag|= T_CALC_CHECKSUM;
715
if ((check_param.testflag & T_UNPACK) &&
716
(check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
719
"%s: --unpack can't be used with --quick or --sort-records\n",
723
if ((check_param.testflag & T_READONLY) &&
724
(check_param.testflag &
725
(T_REP_ANY | T_STATISTICS | T_AUTO_INC |
726
T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
729
"%s: Can't use --readonly when repairing or sorting\n",
734
if (init_tmpdir(&myisamchk_tmpdir, opt_tmpdir))
737
check_param.tmpdir=&myisamchk_tmpdir;
738
check_param.key_cache_block_size= opt_key_cache_block_size;
740
if (set_collation_name)
741
if (!(set_collation= get_charset_by_name(set_collation_name,
745
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
752
static int myisamchk(MI_CHECK *param, char * filename)
754
int error,lock_type,recreate;
755
int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
756
uint32_t raid_chunks;
759
char llbuff[22],llbuff2[22];
760
bool state_updated=0;
763
param->out_flag=error=param->warning_printed=param->error_printed=
766
param->isam_file_name=filename; /* For error messages */
767
if (!(info=mi_open(filename,
768
(param->testflag & (T_DESCRIPT | T_READONLY)) ?
771
((param->testflag & T_WAIT_FOREVER) ?
772
HA_OPEN_WAIT_IF_LOCKED :
773
(param->testflag & T_DESCRIPT) ?
774
HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
776
/* Avoid twice printing of isam file name */
777
param->error_printed=1;
780
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);
782
case HA_ERR_NOT_A_TABLE:
783
mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
785
case HA_ERR_CRASHED_ON_USAGE:
786
mi_check_print_error(param,"'%s' is marked as crashed",filename);
788
case HA_ERR_CRASHED_ON_REPAIR:
789
mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
791
case HA_ERR_OLD_FILE:
792
mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
794
case HA_ERR_END_OF_FILE:
795
mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
798
mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
801
mi_check_print_error(param,"File '%s' doesn't exist",filename);
804
mi_check_print_error(param,"You don't have permission to use '%s'",filename);
807
mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
814
share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
815
share->tot_locks-= share->r_locks;
817
raid_chunks=share->base.raid_chunks;
820
Skip the checking of the file if:
821
We are using --fast and the table is closed properly
822
We are using --check-only-changed-tables and the table hasn't changed
824
if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
826
bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
828
if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
829
((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
830
STATE_CRASHED_ON_REPAIR) ||
831
!(param->testflag & T_CHECK_ONLY_CHANGED))))
834
if (info->s->base.keys && info->state->records)
836
if ((param->testflag & T_STATISTICS) &&
837
(share->state.changed & STATE_NOT_ANALYZED))
839
if ((param->testflag & T_SORT_INDEX) &&
840
(share->state.changed & STATE_NOT_SORTED_PAGES))
842
if ((param->testflag & T_REP_BY_SORT) &&
843
(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
846
if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
847
(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
848
STATE_CRASHED_ON_REPAIR)))
852
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
853
printf("MyISAM file: %s is already checked\n",filename);
856
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
863
if ((param->testflag & (T_REP_ANY | T_STATISTICS |
864
T_SORT_RECORDS | T_SORT_INDEX)) &&
865
(((param->testflag & T_UNPACK) &&
866
share->data_file_type == COMPRESSED_RECORD) ||
867
mi_uint2korr(share->state.header.state_info_length) !=
868
MI_STATE_INFO_SIZE ||
869
mi_uint2korr(share->state.header.base_info_length) !=
871
mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
872
~share->state.key_map) ||
873
test_if_almost_full(info) ||
874
info->s->state.header.file_version[3] != myisam_file_magic[3] ||
876
set_collation->number != share->state.header.language) ||
877
myisam_block_size != MI_KEY_BLOCK_LENGTH))
880
param->language= set_collation->number;
881
if (recreate_table(param, &info,filename))
884
"MyISAM-table '%s' is not fixed because of errors\n",
889
if (!(param->testflag & T_REP_ANY))
891
param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
892
if (!(param->testflag & T_SILENT))
893
printf("- '%s' has old table-format. Recreating index\n",filename);
897
share->tot_locks-= share->r_locks;
901
if (param->testflag & T_DESCRIPT)
903
param->total_files++;
904
param->total_records+=info->state->records;
905
param->total_deleted+=info->state->del;
906
descript(param, info, filename);
911
if (!(param->testflag & T_READONLY))
912
lock_type = F_WRLCK; /* table is changed */
915
if (info->lock_type == F_RDLCK)
916
info->lock_type=F_UNLCK; /* Read only table */
917
if (_mi_readinfo(info,lock_type,0))
919
mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
921
param->error_printed=0;
925
_mi_readinfo() has locked the table.
926
We mark the table as locked (without doing file locks) to be able to
927
use functions that only works on locked tables (like row caching).
929
mi_lock_database(info, F_EXTRA_LCK);
930
datafile=info->dfile;
932
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
934
if (param->testflag & T_REP_ANY)
936
uint64_t tmp=share->state.key_map;
937
mi_copy_keys_active(share->state.key_map, share->base.keys,
939
if (tmp != share->state.key_map)
940
info->update|=HA_STATE_CHANGED;
942
if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
944
if (param->testflag & T_FORCE_CREATE)
947
mi_check_print_info(param,"Creating new data file\n");
952
mi_check_print_error(param,
953
"Quick-recover aborted; Run recovery without switch 'q'");
958
if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
959
(mi_is_any_key_active(share->state.key_map) ||
960
(rep_quick && !param->keys_in_use && !recreate)) &&
961
mi_test_if_sort_rep(info, info->state->records,
962
info->s->state.key_map,
965
if (param->testflag & T_REP_BY_SORT)
966
error=mi_repair_by_sort(param,info,filename,rep_quick);
968
error=mi_repair_parallel(param,info,filename,rep_quick);
971
else if (param->testflag & T_REP_ANY)
972
error=mi_repair(param, info,filename,rep_quick);
974
if (!error && param->testflag & T_SORT_RECORDS)
978
We can't update the index in mi_sort_records if we have a
979
prefix compressed or fulltext index
982
for (key=0 ; key < share->base.keys; key++)
983
if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY))
986
error=mi_sort_records(param,info,filename,param->opt_sort_key,
987
/* what is the following parameter for ? */
988
(bool) !(param->testflag & T_REP),
990
datafile=info->dfile; /* This is now locked */
991
if (!error && !update_index)
994
puts("Table had a compressed index; We must now recreate the index");
995
error=mi_repair_by_sort(param,info,filename,1);
998
if (!error && param->testflag & T_SORT_INDEX)
999
error=mi_sort_index(param,info,filename);
1001
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1002
STATE_CRASHED_ON_REPAIR);
1004
mi_mark_crashed(info);
1006
else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
1008
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1009
printf("Checking MyISAM file: %s\n",filename);
1010
if (!(param->testflag & T_SILENT))
1011
printf("Data records: %7s Deleted blocks: %7s\n",
1012
llstr(info->state->records,llbuff),
1013
llstr(info->state->del,llbuff2));
1014
error =chk_status(param,info);
1015
mi_intersect_keys_active(share->state.key_map, param->keys_in_use);
1016
error =chk_size(param,info);
1017
if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1018
error|=chk_del(param, info,param->testflag);
1019
if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1020
!param->start_check_pos)))
1022
error|=chk_key(param, info);
1023
if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1024
error=update_state_info(param, info,
1025
((param->testflag & T_STATISTICS) ?
1027
((param->testflag & T_AUTO_INC) ?
1028
UPDATE_AUTO_INC : 0));
1030
if ((!rep_quick && !error) ||
1031
!(param->testflag & (T_FAST | T_FORCE_CREATE)))
1033
if (param->testflag & (T_EXTEND | T_MEDIUM))
1034
init_key_cache(dflt_key_cache,opt_key_cache_block_size,
1035
param->use_buffers, 0, 0);
1036
init_io_cache(¶m->read_cache,datafile,
1037
(uint) param->read_buffer_length,
1039
(param->start_check_pos ?
1040
param->start_check_pos :
1041
share->pack.header_length),
1045
if ((info->s->options & (HA_OPTION_PACK_RECORD |
1046
HA_OPTION_COMPRESS_RECORD)) ||
1047
(param->testflag & (T_EXTEND | T_MEDIUM)))
1048
error|=chk_data_link(param, info, param->testflag & T_EXTEND);
1049
error|=flush_blocks(param, share->key_cache, share->kfile);
1050
end_io_cache(¶m->read_cache);
1054
if ((share->state.changed & STATE_CHANGED) &&
1055
(param->testflag & T_UPDATE_STATE))
1056
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1057
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1058
STATE_CRASHED_ON_REPAIR);
1060
else if (!mi_is_crashed(info) &&
1061
(param->testflag & T_UPDATE_STATE))
1062
{ /* Mark crashed */
1063
mi_mark_crashed(info);
1064
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1068
if ((param->testflag & T_AUTO_INC) ||
1069
((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1070
update_auto_increment_key(param, info,
1071
(bool) !test(param->testflag & T_AUTO_INC));
1073
if (!(param->testflag & T_DESCRIPT))
1075
if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1076
error|=update_state_info(param, info,
1078
(((param->testflag & T_REP_ANY) ?
1080
(state_updated ? UPDATE_STAT : 0) |
1081
((param->testflag & T_SORT_RECORDS) ?
1083
info->update&= ~HA_STATE_CHANGED;
1085
mi_lock_database(info, F_UNLCK);
1089
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
1094
if (param->out_flag & O_NEW_DATA)
1095
error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1097
((param->testflag & T_BACKUP_DATA) ?
1098
MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1099
if (param->out_flag & O_NEW_INDEX)
1100
error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1103
fflush(stdout); fflush(stderr);
1104
if (param->error_printed)
1106
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1109
"MyISAM-table '%s' is not fixed because of errors\n",
1111
if (param->testflag & T_REP_ANY)
1113
"Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n");
1115
else if (!(param->error_printed & 2) &&
1116
!(param->testflag & T_FORCE_CREATE))
1118
"MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
1121
else if (param->warning_printed &&
1122
! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1124
fprintf(stderr, "MyISAM-table '%s' is usable but should be fixed\n",
1131
/* Write info about table */
1133
static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
1135
uint32_t key,keyseg_nr,field,start;
1136
register MI_KEYDEF *keyinfo;
1137
register HA_KEYSEG *keyseg;
1138
register const char *text;
1139
char buff[160],length[10],*pos,*end;
1140
enum en_fieldtype type;
1141
MYISAM_SHARE *share=info->s;
1142
char llbuff[22],llbuff2[22];
1144
printf("\nMyISAM file: %s\n",name);
1145
fputs("Record format: ",stdout);
1146
if (share->options & HA_OPTION_COMPRESS_RECORD)
1148
else if (share->options & HA_OPTION_PACK_RECORD)
1151
puts("Fixed length");
1152
printf("Character set: %s (%d)\n",
1153
get_charset_name(share->state.header.language),
1154
share->state.header.language);
1156
if (param->testflag & T_VERBOSE)
1158
printf("File-version: %d\n",
1159
(int) share->state.header.file_version[3]);
1160
if (share->state.create_time)
1162
get_date(buff,1,share->state.create_time);
1163
printf("Creation time: %s\n",buff);
1165
if (share->state.check_time)
1167
get_date(buff,1,share->state.check_time);
1168
printf("Recover time: %s\n",buff);
1171
if (share->state.changed & STATE_CRASHED)
1172
my_stpcpy(buff,"crashed");
1175
if (share->state.open_count)
1176
pos=my_stpcpy(pos,"open,");
1177
if (share->state.changed & STATE_CHANGED)
1178
pos=my_stpcpy(pos,"changed,");
1180
pos=my_stpcpy(pos,"checked,");
1181
if (!(share->state.changed & STATE_NOT_ANALYZED))
1182
pos=my_stpcpy(pos,"analyzed,");
1183
if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1184
pos=my_stpcpy(pos,"optimized keys,");
1185
if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1186
pos=my_stpcpy(pos,"sorted index pages,");
1187
pos[-1]=0; /* Remove extra ',' */
1189
printf("Status: %s\n",buff);
1190
if (share->base.auto_key)
1192
printf("Auto increment key: %13d Last value: %13s\n",
1193
share->base.auto_key,
1194
llstr(share->state.auto_increment,llbuff));
1196
if (share->base.raid_type)
1198
printf("RAID: Type: %u Chunks: %u Chunksize: %lu\n",
1199
share->base.raid_type,
1200
share->base.raid_chunks,
1201
share->base.raid_chunksize);
1203
if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1204
printf("Checksum: %23s\n",llstr(info->state->checksum,llbuff));
1206
if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1207
printf("Keys are only flushed at close\n");
1210
printf("Data records: %13s Deleted blocks: %13s\n",
1211
llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1212
if (param->testflag & T_SILENT)
1213
return; /* This is enough */
1215
if (param->testflag & T_VERBOSE)
1218
printf("Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
1220
printf("Datafile parts: %13s Deleted data: %13s\n",
1221
llstr(share->state.split,llbuff),
1222
llstr(info->state->empty,llbuff2));
1223
printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
1224
share->rec_reflength,share->base.key_reflength);
1225
printf("Datafile length: %13s Keyfile length: %13s\n",
1226
llstr(info->state->data_file_length,llbuff),
1227
llstr(info->state->key_file_length,llbuff2));
1229
if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1230
puts("This is a one-record table");
1233
if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1234
share->base.max_key_file_length != HA_OFFSET_ERROR)
1235
printf("Max datafile length: %13s Max keyfile length: %13s\n",
1236
llstr(share->base.max_data_file_length-1,llbuff),
1237
llstr(share->base.max_key_file_length-1,llbuff2));
1241
printf("Recordlength: %13d\n",(int) share->base.pack_reclength);
1242
if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1244
int64_t2str(share->state.key_map,buff,2);
1245
printf("Using only keys '%s' of %d possibly keys\n",
1246
buff, share->base.keys);
1248
puts("\ntable description:");
1249
printf("Key Start Len Index Type");
1250
if (param->testflag & T_VERBOSE)
1251
printf(" Rec/key Root Blocksize");
1254
for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1255
key < share->base.keys;
1258
keyseg=keyinfo->seg;
1259
if (keyinfo->flag & HA_NOSAME) text="unique ";
1260
else text="multip.";
1263
if (keyseg->flag & HA_REVERSE_SORT)
1265
pos=my_stpcpy(pos,type_names[keyseg->type]);
1268
if (keyinfo->flag & HA_PACK_KEY)
1269
pos=my_stpcpy(pos,prefix_packed_txt);
1270
if (keyinfo->flag & HA_BINARY_PACK_KEY)
1271
pos=my_stpcpy(pos,bin_packed_txt);
1272
if (keyseg->flag & HA_SPACE_PACK)
1273
pos=my_stpcpy(pos,diff_txt);
1274
if (keyseg->flag & HA_BLOB_PART)
1275
pos=my_stpcpy(pos,blob_txt);
1276
if (keyseg->flag & HA_NULL_PART)
1277
pos=my_stpcpy(pos,null_txt);
1280
printf("%-4d%-6ld%-3d %-8s%-21s",
1281
key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1282
if (share->state.key_root[key] != HA_OFFSET_ERROR)
1283
llstr(share->state.key_root[key],buff);
1286
if (param->testflag & T_VERBOSE)
1287
printf("%11lu %12s %10d",
1288
share->state.rec_per_key_part[keyseg_nr++],
1289
buff,keyinfo->block_length);
1291
while ((++keyseg)->type != HA_KEYTYPE_END)
1294
if (keyseg->flag & HA_REVERSE_SORT)
1296
pos=my_stpcpy(pos,type_names[keyseg->type]);
1298
if (keyseg->flag & HA_SPACE_PACK)
1299
pos=my_stpcpy(pos,diff_txt);
1300
if (keyseg->flag & HA_BLOB_PART)
1301
pos=my_stpcpy(pos,blob_txt);
1302
if (keyseg->flag & HA_NULL_PART)
1303
pos=my_stpcpy(pos,null_txt);
1305
printf(" %-6ld%-3d %-21s",
1306
(long) keyseg->start+1,keyseg->length,buff);
1307
if (param->testflag & T_VERBOSE)
1308
printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1313
if (share->state.header.uniques)
1315
MI_UNIQUEDEF *uniqueinfo;
1316
puts("\nUnique Key Start Len Nullpos Nullbit Type");
1317
for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1318
key < share->state.header.uniques; key++, uniqueinfo++)
1321
char null_bit[8],null_pos[8];
1322
printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1323
for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1327
null_bit[0]=null_pos[0]=0;
1328
if (keyseg->null_bit)
1330
sprintf(null_bit,"%d",keyseg->null_bit);
1331
sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1333
printf("%-7ld%-5d%-9s%-10s%-30s\n",
1334
(long) keyseg->start+1,keyseg->length,
1336
type_names[keyseg->type]);
1341
if (param->verbose > 1)
1343
char null_bit[8],null_pos[8];
1344
printf("\nField Start Length Nullpos Nullbit Type");
1345
if (share->options & HA_OPTION_COMPRESS_RECORD)
1346
printf(" Huff tree Bits");
1349
for (field=0 ; field < share->base.fields ; field++)
1351
if (share->options & HA_OPTION_COMPRESS_RECORD)
1352
type=share->rec[field].base_type;
1354
type=(enum en_fieldtype) share->rec[field].type;
1355
end=my_stpcpy(buff,field_pack[type]);
1356
if (share->options & HA_OPTION_COMPRESS_RECORD)
1358
if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1359
end=my_stpcpy(end,", not_always");
1360
if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1361
end=my_stpcpy(end,", no empty");
1362
if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1364
sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
1365
end= strchr(end, '\0');
1369
my_stpcpy(buff,buff+2);
1370
int10_to_str((long) share->rec[field].length,length,10);
1371
null_bit[0]=null_pos[0]=0;
1372
if (share->rec[field].null_bit)
1374
sprintf(null_bit,"%d",share->rec[field].null_bit);
1375
sprintf(null_pos,"%d",share->rec[field].null_pos+1);
1377
printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1378
null_pos, null_bit, buff);
1379
if (share->options & HA_OPTION_COMPRESS_RECORD)
1381
if (share->rec[field].huff_tree)
1383
(uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1384
share->rec[field].huff_tree->quick_table_bits);
1387
start+=share->rec[field].length;
1394
/* Sort records according to one key */
1396
static int mi_sort_records(MI_CHECK *param,
1397
register MI_INFO *info, char * name,
1406
unsigned char *temp_buff;
1407
ha_rows old_record_count;
1408
MYISAM_SHARE *share=info->s;
1409
char llbuff[22],llbuff2[22];
1410
SORT_INFO sort_info;
1411
MI_SORT_PARAM sort_param;
1413
memset(&sort_info, 0, sizeof(sort_info));
1414
memset(&sort_param, 0, sizeof(sort_param));
1415
sort_param.sort_info=&sort_info;
1416
sort_info.param=param;
1417
keyinfo= &share->keyinfo[sort_key];
1422
if (! mi_is_key_active(share->state.key_map, sort_key))
1424
mi_check_print_warning(param,
1425
"Can't sort table '%s' on key %d; No such key",
1427
param->error_printed=0;
1428
return(0); /* Nothing to do */
1430
if (share->data_file_type == COMPRESSED_RECORD)
1432
mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
1433
param->error_printed=0;
1434
return(0); /* Nothing to do */
1436
if (!(param->testflag & T_SILENT))
1438
printf("- Sorting records for MyISAM-table '%s'\n",name);
1440
printf("Data records: %9s Deleted: %9s\n",
1441
llstr(info->state->records,llbuff),
1442
llstr(info->state->del,llbuff2));
1444
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1445
return(0); /* Nothing to do */
1447
init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers,
1449
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1450
WRITE_CACHE,share->pack.header_length,1,
1451
MYF(MY_WME | MY_WAIT_IF_FULL)))
1453
info->opt_flag|=WRITE_CACHE_USED;
1455
if (!(temp_buff=(unsigned char*) my_alloca((uint) keyinfo->block_length)))
1457
mi_check_print_error(param,"Not enough memory for key block");
1461
if (!mi_alloc_rec_buff(info, -1, &sort_param.record))
1463
mi_check_print_error(param,"Not enough memory for record");
1466
fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
1467
new_file=my_raid_create(fn_format(param->temp_filename,
1468
param->temp_filename,"",
1470
0,param->tmpfile_createflag,
1471
share->base.raid_type,
1472
share->base.raid_chunks,
1473
share->base.raid_chunksize,
1477
mi_check_print_error(param,"Can't create new tempfile: '%s'",
1478
param->temp_filename);
1481
if (share->pack.header_length)
1482
if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1485
info->rec_cache.file=new_file; /* Use this file for cacheing*/
1488
for (key=0 ; key < share->base.keys ; key++)
1489
share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1491
if (my_pread(share->kfile,(unsigned char*) temp_buff,
1492
(uint) keyinfo->block_length,
1493
share->state.key_root[sort_key],
1494
MYF(MY_NABP+MY_WME)))
1496
mi_check_print_error(param,"Can't read indexpage from filepos: %s",
1497
(ulong) share->state.key_root[sort_key]);
1501
/* Setup param for sort_write_record */
1502
sort_info.info=info;
1503
sort_info.new_data_file_type=share->data_file_type;
1504
sort_param.fix_datafile=1;
1505
sort_param.master=1;
1506
sort_param.filepos=share->pack.header_length;
1507
old_record_count=info->state->records;
1508
info->state->records=0;
1509
if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1510
info->state->checksum=0;
1512
if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1513
temp_buff, sort_key,new_file,update_index) ||
1514
write_data_suffix(&sort_info,1) ||
1515
flush_io_cache(&info->rec_cache))
1518
if (info->state->records != old_record_count)
1520
mi_check_print_error(param,"found %s of %s records",
1521
llstr(info->state->records,llbuff),
1522
llstr(old_record_count,llbuff2));
1526
my_close(info->dfile,MYF(MY_WME));
1527
param->out_flag|=O_NEW_DATA; /* Data in new file */
1528
info->dfile=new_file; /* Use new datafile */
1530
info->state->empty=0;
1531
share->state.dellink= HA_OFFSET_ERROR;
1532
info->state->data_file_length=sort_param.filepos;
1533
share->state.split=info->state->records; /* Only hole records */
1534
share->state.version=(ulong) time((time_t*) 0);
1536
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1538
if (param->testflag & T_WRITE_LOOP)
1540
fputs(" \r",stdout); fflush(stdout);
1545
if (got_error && new_file >= 0)
1547
end_io_cache(&info->rec_cache);
1548
(void) my_close(new_file,MYF(MY_WME));
1549
(void) my_raid_delete(param->temp_filename, share->base.raid_chunks,
1554
my_afree((unsigned char*) temp_buff);
1556
void * rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
1557
if (rec_buff_ptr != NULL)
1560
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1561
end_io_cache(&info->rec_cache);
1562
free(sort_info.buff);
1564
share->state.sortkey=sort_key;
1565
return(flush_blocks(param, share->key_cache, share->kfile) |
1567
} /* sort_records */
1570
/* Sort records recursive using one index */
1572
static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
1574
my_off_t page, unsigned char *buff, uint32_t sort_key,
1575
File new_file,bool update_index)
1577
uint nod_flag,used_length,key_length;
1578
unsigned char *temp_buff,*keypos,*endpos;
1579
my_off_t next_page,rec_pos;
1580
unsigned char lastkey[MI_MAX_KEY_BUFF];
1582
SORT_INFO *sort_info= sort_param->sort_info;
1583
MI_CHECK *param=sort_info->param;
1585
nod_flag=mi_test_if_nod(buff);
1590
if (!(temp_buff=(unsigned char*) my_alloca((uint) keyinfo->block_length)))
1592
mi_check_print_error(param,"Not Enough memory");
1596
used_length=mi_getint(buff);
1597
keypos=buff+2+nod_flag;
1598
endpos=buff+used_length;
1603
next_page=_mi_kpos(nod_flag,keypos);
1604
if (my_pread(info->s->kfile,(unsigned char*) temp_buff,
1605
(uint) keyinfo->block_length, next_page,
1606
MYF(MY_NABP+MY_WME)))
1608
mi_check_print_error(param,"Can't read keys from filepos: %s",
1609
llstr(next_page,llbuff));
1612
if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1613
new_file, update_index))
1616
if (keypos >= endpos ||
1617
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1620
rec_pos= _mi_dpos(info,0,lastkey+key_length);
1622
if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1624
mi_check_print_error(param,"%d when reading datafile",my_errno);
1627
if (rec_pos != sort_param->filepos && update_index)
1629
_mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1630
sort_param->filepos);
1631
if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1634
mi_check_print_error(param,"%d when updating key-pointers",my_errno);
1638
if (sort_write_record(sort_param))
1641
/* Clear end of block to get better compression if the table is backuped */
1642
memset(buff+used_length, 0, keyinfo->block_length-used_length);
1643
if (my_pwrite(info->s->kfile,(unsigned char*) buff,(uint) keyinfo->block_length,
1644
page,param->myf_rw))
1646
mi_check_print_error(param,"%d when updating keyblock",my_errno);
1650
my_afree((unsigned char*) temp_buff);
1654
my_afree((unsigned char*) temp_buff);
1656
} /* sort_record_index */
1661
Check if myisamchk was killed by a signal
1662
This is overloaded by other programs that want to be able to abort
1666
static int not_killed= 0;
1668
volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
1670
return ¬_killed; /* always NULL */
1673
/* print warnings and errors */
1676
void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
1677
const char *fmt,...)
1682
vfprintf(stdout, fmt, args);
1689
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
1694
if (!param->warning_printed && !param->error_printed)
1696
if (param->testflag & T_SILENT)
1697
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,
1698
param->isam_file_name);
1699
param->out_flag|= O_DATA_LOST;
1701
param->warning_printed=1;
1703
fprintf(stderr,"%s: warning: ",my_progname_short);
1704
vfprintf(stderr, fmt, args);
1713
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
1718
if (!param->warning_printed && !param->error_printed)
1720
if (param->testflag & T_SILENT)
1721
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1722
param->out_flag|= O_DATA_LOST;
1724
param->error_printed|=1;
1726
fprintf(stderr,"%s: error: ",my_progname_short);
1727
vfprintf(stderr, fmt, args);