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
32
SET_STACK_SIZE(9000) /* Minimum stack size for program */
34
#define my_raid_create(A,B,C,D,E,F,G) my_create(A,B,C,G)
35
#define my_raid_delete(A,B,C) my_delete(A,B)
37
#include "myisamdef.h"
39
static uint decode_bits;
40
static char **default_argv;
41
static const char *load_default_groups[]= { "myisamchk", 0 };
42
static const char *set_collation_name, *opt_tmpdir;
43
static const CHARSET_INFO *set_collation;
44
static long opt_myisam_block_size;
45
static long opt_key_cache_block_size;
46
static const char *my_progname_short;
47
static MY_TMPDIR myisamchk_tmpdir;
49
static const char *type_names[]=
50
{ "impossible","char","binary", "short", "long", "float",
51
"double","number","unsigned short",
52
"unsigned long","int64_t","uint64_t","int24",
53
"uint24","int8","varchar", "varbin","?",
56
static const char *prefix_packed_txt="packed ",
57
*bin_packed_txt="prefix ",
58
*diff_txt="stripped ",
62
static const char *field_pack[]=
63
{"","no endspace", "no prespace",
64
"no zeros", "blob", "constant", "table-lockup",
65
"always zero","varchar","unique-hash","?","?"};
67
static const char *myisam_stats_method_str="nulls_unequal";
69
static void get_options(int *argc,char * * *argv);
70
static void print_version(void);
71
static void usage(void);
72
static int myisamchk(MI_CHECK *param, char *filename);
73
static void descript(MI_CHECK *param, register MI_INFO *info, char * name);
74
static int mi_sort_records(MI_CHECK *param, register MI_INFO *info,
75
char * name, uint sort_key,
76
bool write_info, bool update_index);
77
static int sort_record_index(MI_SORT_PARAM *sort_param, MI_INFO *info,
79
my_off_t page,uchar *buff,uint sortkey,
80
File new_file, bool update_index);
86
int main(int argc, char **argv)
90
my_progname_short= my_progname+dirname_length(my_progname);
92
myisamchk_init(&check_param);
93
check_param.opt_lock_memory=1; /* Lock memory if possible */
94
check_param.using_global_keycache = 0;
95
get_options(&argc,(char***) &argv);
96
myisam_quick_table_bits=decode_bits;
100
int new_error=myisamchk(&check_param, *(argv++));
101
if ((check_param.testflag & T_REP_ANY) != T_REP)
102
check_param.testflag&= ~T_REP;
103
VOID(fflush(stdout));
104
VOID(fflush(stderr));
105
if ((check_param.error_printed | check_param.warning_printed) &&
106
(check_param.testflag & T_FORCE_CREATE) &&
107
(!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
110
uint old_testflag=check_param.testflag;
111
if (!(check_param.testflag & T_REP))
112
check_param.testflag|= T_REP_BY_SORT;
113
check_param.testflag&= ~T_EXTEND; /* Don't needed */
114
error|=myisamchk(&check_param, argv[-1]);
115
check_param.testflag= old_testflag;
116
VOID(fflush(stdout));
117
VOID(fflush(stderr));
121
if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
123
puts("\n---------\n");
124
VOID(fflush(stdout));
127
if (check_param.total_files > 1)
128
{ /* Only if descript */
129
char buff[22],buff2[22];
130
if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
131
puts("\n---------\n");
132
printf("\nTotal of all %d MyISAM-files:\nData records: %9s Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
133
llstr(check_param.total_deleted,buff2));
135
free_defaults(default_argv);
136
free_tmpdir(&myisamchk_tmpdir);
137
my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
140
return 0; /* No compiler warning */
145
OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
146
OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE,
147
OPT_KEY_CACHE_BLOCK_SIZE, OPT_MYISAM_BLOCK_SIZE,
148
OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
149
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS,
150
OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD
153
static struct my_option my_long_options[] =
156
"Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
157
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
158
{"block-search", 'b',
159
"No help available.",
160
0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
162
"Make a backup of the .MYD file as 'filename-time.BAK'.",
163
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
164
{"character-sets-dir", OPT_CHARSETS_DIR,
165
"Directory where character sets are.",
166
(char**) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
168
"Check table for errors.",
169
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
170
{"check-only-changed", 'C',
171
"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).",
172
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
173
{"correct-checksum", OPT_CORRECT_CHECKSUM,
174
"Correct checksum information for table.",
175
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
177
"Prints some information about table.",
178
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
179
{"data-file-length", 'D',
180
"Max length of data file (when recreating data-file when it's full).",
181
(char**) &check_param.max_data_file_length,
182
(char**) &check_param.max_data_file_length,
183
0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
184
{"extend-check", 'e',
185
"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.",
186
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
188
"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).",
189
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
191
"Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
192
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
194
"Display this help and exit.",
195
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
197
"Display this help and exit.",
198
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
200
"Print statistics information about table that is checked.",
201
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
203
"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.",
204
(char**) &check_param.keys_in_use,
205
(char**) &check_param.keys_in_use,
206
0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
207
{"max-record-length", OPT_MAX_RECORD_LENGTH,
208
"Skip rows bigger than this if myisamchk can't allocate memory to hold it",
209
(char**) &check_param.max_record_length,
210
(char**) &check_param.max_record_length,
211
0, GET_ULL, REQUIRED_ARG, INT64_MAX, 0, INT64_MAX, 0, 0, 0},
212
{"medium-check", 'm',
213
"Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
214
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
215
{"quick", 'q', "Faster repair by not modifying the data file.",
216
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
218
"Don't mark table as checked.",
219
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
221
"Can fix almost anything except unique keys that aren't unique.",
222
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
223
{"parallel-recover", 'p',
224
"Same as '-r' but creates all the keys in parallel.",
225
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
226
{"safe-recover", 'o',
227
"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.",
228
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
229
{"sort-recover", 'n',
230
"Force recovering with sorting even if the temporary file was very big.",
231
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
233
{"start-check-pos", OPT_START_CHECK_POS,
234
"No help available.",
235
0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
237
{"set-auto-increment", 'A',
238
"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.",
239
(char**) &check_param.auto_increment_value,
240
(char**) &check_param.auto_increment_value,
241
0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
242
{"set-collation", OPT_SET_COLLATION,
243
"Change the collation used by the index",
244
(char**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
245
{"set-variable", 'O',
246
"Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
247
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
249
"Only print errors. One can use two -s to make myisamchk very silent.",
250
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
252
"Sort index blocks. This speeds up 'read-next' in applications.",
253
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
254
{"sort-records", 'R',
255
"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!)",
256
(char**) &check_param.opt_sort_key,
257
(char**) &check_param.opt_sort_key,
258
0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
260
"Path for temporary files.",
261
(char**) &opt_tmpdir,
262
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
263
{"update-state", 'U',
264
"Mark tables as crashed if any errors were found.",
265
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
267
"Unpack file packed with myisampack.",
268
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
270
"Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
271
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
273
"Print version and exit.",
274
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
276
"Wait if table is locked.",
277
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
278
{ "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
279
(char**) &check_param.use_buffers, (char**) &check_param.use_buffers, 0,
280
GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
281
(long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
282
{ "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "",
283
(char**) &opt_key_cache_block_size,
284
(char**) &opt_key_cache_block_size, 0,
285
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
286
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
287
{ "myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "",
288
(char**) &opt_myisam_block_size, (char**) &opt_myisam_block_size, 0,
289
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
290
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
291
{ "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
292
(char**) &check_param.read_buffer_length,
293
(char**) &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
294
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
295
(long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
296
{ "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
297
(char**) &check_param.write_buffer_length,
298
(char**) &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
299
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
300
(long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
301
{ "sort_buffer_size", OPT_SORT_BUFFER_SIZE, "",
302
(char**) &check_param.sort_buffer_length,
303
(char**) &check_param.sort_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
304
(long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
305
(long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
306
{ "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
307
(char**) &check_param.sort_key_blocks,
308
(char**) &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
309
BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
310
{ "decode_bits", OPT_DECODE_BITS, "", (char**) &decode_bits,
311
(char**) &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
312
{"stats_method", OPT_STATS_METHOD,
313
"Specifies how index statistics collection code should treat NULLs. "
314
"Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
315
"\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
316
(char**) &myisam_stats_method_str, (char**) &myisam_stats_method_str, 0,
317
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
318
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
322
static void print_version(void)
324
printf("%s Ver 2.7 for %s at %s\n", my_progname, SYSTEM_TYPE,
329
static void usage(void)
332
puts("By Monty, for your professional use");
333
puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
334
puts("Description, check and repair of MyISAM tables.");
335
puts("Used without options all tables on the command will be checked for errors");
336
printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname_short);
337
printf("\nGlobal options:\n");
339
-?, --help Display this help and exit.\n\
340
-O, --set-variable var=option.\n\
341
Change the value of a variable. Please note that\n\
342
this option is deprecated; you can set variables\n\
343
directly with '--variable-name=value'.\n\
344
-t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
345
specified, separated by ");
346
#if defined( __WIN__)
347
printf("semicolon (;)");
351
printf(", they will be used\n\
352
in a round-robin fashion.\n\
353
-s, --silent Only print errors. One can use two -s to make\n\
354
myisamchk very silent.\n\
355
-v, --verbose Print more information. This can be used with\n\
356
--description and --check. Use many -v for more verbosity.\n\
357
-V, --version Print version and exit.\n\
358
-w, --wait Wait if table is locked.\n\n");
360
puts(" --start-check-pos=# Start reading file at given offset.\n");
363
puts("Check options (check is the default action for myisamchk):\n\
364
-c, --check Check table for errors.\n\
365
-e, --extend-check Check the table VERY throughly. Only use this in\n\
366
extreme cases as myisamchk should normally be able to\n\
367
find out if the table is ok even without this switch.\n\
368
-F, --fast Check only tables that haven't been closed properly.\n\
369
-C, --check-only-changed\n\
370
Check only tables that have changed since last check.\n\
371
-f, --force Restart with '-r' if there are any errors in the table.\n\
372
States will be updated as with '--update-state'.\n\
373
-i, --information Print statistics information about table that is checked.\n\
374
-m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
375
all errors. Should be good enough for most cases.\n\
376
-U --update-state Mark tables as crashed if you find any errors.\n\
377
-T, --read-only Don't mark table as checked.\n");
379
puts("Repair options (When using '-r' or '-o'):\n\
380
-B, --backup Make a backup of the .MYD file as 'filename-time.BAK'.\n\
381
--correct-checksum Correct checksum information for table.\n\
382
-D, --data-file-length=# Max length of data file (when recreating data\n\
383
file when it's full).\n\
384
-e, --extend-check Try to recover every possible row from the data file\n\
385
Normally this will also find a lot of garbage rows;\n\
386
Don't use this option if you are not totally desperate.\n\
387
-f, --force Overwrite old temporary files.\n\
388
-k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\
389
bit mask of which keys to use. This can be used to\n\
390
get faster inserts.\n\
391
--max-record-length=#\n\
392
Skip rows bigger than this if myisamchk can't allocate\n\
393
memory to hold it.\n\
394
-r, --recover Can fix almost anything except unique keys that aren't\n\
396
-n, --sort-recover Forces recovering with sorting even if the temporary\n\
397
file would be very big.\n\
398
-p, --parallel-recover\n\
399
Uses the same technique as '-r' and '-n', but creates\n\
400
all the keys in parallel, in different threads.\n\
401
-o, --safe-recover Uses old recovery method; Slower than '-r' but can\n\
402
handle a couple of cases where '-r' reports that it\n\
403
can't fix the data file.\n\
404
--character-sets-dir=...\n\
405
Directory where character sets are.\n\
406
--set-collation=name\n\
407
Change the collation used by the index.\n\
408
-q, --quick Faster repair by not modifying the data file.\n\
409
One can give a second '-q' to force myisamchk to\n\
410
modify the original datafile in case of duplicate keys.\n\
411
NOTE: Tables where the data file is currupted can't be\n\
412
fixed with this option.\n\
413
-u, --unpack Unpack file packed with myisampack.\n\
416
puts("Other actions:\n\
417
-a, --analyze Analyze distribution of keys. Will make some joins in\n\
418
MySQL faster. You can check the calculated distribution\n\
419
by using '--description --verbose table_name'.\n\
420
--stats_method=name Specifies how index statistics collection code should\n\
421
treat NULLs. Possible values of name are \"nulls_unequal\"\n\
422
(default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
423
\"nulls_ignored\".\n\
424
-d, --description Prints some information about table.\n\
425
-A, --set-auto-increment[=value]\n\
426
Force auto_increment to start at this or higher value\n\
427
If no value is given, then sets the next auto_increment\n\
428
value to the highest used value for the auto key + 1.\n\
429
-S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
431
-R, --sort-records=#\n\
432
Sort records according to an index. This makes your\n\
433
data much more localized and may speed up things\n\
434
(It may be VERY slow to do a sort the first time!).\n\
435
-b, --block-search=#\n\
436
Find a record, a block at given offset belongs to.");
438
print_defaults("my", load_default_groups);
439
my_print_variables(my_long_options);
442
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
443
"nulls_ignored", NullS};
444
TYPELIB myisam_stats_method_typelib= {
445
array_elements(myisam_stats_method_names) - 1, "",
446
myisam_stats_method_names, NULL};
451
get_one_option(int optid,
452
const struct my_option *opt __attribute__((unused)),
457
if (argument == disabled_my_option)
458
check_param.testflag&= ~T_STATISTICS;
460
check_param.testflag|= T_STATISTICS;
464
check_param.auto_increment_value= strtoull(argument, NULL, 0);
466
check_param.auto_increment_value= 0; /* Set to max used value */
467
check_param.testflag|= T_AUTO_INC;
470
check_param.search_after_block= strtoul(argument, NULL, 10);
473
if (argument == disabled_my_option)
474
check_param.testflag&= ~T_BACKUP_DATA;
476
check_param.testflag|= T_BACKUP_DATA;
479
if (argument == disabled_my_option)
480
check_param.testflag&= ~T_CHECK;
482
check_param.testflag|= T_CHECK;
485
if (argument == disabled_my_option)
486
check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
488
check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
491
check_param.max_data_file_length=strtoll(argument, NULL, 10);
493
case 's': /* silent */
494
if (argument == disabled_my_option)
495
check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
498
if (check_param.testflag & T_SILENT)
499
check_param.testflag|= T_VERY_SILENT;
500
check_param.testflag|= T_SILENT;
501
check_param.testflag&= ~T_WRITE_LOOP;
505
if (argument == disabled_my_option)
506
check_param.testflag&= ~T_WAIT_FOREVER;
508
check_param.testflag|= T_WAIT_FOREVER;
510
case 'd': /* description if isam-file */
511
if (argument == disabled_my_option)
512
check_param.testflag&= ~T_DESCRIPT;
514
check_param.testflag|= T_DESCRIPT;
516
case 'e': /* extend check */
517
if (argument == disabled_my_option)
518
check_param.testflag&= ~T_EXTEND;
520
check_param.testflag|= T_EXTEND;
523
if (argument == disabled_my_option)
524
check_param.testflag&= ~T_INFO;
526
check_param.testflag|= T_INFO;
529
if (argument == disabled_my_option)
531
check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
532
check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
536
check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
537
check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
541
if (argument == disabled_my_option)
542
check_param.testflag&= ~T_FAST;
544
check_param.testflag|= T_FAST;
547
check_param.keys_in_use= (uint64_t) strtoll(argument, NULL, 10);
550
if (argument == disabled_my_option)
551
check_param.testflag&= ~T_MEDIUM;
553
check_param.testflag|= T_MEDIUM; /* Medium check */
555
case 'r': /* Repair table */
556
check_param.testflag&= ~T_REP_ANY;
557
if (argument != disabled_my_option)
558
check_param.testflag|= T_REP_BY_SORT;
561
check_param.testflag&= ~T_REP_ANY;
562
if (argument != disabled_my_option)
563
check_param.testflag|= T_REP_PARALLEL;
566
check_param.testflag&= ~T_REP_ANY;
567
check_param.force_sort= 0;
568
if (argument != disabled_my_option)
570
check_param.testflag|= T_REP;
571
my_disable_async_io= 1; /* More safety */
575
check_param.testflag&= ~T_REP_ANY;
576
if (argument == disabled_my_option)
577
check_param.force_sort= 0;
580
check_param.testflag|= T_REP_BY_SORT;
581
check_param.force_sort= 1;
585
if (argument == disabled_my_option)
586
check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
588
check_param.testflag|=
589
(check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
592
if (argument == disabled_my_option)
593
check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
595
check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
597
case 'v': /* Verbose */
598
if (argument == disabled_my_option)
600
check_param.testflag&= ~T_VERBOSE;
601
check_param.verbose=0;
605
check_param.testflag|= T_VERBOSE;
606
check_param.verbose++;
609
case 'R': /* Sort records */
610
if (argument == disabled_my_option)
611
check_param.testflag&= ~T_SORT_RECORDS;
614
check_param.testflag|= T_SORT_RECORDS;
615
check_param.opt_sort_key= (uint) atoi(argument) - 1;
616
if (check_param.opt_sort_key >= MI_MAX_KEY)
619
"The value of the sort key is bigger than max key: %d.\n",
625
case 'S': /* Sort index */
626
if (argument == disabled_my_option)
627
check_param.testflag&= ~T_SORT_INDEX;
629
check_param.testflag|= T_SORT_INDEX;
632
if (argument == disabled_my_option)
633
check_param.testflag&= ~T_READONLY;
635
check_param.testflag|= T_READONLY;
638
if (argument == disabled_my_option)
639
check_param.testflag&= ~T_UPDATE_STATE;
641
check_param.testflag|= T_UPDATE_STATE;
646
case OPT_CORRECT_CHECKSUM:
647
if (argument == disabled_my_option)
648
check_param.testflag&= ~T_CALC_CHECKSUM;
650
check_param.testflag|= T_CALC_CHECKSUM;
652
case OPT_STATS_METHOD:
655
enum_mi_stats_method method_conv;
656
myisam_stats_method_str= argument;
657
if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
659
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
664
method_conv= MI_STATS_METHOD_NULLS_EQUAL;
667
method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
670
method_conv= MI_STATS_METHOD_IGNORE_NULLS;
672
default: assert(0); /* Impossible */
674
check_param.stats_method= method_conv;
677
#ifdef DEBUG /* Only useful if debugging */
678
case OPT_START_CHECK_POS:
679
check_param.start_check_pos= strtoull(argument, NULL, 0);
683
my_print_help(my_long_options);
693
static void get_options(register int *argc,register char ***argv)
697
load_defaults("my", load_default_groups, argc, argv);
699
if (isatty(fileno(stdout)))
700
check_param.testflag|=T_WRITE_LOOP;
702
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
705
/* If using repair, then update checksum if one uses --update-state */
706
if ((check_param.testflag & T_UPDATE_STATE) &&
707
(check_param.testflag & T_REP_ANY))
708
check_param.testflag|= T_CALC_CHECKSUM;
716
if ((check_param.testflag & T_UNPACK) &&
717
(check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
720
"%s: --unpack can't be used with --quick or --sort-records\n",
724
if ((check_param.testflag & T_READONLY) &&
725
(check_param.testflag &
726
(T_REP_ANY | T_STATISTICS | T_AUTO_INC |
727
T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
730
"%s: Can't use --readonly when repairing or sorting\n",
735
if (init_tmpdir(&myisamchk_tmpdir, opt_tmpdir))
738
check_param.tmpdir=&myisamchk_tmpdir;
739
check_param.key_cache_block_size= opt_key_cache_block_size;
741
if (set_collation_name)
742
if (!(set_collation= get_charset_by_name(set_collation_name,
746
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
753
static int myisamchk(MI_CHECK *param, char * filename)
755
int error,lock_type,recreate;
756
int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
760
char llbuff[22],llbuff2[22];
761
bool state_updated=0;
764
param->out_flag=error=param->warning_printed=param->error_printed=
767
param->isam_file_name=filename; /* For error messages */
768
if (!(info=mi_open(filename,
769
(param->testflag & (T_DESCRIPT | T_READONLY)) ?
772
((param->testflag & T_WAIT_FOREVER) ?
773
HA_OPEN_WAIT_IF_LOCKED :
774
(param->testflag & T_DESCRIPT) ?
775
HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
777
/* Avoid twice printing of isam file name */
778
param->error_printed=1;
781
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);
783
case HA_ERR_NOT_A_TABLE:
784
mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
786
case HA_ERR_CRASHED_ON_USAGE:
787
mi_check_print_error(param,"'%s' is marked as crashed",filename);
789
case HA_ERR_CRASHED_ON_REPAIR:
790
mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
792
case HA_ERR_OLD_FILE:
793
mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
795
case HA_ERR_END_OF_FILE:
796
mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
799
mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
802
mi_check_print_error(param,"File '%s' doesn't exist",filename);
805
mi_check_print_error(param,"You don't have permission to use '%s'",filename);
808
mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
815
share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
816
share->tot_locks-= share->r_locks;
818
raid_chunks=share->base.raid_chunks;
821
Skip the checking of the file if:
822
We are using --fast and the table is closed properly
823
We are using --check-only-changed-tables and the table hasn't changed
825
if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
827
bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
829
if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
830
((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
831
STATE_CRASHED_ON_REPAIR) ||
832
!(param->testflag & T_CHECK_ONLY_CHANGED))))
835
if (info->s->base.keys && info->state->records)
837
if ((param->testflag & T_STATISTICS) &&
838
(share->state.changed & STATE_NOT_ANALYZED))
840
if ((param->testflag & T_SORT_INDEX) &&
841
(share->state.changed & STATE_NOT_SORTED_PAGES))
843
if ((param->testflag & T_REP_BY_SORT) &&
844
(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
847
if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
848
(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
849
STATE_CRASHED_ON_REPAIR)))
853
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
854
printf("MyISAM file: %s is already checked\n",filename);
857
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
864
if ((param->testflag & (T_REP_ANY | T_STATISTICS |
865
T_SORT_RECORDS | T_SORT_INDEX)) &&
866
(((param->testflag & T_UNPACK) &&
867
share->data_file_type == COMPRESSED_RECORD) ||
868
mi_uint2korr(share->state.header.state_info_length) !=
869
MI_STATE_INFO_SIZE ||
870
mi_uint2korr(share->state.header.base_info_length) !=
872
mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
873
~share->state.key_map) ||
874
test_if_almost_full(info) ||
875
info->s->state.header.file_version[3] != myisam_file_magic[3] ||
877
set_collation->number != share->state.header.language) ||
878
myisam_block_size != MI_KEY_BLOCK_LENGTH))
881
param->language= set_collation->number;
882
if (recreate_table(param, &info,filename))
885
"MyISAM-table '%s' is not fixed because of errors\n",
890
if (!(param->testflag & T_REP_ANY))
892
param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
893
if (!(param->testflag & T_SILENT))
894
printf("- '%s' has old table-format. Recreating index\n",filename);
898
share->tot_locks-= share->r_locks;
902
if (param->testflag & T_DESCRIPT)
904
param->total_files++;
905
param->total_records+=info->state->records;
906
param->total_deleted+=info->state->del;
907
descript(param, info, filename);
912
if (!(param->testflag & T_READONLY))
913
lock_type = F_WRLCK; /* table is changed */
916
if (info->lock_type == F_RDLCK)
917
info->lock_type=F_UNLCK; /* Read only table */
918
if (_mi_readinfo(info,lock_type,0))
920
mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
922
param->error_printed=0;
926
_mi_readinfo() has locked the table.
927
We mark the table as locked (without doing file locks) to be able to
928
use functions that only works on locked tables (like row caching).
930
mi_lock_database(info, F_EXTRA_LCK);
931
datafile=info->dfile;
933
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
935
if (param->testflag & T_REP_ANY)
937
uint64_t tmp=share->state.key_map;
938
mi_copy_keys_active(share->state.key_map, share->base.keys,
940
if (tmp != share->state.key_map)
941
info->update|=HA_STATE_CHANGED;
943
if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
945
if (param->testflag & T_FORCE_CREATE)
948
mi_check_print_info(param,"Creating new data file\n");
953
mi_check_print_error(param,
954
"Quick-recover aborted; Run recovery without switch 'q'");
959
if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
960
(mi_is_any_key_active(share->state.key_map) ||
961
(rep_quick && !param->keys_in_use && !recreate)) &&
962
mi_test_if_sort_rep(info, info->state->records,
963
info->s->state.key_map,
966
if (param->testflag & T_REP_BY_SORT)
967
error=mi_repair_by_sort(param,info,filename,rep_quick);
969
error=mi_repair_parallel(param,info,filename,rep_quick);
972
else if (param->testflag & T_REP_ANY)
973
error=mi_repair(param, info,filename,rep_quick);
975
if (!error && param->testflag & T_SORT_RECORDS)
979
We can't update the index in mi_sort_records if we have a
980
prefix compressed or fulltext index
983
for (key=0 ; key < share->base.keys; key++)
984
if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY))
987
error=mi_sort_records(param,info,filename,param->opt_sort_key,
988
/* what is the following parameter for ? */
989
(bool) !(param->testflag & T_REP),
991
datafile=info->dfile; /* This is now locked */
992
if (!error && !update_index)
995
puts("Table had a compressed index; We must now recreate the index");
996
error=mi_repair_by_sort(param,info,filename,1);
999
if (!error && param->testflag & T_SORT_INDEX)
1000
error=mi_sort_index(param,info,filename);
1002
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1003
STATE_CRASHED_ON_REPAIR);
1005
mi_mark_crashed(info);
1007
else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
1009
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1010
printf("Checking MyISAM file: %s\n",filename);
1011
if (!(param->testflag & T_SILENT))
1012
printf("Data records: %7s Deleted blocks: %7s\n",
1013
llstr(info->state->records,llbuff),
1014
llstr(info->state->del,llbuff2));
1015
error =chk_status(param,info);
1016
mi_intersect_keys_active(share->state.key_map, param->keys_in_use);
1017
error =chk_size(param,info);
1018
if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1019
error|=chk_del(param, info,param->testflag);
1020
if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1021
!param->start_check_pos)))
1023
error|=chk_key(param, info);
1024
if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1025
error=update_state_info(param, info,
1026
((param->testflag & T_STATISTICS) ?
1028
((param->testflag & T_AUTO_INC) ?
1029
UPDATE_AUTO_INC : 0));
1031
if ((!rep_quick && !error) ||
1032
!(param->testflag & (T_FAST | T_FORCE_CREATE)))
1034
if (param->testflag & (T_EXTEND | T_MEDIUM))
1035
VOID(init_key_cache(dflt_key_cache,opt_key_cache_block_size,
1036
param->use_buffers, 0, 0));
1037
VOID(init_io_cache(¶m->read_cache,datafile,
1038
(uint) param->read_buffer_length,
1040
(param->start_check_pos ?
1041
param->start_check_pos :
1042
share->pack.header_length),
1046
if ((info->s->options & (HA_OPTION_PACK_RECORD |
1047
HA_OPTION_COMPRESS_RECORD)) ||
1048
(param->testflag & (T_EXTEND | T_MEDIUM)))
1049
error|=chk_data_link(param, info, param->testflag & T_EXTEND);
1050
error|=flush_blocks(param, share->key_cache, share->kfile);
1051
VOID(end_io_cache(¶m->read_cache));
1055
if ((share->state.changed & STATE_CHANGED) &&
1056
(param->testflag & T_UPDATE_STATE))
1057
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1058
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1059
STATE_CRASHED_ON_REPAIR);
1061
else if (!mi_is_crashed(info) &&
1062
(param->testflag & T_UPDATE_STATE))
1063
{ /* Mark crashed */
1064
mi_mark_crashed(info);
1065
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1069
if ((param->testflag & T_AUTO_INC) ||
1070
((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1071
update_auto_increment_key(param, info,
1072
(bool) !test(param->testflag & T_AUTO_INC));
1074
if (!(param->testflag & T_DESCRIPT))
1076
if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1077
error|=update_state_info(param, info,
1079
(((param->testflag & T_REP_ANY) ?
1081
(state_updated ? UPDATE_STAT : 0) |
1082
((param->testflag & T_SORT_RECORDS) ?
1084
info->update&= ~HA_STATE_CHANGED;
1086
mi_lock_database(info, F_UNLCK);
1090
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
1095
if (param->out_flag & O_NEW_DATA)
1096
error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1098
((param->testflag & T_BACKUP_DATA) ?
1099
MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1100
if (param->out_flag & O_NEW_INDEX)
1101
error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1104
VOID(fflush(stdout)); VOID(fflush(stderr));
1105
if (param->error_printed)
1107
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1109
VOID(fprintf(stderr,
1110
"MyISAM-table '%s' is not fixed because of errors\n",
1112
if (param->testflag & T_REP_ANY)
1113
VOID(fprintf(stderr,
1114
"Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n"));
1116
else if (!(param->error_printed & 2) &&
1117
!(param->testflag & T_FORCE_CREATE))
1118
VOID(fprintf(stderr,
1119
"MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
1122
else if (param->warning_printed &&
1123
! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1125
VOID(fprintf(stderr, "MyISAM-table '%s' is usable but should be fixed\n",
1127
VOID(fflush(stderr));
1132
/* Write info about table */
1134
static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
1136
uint key,keyseg_nr,field,start;
1137
register MI_KEYDEF *keyinfo;
1138
register HA_KEYSEG *keyseg;
1139
register const char *text;
1140
char buff[160],length[10],*pos,*end;
1141
enum en_fieldtype type;
1142
MYISAM_SHARE *share=info->s;
1143
char llbuff[22],llbuff2[22];
1145
printf("\nMyISAM file: %s\n",name);
1146
fputs("Record format: ",stdout);
1147
if (share->options & HA_OPTION_COMPRESS_RECORD)
1149
else if (share->options & HA_OPTION_PACK_RECORD)
1152
puts("Fixed length");
1153
printf("Character set: %s (%d)\n",
1154
get_charset_name(share->state.header.language),
1155
share->state.header.language);
1157
if (param->testflag & T_VERBOSE)
1159
printf("File-version: %d\n",
1160
(int) share->state.header.file_version[3]);
1161
if (share->state.create_time)
1163
get_date(buff,1,share->state.create_time);
1164
printf("Creation time: %s\n",buff);
1166
if (share->state.check_time)
1168
get_date(buff,1,share->state.check_time);
1169
printf("Recover time: %s\n",buff);
1172
if (share->state.changed & STATE_CRASHED)
1173
stpcpy(buff,"crashed");
1176
if (share->state.open_count)
1177
pos=stpcpy(pos,"open,");
1178
if (share->state.changed & STATE_CHANGED)
1179
pos=stpcpy(pos,"changed,");
1181
pos=stpcpy(pos,"checked,");
1182
if (!(share->state.changed & STATE_NOT_ANALYZED))
1183
pos=stpcpy(pos,"analyzed,");
1184
if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1185
pos=stpcpy(pos,"optimized keys,");
1186
if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1187
pos=stpcpy(pos,"sorted index pages,");
1188
pos[-1]=0; /* Remove extra ',' */
1190
printf("Status: %s\n",buff);
1191
if (share->base.auto_key)
1193
printf("Auto increment key: %13d Last value: %13s\n",
1194
share->base.auto_key,
1195
llstr(share->state.auto_increment,llbuff));
1197
if (share->base.raid_type)
1199
printf("RAID: Type: %u Chunks: %u Chunksize: %lu\n",
1200
share->base.raid_type,
1201
share->base.raid_chunks,
1202
share->base.raid_chunksize);
1204
if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1205
printf("Checksum: %23s\n",llstr(info->state->checksum,llbuff));
1207
if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1208
printf("Keys are only flushed at close\n");
1211
printf("Data records: %13s Deleted blocks: %13s\n",
1212
llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1213
if (param->testflag & T_SILENT)
1214
return; /* This is enough */
1216
if (param->testflag & T_VERBOSE)
1219
printf("Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
1221
printf("Datafile parts: %13s Deleted data: %13s\n",
1222
llstr(share->state.split,llbuff),
1223
llstr(info->state->empty,llbuff2));
1224
printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
1225
share->rec_reflength,share->base.key_reflength);
1226
printf("Datafile length: %13s Keyfile length: %13s\n",
1227
llstr(info->state->data_file_length,llbuff),
1228
llstr(info->state->key_file_length,llbuff2));
1230
if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1231
puts("This is a one-record table");
1234
if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1235
share->base.max_key_file_length != HA_OFFSET_ERROR)
1236
printf("Max datafile length: %13s Max keyfile length: %13s\n",
1237
llstr(share->base.max_data_file_length-1,llbuff),
1238
llstr(share->base.max_key_file_length-1,llbuff2));
1242
printf("Recordlength: %13d\n",(int) share->base.pack_reclength);
1243
if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1245
int64_t2str(share->state.key_map,buff,2);
1246
printf("Using only keys '%s' of %d possibly keys\n",
1247
buff, share->base.keys);
1249
puts("\ntable description:");
1250
printf("Key Start Len Index Type");
1251
if (param->testflag & T_VERBOSE)
1252
printf(" Rec/key Root Blocksize");
1253
VOID(putchar('\n'));
1255
for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1256
key < share->base.keys;
1259
keyseg=keyinfo->seg;
1260
if (keyinfo->flag & HA_NOSAME) text="unique ";
1261
else text="multip.";
1264
if (keyseg->flag & HA_REVERSE_SORT)
1266
pos=stpcpy(pos,type_names[keyseg->type]);
1269
if (keyinfo->flag & HA_PACK_KEY)
1270
pos=stpcpy(pos,prefix_packed_txt);
1271
if (keyinfo->flag & HA_BINARY_PACK_KEY)
1272
pos=stpcpy(pos,bin_packed_txt);
1273
if (keyseg->flag & HA_SPACE_PACK)
1274
pos=stpcpy(pos,diff_txt);
1275
if (keyseg->flag & HA_BLOB_PART)
1276
pos=stpcpy(pos,blob_txt);
1277
if (keyseg->flag & HA_NULL_PART)
1278
pos=stpcpy(pos,null_txt);
1281
printf("%-4d%-6ld%-3d %-8s%-21s",
1282
key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1283
if (share->state.key_root[key] != HA_OFFSET_ERROR)
1284
llstr(share->state.key_root[key],buff);
1287
if (param->testflag & T_VERBOSE)
1288
printf("%11lu %12s %10d",
1289
share->state.rec_per_key_part[keyseg_nr++],
1290
buff,keyinfo->block_length);
1291
VOID(putchar('\n'));
1292
while ((++keyseg)->type != HA_KEYTYPE_END)
1295
if (keyseg->flag & HA_REVERSE_SORT)
1297
pos=stpcpy(pos,type_names[keyseg->type]);
1299
if (keyseg->flag & HA_SPACE_PACK)
1300
pos=stpcpy(pos,diff_txt);
1301
if (keyseg->flag & HA_BLOB_PART)
1302
pos=stpcpy(pos,blob_txt);
1303
if (keyseg->flag & HA_NULL_PART)
1304
pos=stpcpy(pos,null_txt);
1306
printf(" %-6ld%-3d %-21s",
1307
(long) keyseg->start+1,keyseg->length,buff);
1308
if (param->testflag & T_VERBOSE)
1309
printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1310
VOID(putchar('\n'));
1314
if (share->state.header.uniques)
1316
MI_UNIQUEDEF *uniqueinfo;
1317
puts("\nUnique Key Start Len Nullpos Nullbit Type");
1318
for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1319
key < share->state.header.uniques; key++, uniqueinfo++)
1322
char null_bit[8],null_pos[8];
1323
printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1324
for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1328
null_bit[0]=null_pos[0]=0;
1329
if (keyseg->null_bit)
1331
sprintf(null_bit,"%d",keyseg->null_bit);
1332
sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1334
printf("%-7ld%-5d%-9s%-10s%-30s\n",
1335
(long) keyseg->start+1,keyseg->length,
1337
type_names[keyseg->type]);
1342
if (param->verbose > 1)
1344
char null_bit[8],null_pos[8];
1345
printf("\nField Start Length Nullpos Nullbit Type");
1346
if (share->options & HA_OPTION_COMPRESS_RECORD)
1347
printf(" Huff tree Bits");
1348
VOID(putchar('\n'));
1350
for (field=0 ; field < share->base.fields ; field++)
1352
if (share->options & HA_OPTION_COMPRESS_RECORD)
1353
type=share->rec[field].base_type;
1355
type=(enum en_fieldtype) share->rec[field].type;
1356
end=stpcpy(buff,field_pack[type]);
1357
if (share->options & HA_OPTION_COMPRESS_RECORD)
1359
if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1360
end=stpcpy(end,", not_always");
1361
if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1362
end=stpcpy(end,", no empty");
1363
if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1365
sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
1370
stpcpy(buff,buff+2);
1371
int10_to_str((long) share->rec[field].length,length,10);
1372
null_bit[0]=null_pos[0]=0;
1373
if (share->rec[field].null_bit)
1375
sprintf(null_bit,"%d",share->rec[field].null_bit);
1376
sprintf(null_pos,"%d",share->rec[field].null_pos+1);
1378
printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1379
null_pos, null_bit, buff);
1380
if (share->options & HA_OPTION_COMPRESS_RECORD)
1382
if (share->rec[field].huff_tree)
1384
(uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1385
share->rec[field].huff_tree->quick_table_bits);
1387
VOID(putchar('\n'));
1388
start+=share->rec[field].length;
1395
/* Sort records according to one key */
1397
static int mi_sort_records(MI_CHECK *param,
1398
register MI_INFO *info, char * name,
1408
ha_rows old_record_count;
1409
MYISAM_SHARE *share=info->s;
1410
char llbuff[22],llbuff2[22];
1411
SORT_INFO sort_info;
1412
MI_SORT_PARAM sort_param;
1414
memset(&sort_info, 0, sizeof(sort_info));
1415
memset(&sort_param, 0, sizeof(sort_param));
1416
sort_param.sort_info=&sort_info;
1417
sort_info.param=param;
1418
keyinfo= &share->keyinfo[sort_key];
1423
if (! mi_is_key_active(share->state.key_map, sort_key))
1425
mi_check_print_warning(param,
1426
"Can't sort table '%s' on key %d; No such key",
1428
param->error_printed=0;
1429
return(0); /* Nothing to do */
1431
if (share->data_file_type == COMPRESSED_RECORD)
1433
mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
1434
param->error_printed=0;
1435
return(0); /* Nothing to do */
1437
if (!(param->testflag & T_SILENT))
1439
printf("- Sorting records for MyISAM-table '%s'\n",name);
1441
printf("Data records: %9s Deleted: %9s\n",
1442
llstr(info->state->records,llbuff),
1443
llstr(info->state->del,llbuff2));
1445
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1446
return(0); /* Nothing to do */
1448
init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers,
1450
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1451
WRITE_CACHE,share->pack.header_length,1,
1452
MYF(MY_WME | MY_WAIT_IF_FULL)))
1454
info->opt_flag|=WRITE_CACHE_USED;
1456
if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
1458
mi_check_print_error(param,"Not enough memory for key block");
1462
if (!mi_alloc_rec_buff(info, -1, &sort_param.record))
1464
mi_check_print_error(param,"Not enough memory for record");
1467
fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
1468
new_file=my_raid_create(fn_format(param->temp_filename,
1469
param->temp_filename,"",
1471
0,param->tmpfile_createflag,
1472
share->base.raid_type,
1473
share->base.raid_chunks,
1474
share->base.raid_chunksize,
1478
mi_check_print_error(param,"Can't create new tempfile: '%s'",
1479
param->temp_filename);
1482
if (share->pack.header_length)
1483
if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1486
info->rec_cache.file=new_file; /* Use this file for cacheing*/
1489
for (key=0 ; key < share->base.keys ; key++)
1490
share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1492
if (my_pread(share->kfile,(uchar*) temp_buff,
1493
(uint) keyinfo->block_length,
1494
share->state.key_root[sort_key],
1495
MYF(MY_NABP+MY_WME)))
1497
mi_check_print_error(param,"Can't read indexpage from filepos: %s",
1498
(ulong) share->state.key_root[sort_key]);
1502
/* Setup param for sort_write_record */
1503
sort_info.info=info;
1504
sort_info.new_data_file_type=share->data_file_type;
1505
sort_param.fix_datafile=1;
1506
sort_param.master=1;
1507
sort_param.filepos=share->pack.header_length;
1508
old_record_count=info->state->records;
1509
info->state->records=0;
1510
if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1511
info->state->checksum=0;
1513
if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1514
temp_buff, sort_key,new_file,update_index) ||
1515
write_data_suffix(&sort_info,1) ||
1516
flush_io_cache(&info->rec_cache))
1519
if (info->state->records != old_record_count)
1521
mi_check_print_error(param,"found %s of %s records",
1522
llstr(info->state->records,llbuff),
1523
llstr(old_record_count,llbuff2));
1527
VOID(my_close(info->dfile,MYF(MY_WME)));
1528
param->out_flag|=O_NEW_DATA; /* Data in new file */
1529
info->dfile=new_file; /* Use new datafile */
1531
info->state->empty=0;
1532
share->state.dellink= HA_OFFSET_ERROR;
1533
info->state->data_file_length=sort_param.filepos;
1534
share->state.split=info->state->records; /* Only hole records */
1535
share->state.version=(ulong) time((time_t*) 0);
1537
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1539
if (param->testflag & T_WRITE_LOOP)
1541
VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
1546
if (got_error && new_file >= 0)
1548
VOID(end_io_cache(&info->rec_cache));
1549
(void) my_close(new_file,MYF(MY_WME));
1550
(void) my_raid_delete(param->temp_filename, share->base.raid_chunks,
1555
my_afree((uchar*) temp_buff);
1557
my_free(mi_get_rec_buff_ptr(info, sort_param.record),
1558
MYF(MY_ALLOW_ZERO_PTR));
1559
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1560
VOID(end_io_cache(&info->rec_cache));
1561
my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
1563
share->state.sortkey=sort_key;
1564
return(flush_blocks(param, share->key_cache, share->kfile) |
1566
} /* sort_records */
1569
/* Sort records recursive using one index */
1571
static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
1573
my_off_t page, uchar *buff, uint sort_key,
1574
File new_file,bool update_index)
1576
uint nod_flag,used_length,key_length;
1577
uchar *temp_buff,*keypos,*endpos;
1578
my_off_t next_page,rec_pos;
1579
uchar lastkey[MI_MAX_KEY_BUFF];
1581
SORT_INFO *sort_info= sort_param->sort_info;
1582
MI_CHECK *param=sort_info->param;
1584
nod_flag=mi_test_if_nod(buff);
1589
if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
1591
mi_check_print_error(param,"Not Enough memory");
1595
used_length=mi_getint(buff);
1596
keypos=buff+2+nod_flag;
1597
endpos=buff+used_length;
1602
next_page=_mi_kpos(nod_flag,keypos);
1603
if (my_pread(info->s->kfile,(uchar*) temp_buff,
1604
(uint) keyinfo->block_length, next_page,
1605
MYF(MY_NABP+MY_WME)))
1607
mi_check_print_error(param,"Can't read keys from filepos: %s",
1608
llstr(next_page,llbuff));
1611
if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1612
new_file, update_index))
1615
if (keypos >= endpos ||
1616
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1619
rec_pos= _mi_dpos(info,0,lastkey+key_length);
1621
if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1623
mi_check_print_error(param,"%d when reading datafile",my_errno);
1626
if (rec_pos != sort_param->filepos && update_index)
1628
_mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1629
sort_param->filepos);
1630
if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1633
mi_check_print_error(param,"%d when updating key-pointers",my_errno);
1637
if (sort_write_record(sort_param))
1640
/* Clear end of block to get better compression if the table is backuped */
1641
memset(buff+used_length, 0, keyinfo->block_length-used_length);
1642
if (my_pwrite(info->s->kfile,(uchar*) buff,(uint) keyinfo->block_length,
1643
page,param->myf_rw))
1645
mi_check_print_error(param,"%d when updating keyblock",my_errno);
1649
my_afree((uchar*) temp_buff);
1653
my_afree((uchar*) temp_buff);
1655
} /* sort_record_index */
1660
Check if myisamchk was killed by a signal
1661
This is overloaded by other programs that want to be able to abort
1665
static int not_killed= 0;
1667
volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
1669
return ¬_killed; /* always NULL */
1672
/* print warnings and errors */
1675
void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
1676
const char *fmt,...)
1681
VOID(vfprintf(stdout, fmt, args));
1682
VOID(fputc('\n',stdout));
1688
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
1693
if (!param->warning_printed && !param->error_printed)
1695
if (param->testflag & T_SILENT)
1696
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,
1697
param->isam_file_name);
1698
param->out_flag|= O_DATA_LOST;
1700
param->warning_printed=1;
1702
fprintf(stderr,"%s: warning: ",my_progname_short);
1703
VOID(vfprintf(stderr, fmt, args));
1704
VOID(fputc('\n',stderr));
1712
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
1717
if (!param->warning_printed && !param->error_printed)
1719
if (param->testflag & T_SILENT)
1720
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1721
param->out_flag|= O_DATA_LOST;
1723
param->error_printed|=1;
1725
fprintf(stderr,"%s: error: ",my_progname_short);
1726
VOID(vfprintf(stderr, fmt, args));
1727
VOID(fputc('\n',stderr));