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->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1197
printf("Checksum: %23s\n",llstr(info->state->checksum,llbuff));
1199
if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1200
printf("Keys are only flushed at close\n");
1203
printf("Data records: %13s Deleted blocks: %13s\n",
1204
llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1205
if (param->testflag & T_SILENT)
1206
return; /* This is enough */
1208
if (param->testflag & T_VERBOSE)
1211
printf("Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
1213
printf("Datafile parts: %13s Deleted data: %13s\n",
1214
llstr(share->state.split,llbuff),
1215
llstr(info->state->empty,llbuff2));
1216
printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
1217
share->rec_reflength,share->base.key_reflength);
1218
printf("Datafile length: %13s Keyfile length: %13s\n",
1219
llstr(info->state->data_file_length,llbuff),
1220
llstr(info->state->key_file_length,llbuff2));
1222
if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1223
puts("This is a one-record table");
1226
if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1227
share->base.max_key_file_length != HA_OFFSET_ERROR)
1228
printf("Max datafile length: %13s Max keyfile length: %13s\n",
1229
llstr(share->base.max_data_file_length-1,llbuff),
1230
llstr(share->base.max_key_file_length-1,llbuff2));
1234
printf("Recordlength: %13d\n",(int) share->base.pack_reclength);
1235
if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1237
int64_t2str(share->state.key_map,buff,2);
1238
printf("Using only keys '%s' of %d possibly keys\n",
1239
buff, share->base.keys);
1241
puts("\ntable description:");
1242
printf("Key Start Len Index Type");
1243
if (param->testflag & T_VERBOSE)
1244
printf(" Rec/key Root Blocksize");
1247
for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1248
key < share->base.keys;
1251
keyseg=keyinfo->seg;
1252
if (keyinfo->flag & HA_NOSAME) text="unique ";
1253
else text="multip.";
1256
if (keyseg->flag & HA_REVERSE_SORT)
1258
pos=my_stpcpy(pos,type_names[keyseg->type]);
1261
if (keyinfo->flag & HA_PACK_KEY)
1262
pos=my_stpcpy(pos,prefix_packed_txt);
1263
if (keyinfo->flag & HA_BINARY_PACK_KEY)
1264
pos=my_stpcpy(pos,bin_packed_txt);
1265
if (keyseg->flag & HA_SPACE_PACK)
1266
pos=my_stpcpy(pos,diff_txt);
1267
if (keyseg->flag & HA_BLOB_PART)
1268
pos=my_stpcpy(pos,blob_txt);
1269
if (keyseg->flag & HA_NULL_PART)
1270
pos=my_stpcpy(pos,null_txt);
1273
printf("%-4d%-6ld%-3d %-8s%-21s",
1274
key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1275
if (share->state.key_root[key] != HA_OFFSET_ERROR)
1276
llstr(share->state.key_root[key],buff);
1279
if (param->testflag & T_VERBOSE)
1280
printf("%11lu %12s %10d",
1281
share->state.rec_per_key_part[keyseg_nr++],
1282
buff,keyinfo->block_length);
1284
while ((++keyseg)->type != HA_KEYTYPE_END)
1287
if (keyseg->flag & HA_REVERSE_SORT)
1289
pos=my_stpcpy(pos,type_names[keyseg->type]);
1291
if (keyseg->flag & HA_SPACE_PACK)
1292
pos=my_stpcpy(pos,diff_txt);
1293
if (keyseg->flag & HA_BLOB_PART)
1294
pos=my_stpcpy(pos,blob_txt);
1295
if (keyseg->flag & HA_NULL_PART)
1296
pos=my_stpcpy(pos,null_txt);
1298
printf(" %-6ld%-3d %-21s",
1299
(long) keyseg->start+1,keyseg->length,buff);
1300
if (param->testflag & T_VERBOSE)
1301
printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1306
if (share->state.header.uniques)
1308
MI_UNIQUEDEF *uniqueinfo;
1309
puts("\nUnique Key Start Len Nullpos Nullbit Type");
1310
for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1311
key < share->state.header.uniques; key++, uniqueinfo++)
1314
char null_bit[8],null_pos[8];
1315
printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1316
for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1320
null_bit[0]=null_pos[0]=0;
1321
if (keyseg->null_bit)
1323
sprintf(null_bit,"%d",keyseg->null_bit);
1324
sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1326
printf("%-7ld%-5d%-9s%-10s%-30s\n",
1327
(long) keyseg->start+1,keyseg->length,
1329
type_names[keyseg->type]);
1334
if (param->verbose > 1)
1336
char null_bit[8],null_pos[8];
1337
printf("\nField Start Length Nullpos Nullbit Type");
1338
if (share->options & HA_OPTION_COMPRESS_RECORD)
1339
printf(" Huff tree Bits");
1342
for (field=0 ; field < share->base.fields ; field++)
1344
if (share->options & HA_OPTION_COMPRESS_RECORD)
1345
type=share->rec[field].base_type;
1347
type=(enum en_fieldtype) share->rec[field].type;
1348
end=my_stpcpy(buff,field_pack[type]);
1349
if (share->options & HA_OPTION_COMPRESS_RECORD)
1351
if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1352
end=my_stpcpy(end,", not_always");
1353
if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1354
end=my_stpcpy(end,", no empty");
1355
if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1357
sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
1358
end= strchr(end, '\0');
1362
my_stpcpy(buff,buff+2);
1363
int10_to_str((long) share->rec[field].length,length,10);
1364
null_bit[0]=null_pos[0]=0;
1365
if (share->rec[field].null_bit)
1367
sprintf(null_bit,"%d",share->rec[field].null_bit);
1368
sprintf(null_pos,"%d",share->rec[field].null_pos+1);
1370
printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1371
null_pos, null_bit, buff);
1372
if (share->options & HA_OPTION_COMPRESS_RECORD)
1374
if (share->rec[field].huff_tree)
1376
(uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1377
share->rec[field].huff_tree->quick_table_bits);
1380
start+=share->rec[field].length;
1387
/* Sort records according to one key */
1389
static int mi_sort_records(MI_CHECK *param,
1390
register MI_INFO *info, char * name,
1399
unsigned char *temp_buff;
1400
ha_rows old_record_count;
1401
MYISAM_SHARE *share=info->s;
1402
char llbuff[22],llbuff2[22];
1403
SORT_INFO sort_info;
1404
MI_SORT_PARAM sort_param;
1406
memset(&sort_info, 0, sizeof(sort_info));
1407
memset(&sort_param, 0, sizeof(sort_param));
1408
sort_param.sort_info=&sort_info;
1409
sort_info.param=param;
1410
keyinfo= &share->keyinfo[sort_key];
1415
if (! mi_is_key_active(share->state.key_map, sort_key))
1417
mi_check_print_warning(param,
1418
"Can't sort table '%s' on key %d; No such key",
1420
param->error_printed=0;
1421
return(0); /* Nothing to do */
1423
if (share->data_file_type == COMPRESSED_RECORD)
1425
mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
1426
param->error_printed=0;
1427
return(0); /* Nothing to do */
1429
if (!(param->testflag & T_SILENT))
1431
printf("- Sorting records for MyISAM-table '%s'\n",name);
1433
printf("Data records: %9s Deleted: %9s\n",
1434
llstr(info->state->records,llbuff),
1435
llstr(info->state->del,llbuff2));
1437
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1438
return(0); /* Nothing to do */
1440
init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers,
1442
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1443
WRITE_CACHE,share->pack.header_length,1,
1444
MYF(MY_WME | MY_WAIT_IF_FULL)))
1446
info->opt_flag|=WRITE_CACHE_USED;
1448
if (!(temp_buff=(unsigned char*) my_alloca((uint) keyinfo->block_length)))
1450
mi_check_print_error(param,"Not enough memory for key block");
1454
if (!mi_alloc_rec_buff(info, -1, &sort_param.record))
1456
mi_check_print_error(param,"Not enough memory for record");
1459
fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
1460
new_file=my_raid_create(fn_format(param->temp_filename,
1461
param->temp_filename,"",
1463
0,param->tmpfile_createflag,
1464
share->base.raid_type,
1465
share->base.raid_chunks,
1466
share->base.raid_chunksize,
1470
mi_check_print_error(param,"Can't create new tempfile: '%s'",
1471
param->temp_filename);
1474
if (share->pack.header_length)
1475
if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1478
info->rec_cache.file=new_file; /* Use this file for cacheing*/
1481
for (key=0 ; key < share->base.keys ; key++)
1482
share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1484
if (my_pread(share->kfile,(unsigned char*) temp_buff,
1485
(uint) keyinfo->block_length,
1486
share->state.key_root[sort_key],
1487
MYF(MY_NABP+MY_WME)))
1489
mi_check_print_error(param,"Can't read indexpage from filepos: %s",
1490
(ulong) share->state.key_root[sort_key]);
1494
/* Setup param for sort_write_record */
1495
sort_info.info=info;
1496
sort_info.new_data_file_type=share->data_file_type;
1497
sort_param.fix_datafile=1;
1498
sort_param.master=1;
1499
sort_param.filepos=share->pack.header_length;
1500
old_record_count=info->state->records;
1501
info->state->records=0;
1502
if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1503
info->state->checksum=0;
1505
if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1506
temp_buff, sort_key,new_file,update_index) ||
1507
write_data_suffix(&sort_info,1) ||
1508
flush_io_cache(&info->rec_cache))
1511
if (info->state->records != old_record_count)
1513
mi_check_print_error(param,"found %s of %s records",
1514
llstr(info->state->records,llbuff),
1515
llstr(old_record_count,llbuff2));
1519
my_close(info->dfile,MYF(MY_WME));
1520
param->out_flag|=O_NEW_DATA; /* Data in new file */
1521
info->dfile=new_file; /* Use new datafile */
1523
info->state->empty=0;
1524
share->state.dellink= HA_OFFSET_ERROR;
1525
info->state->data_file_length=sort_param.filepos;
1526
share->state.split=info->state->records; /* Only hole records */
1527
share->state.version=(ulong) time((time_t*) 0);
1529
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1531
if (param->testflag & T_WRITE_LOOP)
1533
fputs(" \r",stdout); fflush(stdout);
1538
if (got_error && new_file >= 0)
1540
end_io_cache(&info->rec_cache);
1541
(void) my_close(new_file,MYF(MY_WME));
1542
(void) my_raid_delete(param->temp_filename, share->base.raid_chunks,
1547
my_afree((unsigned char*) temp_buff);
1549
void * rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
1550
if (rec_buff_ptr != NULL)
1553
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1554
end_io_cache(&info->rec_cache);
1555
free(sort_info.buff);
1557
share->state.sortkey=sort_key;
1558
return(flush_blocks(param, share->key_cache, share->kfile) |
1560
} /* sort_records */
1563
/* Sort records recursive using one index */
1565
static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
1567
my_off_t page, unsigned char *buff, uint32_t sort_key,
1568
File new_file,bool update_index)
1570
uint nod_flag,used_length,key_length;
1571
unsigned char *temp_buff,*keypos,*endpos;
1572
my_off_t next_page,rec_pos;
1573
unsigned char lastkey[MI_MAX_KEY_BUFF];
1575
SORT_INFO *sort_info= sort_param->sort_info;
1576
MI_CHECK *param=sort_info->param;
1578
nod_flag=mi_test_if_nod(buff);
1583
if (!(temp_buff=(unsigned char*) my_alloca((uint) keyinfo->block_length)))
1585
mi_check_print_error(param,"Not Enough memory");
1589
used_length=mi_getint(buff);
1590
keypos=buff+2+nod_flag;
1591
endpos=buff+used_length;
1596
next_page=_mi_kpos(nod_flag,keypos);
1597
if (my_pread(info->s->kfile,(unsigned char*) temp_buff,
1598
(uint) keyinfo->block_length, next_page,
1599
MYF(MY_NABP+MY_WME)))
1601
mi_check_print_error(param,"Can't read keys from filepos: %s",
1602
llstr(next_page,llbuff));
1605
if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1606
new_file, update_index))
1609
if (keypos >= endpos ||
1610
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1613
rec_pos= _mi_dpos(info,0,lastkey+key_length);
1615
if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1617
mi_check_print_error(param,"%d when reading datafile",my_errno);
1620
if (rec_pos != sort_param->filepos && update_index)
1622
_mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1623
sort_param->filepos);
1624
if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1627
mi_check_print_error(param,"%d when updating key-pointers",my_errno);
1631
if (sort_write_record(sort_param))
1634
/* Clear end of block to get better compression if the table is backuped */
1635
memset(buff+used_length, 0, keyinfo->block_length-used_length);
1636
if (my_pwrite(info->s->kfile,(unsigned char*) buff,(uint) keyinfo->block_length,
1637
page,param->myf_rw))
1639
mi_check_print_error(param,"%d when updating keyblock",my_errno);
1643
my_afree((unsigned char*) temp_buff);
1647
my_afree((unsigned char*) temp_buff);
1649
} /* sort_record_index */
1654
Check if myisamchk was killed by a signal
1655
This is overloaded by other programs that want to be able to abort
1659
static int not_killed= 0;
1661
volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
1663
return ¬_killed; /* always NULL */
1666
/* print warnings and errors */
1669
void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
1670
const char *fmt,...)
1675
vfprintf(stdout, fmt, args);
1682
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
1687
if (!param->warning_printed && !param->error_printed)
1689
if (param->testflag & T_SILENT)
1690
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,
1691
param->isam_file_name);
1692
param->out_flag|= O_DATA_LOST;
1694
param->warning_printed=1;
1696
fprintf(stderr,"%s: warning: ",my_progname_short);
1697
vfprintf(stderr, fmt, args);
1706
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
1711
if (!param->warning_printed && !param->error_printed)
1713
if (param->testflag & T_SILENT)
1714
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1715
param->out_flag|= O_DATA_LOST;
1717
param->error_printed|=1;
1719
fprintf(stderr,"%s: error: ",my_progname_short);
1720
vfprintf(stderr, fmt, args);