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
#include <drizzled/util/test.h>
35
#define my_raid_create(A,B,C,D,E,F,G) my_create(A,B,C,G)
36
#define my_raid_delete(A,B,C) my_delete(A,B)
38
#include "myisamdef.h"
40
static uint32_t decode_bits;
41
static char **default_argv;
42
static const char *load_default_groups[]= { "myisamchk", 0 };
43
static const char *set_collation_name, *opt_tmpdir;
44
static const CHARSET_INFO *set_collation;
45
static long opt_myisam_block_size;
46
static long opt_key_cache_block_size;
47
static const char *my_progname_short;
48
static MY_TMPDIR myisamchk_tmpdir;
50
static const char *type_names[]=
51
{ "impossible","char","binary", "short", "long", "float",
52
"double","number","unsigned short",
53
"unsigned long","int64_t","uint64_t","int24",
54
"uint24","int8","varchar", "varbin","?",
57
static const char *prefix_packed_txt="packed ",
58
*bin_packed_txt="prefix ",
59
*diff_txt="stripped ",
63
static const char *field_pack[]=
64
{"","no endspace", "no prespace",
65
"no zeros", "blob", "constant", "table-lockup",
66
"always zero","varchar","unique-hash","?","?"};
68
static const char *myisam_stats_method_str="nulls_unequal";
70
static void get_options(int *argc,char * * *argv);
71
static void print_version(void);
72
static void usage(void);
73
static int myisamchk(MI_CHECK *param, char *filename);
74
static void descript(MI_CHECK *param, register MI_INFO *info, char * name);
75
static int mi_sort_records(MI_CHECK *param, register MI_INFO *info,
76
char * name, uint32_t sort_key,
77
bool write_info, bool update_index);
78
static int sort_record_index(MI_SORT_PARAM *sort_param, MI_INFO *info,
80
my_off_t page,unsigned char *buff,uint32_t sortkey,
81
File new_file, bool update_index);
87
int main(int argc, char **argv)
91
my_progname_short= my_progname+dirname_length(my_progname);
93
myisamchk_init(&check_param);
94
check_param.opt_lock_memory=1; /* Lock memory if possible */
95
check_param.using_global_keycache = 0;
96
get_options(&argc,(char***) &argv);
97
myisam_quick_table_bits=decode_bits;
101
int new_error=myisamchk(&check_param, *(argv++));
102
if ((check_param.testflag & T_REP_ANY) != T_REP)
103
check_param.testflag&= ~T_REP;
106
if ((check_param.error_printed | check_param.warning_printed) &&
107
(check_param.testflag & T_FORCE_CREATE) &&
108
(!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
111
uint32_t old_testflag=check_param.testflag;
112
if (!(check_param.testflag & T_REP))
113
check_param.testflag|= T_REP_BY_SORT;
114
check_param.testflag&= ~T_EXTEND; /* Don't needed */
115
error|=myisamchk(&check_param, argv[-1]);
116
check_param.testflag= old_testflag;
122
if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
124
puts("\n---------\n");
128
if (check_param.total_files > 1)
129
{ /* Only if descript */
130
char buff[22],buff2[22];
131
if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
132
puts("\n---------\n");
133
printf("\nTotal of all %d MyISAM-files:\nData records: %9s Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
134
llstr(check_param.total_deleted,buff2));
136
free_defaults(default_argv);
137
free_tmpdir(&myisamchk_tmpdir);
138
my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
141
return 0; /* No compiler warning */
146
OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
147
OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE,
148
OPT_KEY_CACHE_BLOCK_SIZE, OPT_MYISAM_BLOCK_SIZE,
149
OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
150
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS,
151
OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD
154
static struct my_option my_long_options[] =
157
"Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
158
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
159
{"block-search", 'b',
160
"No help available.",
161
0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
163
"Make a backup of the .MYD file as 'filename-time.BAK'.",
164
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
165
{"character-sets-dir", OPT_CHARSETS_DIR,
166
"Directory where character sets are.",
167
(char**) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
169
"Check table for errors.",
170
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
171
{"check-only-changed", 'C',
172
"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).",
173
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
174
{"correct-checksum", OPT_CORRECT_CHECKSUM,
175
"Correct checksum information for table.",
176
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
178
"Prints some information about table.",
179
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
180
{"data-file-length", 'D',
181
"Max length of data file (when recreating data-file when it's full).",
182
(char**) &check_param.max_data_file_length,
183
(char**) &check_param.max_data_file_length,
184
0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
185
{"extend-check", 'e',
186
"If used when checking a table, ensure that the table is 100 percent consistent, which will take a long time. If used when repairing a table, try to recover every possible row from the data file. Normally this will also find a lot of garbage rows; Don't use this option with repair if you are not totally desperate.",
187
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
189
"Check only tables that haven't been closed properly. It also applies to other requested actions (e.g. --analyze will be ignored if the table is already analyzed).",
190
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
192
"Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
193
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
195
"Display this help and exit.",
196
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
198
"Display this help and exit.",
199
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
201
"Print statistics information about table that is checked.",
202
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
204
"Tell MyISAM to update only some specific keys. # is a bit mask of which keys to use. This can be used to get faster inserts.",
205
(char**) &check_param.keys_in_use,
206
(char**) &check_param.keys_in_use,
207
0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
208
{"max-record-length", OPT_MAX_RECORD_LENGTH,
209
"Skip rows bigger than this if myisamchk can't allocate memory to hold it",
210
(char**) &check_param.max_record_length,
211
(char**) &check_param.max_record_length,
212
0, GET_ULL, REQUIRED_ARG, INT64_MAX, 0, INT64_MAX, 0, 0, 0},
213
{"medium-check", 'm',
214
"Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
215
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
216
{"quick", 'q', "Faster repair by not modifying the data file.",
217
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
219
"Don't mark table as checked.",
220
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
222
"Can fix almost anything except unique keys that aren't unique.",
223
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
224
{"parallel-recover", 'p',
225
"Same as '-r' but creates all the keys in parallel.",
226
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
227
{"safe-recover", 'o',
228
"Uses old recovery method; Slower than '-r' but can handle a couple of cases where '-r' reports that it can't fix the data file.",
229
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
230
{"sort-recover", 'n',
231
"Force recovering with sorting even if the temporary file was very big.",
232
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
234
{"start-check-pos", OPT_START_CHECK_POS,
235
"No help available.",
236
0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
238
{"set-auto-increment", 'A',
239
"Force auto_increment to start at this or higher value. If no value is given, then sets the next auto_increment value to the highest used value for the auto key + 1.",
240
(char**) &check_param.auto_increment_value,
241
(char**) &check_param.auto_increment_value,
242
0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
243
{"set-collation", OPT_SET_COLLATION,
244
"Change the collation used by the index",
245
(char**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
246
{"set-variable", 'O',
247
"Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
248
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
250
"Only print errors. One can use two -s to make myisamchk very silent.",
251
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
253
"Sort index blocks. This speeds up 'read-next' in applications.",
254
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
255
{"sort-records", 'R',
256
"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!)",
257
(char**) &check_param.opt_sort_key,
258
(char**) &check_param.opt_sort_key,
259
0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
261
"Path for temporary files.",
262
(char**) &opt_tmpdir,
263
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
264
{"update-state", 'U',
265
"Mark tables as crashed if any errors were found.",
266
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
268
"Unpack file packed with myisampack.",
269
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
271
"Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
272
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
274
"Print version and exit.",
275
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
277
"Wait if table is locked.",
278
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
279
{ "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
280
(char**) &check_param.use_buffers, (char**) &check_param.use_buffers, 0,
281
GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
282
INT32_MAX, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
283
{ "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "",
284
(char**) &opt_key_cache_block_size,
285
(char**) &opt_key_cache_block_size, 0,
286
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
287
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
288
{ "myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "",
289
(char**) &opt_myisam_block_size, (char**) &opt_myisam_block_size, 0,
290
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
291
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
292
{ "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
293
(char**) &check_param.read_buffer_length,
294
(char**) &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
295
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
296
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
297
{ "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
298
(char**) &check_param.write_buffer_length,
299
(char**) &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
300
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
301
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
302
{ "sort_buffer_size", OPT_SORT_BUFFER_SIZE, "",
303
(char**) &check_param.sort_buffer_length,
304
(char**) &check_param.sort_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
305
(long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
306
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
307
{ "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
308
(char**) &check_param.sort_key_blocks,
309
(char**) &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
310
BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
311
{ "decode_bits", OPT_DECODE_BITS, "", (char**) &decode_bits,
312
(char**) &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
313
{"stats_method", OPT_STATS_METHOD,
314
"Specifies how index statistics collection code should treat NULLs. "
315
"Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
316
"\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
317
(char**) &myisam_stats_method_str, (char**) &myisam_stats_method_str, 0,
318
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
319
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
323
static void print_version(void)
325
printf("%s Ver 2.7 for %s at %s\n", my_progname, SYSTEM_TYPE,
330
static void usage(void)
333
puts("By Monty, for your professional use");
334
puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
335
puts("Description, check and repair of MyISAM tables.");
336
puts("Used without options all tables on the command will be checked for errors");
337
printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname_short);
338
printf("\nGlobal options:\n");
340
-?, --help Display this help and exit.\n\
341
-O, --set-variable var=option.\n\
342
Change the value of a variable. Please note that\n\
343
this option is deprecated; you can set variables\n\
344
directly with '--variable-name=value'.\n\
345
-t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
346
specified, separated by ");
347
#if defined( __WIN__)
348
printf("semicolon (;)");
352
printf(", they will be used\n\
353
in a round-robin fashion.\n\
354
-s, --silent Only print errors. One can use two -s to make\n\
355
myisamchk very silent.\n\
356
-v, --verbose Print more information. This can be used with\n\
357
--description and --check. Use many -v for more verbosity.\n\
358
-V, --version Print version and exit.\n\
359
-w, --wait Wait if table is locked.\n\n");
361
puts(" --start-check-pos=# Start reading file at given offset.\n");
364
puts("Check options (check is the default action for myisamchk):\n\
365
-c, --check Check table for errors.\n\
366
-e, --extend-check Check the table VERY throughly. Only use this in\n\
367
extreme cases as myisamchk should normally be able to\n\
368
find out if the table is ok even without this switch.\n\
369
-F, --fast Check only tables that haven't been closed properly.\n\
370
-C, --check-only-changed\n\
371
Check only tables that have changed since last check.\n\
372
-f, --force Restart with '-r' if there are any errors in the table.\n\
373
States will be updated as with '--update-state'.\n\
374
-i, --information Print statistics information about table that is checked.\n\
375
-m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
376
all errors. Should be good enough for most cases.\n\
377
-U --update-state Mark tables as crashed if you find any errors.\n\
378
-T, --read-only Don't mark table as checked.\n");
380
puts("Repair options (When using '-r' or '-o'):\n\
381
-B, --backup Make a backup of the .MYD file as 'filename-time.BAK'.\n\
382
--correct-checksum Correct checksum information for table.\n\
383
-D, --data-file-length=# Max length of data file (when recreating data\n\
384
file when it's full).\n\
385
-e, --extend-check Try to recover every possible row from the data file\n\
386
Normally this will also find a lot of garbage rows;\n\
387
Don't use this option if you are not totally desperate.\n\
388
-f, --force Overwrite old temporary files.\n\
389
-k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\
390
bit mask of which keys to use. This can be used to\n\
391
get faster inserts.\n\
392
--max-record-length=#\n\
393
Skip rows bigger than this if myisamchk can't allocate\n\
394
memory to hold it.\n\
395
-r, --recover Can fix almost anything except unique keys that aren't\n\
397
-n, --sort-recover Forces recovering with sorting even if the temporary\n\
398
file would be very big.\n\
399
-p, --parallel-recover\n\
400
Uses the same technique as '-r' and '-n', but creates\n\
401
all the keys in parallel, in different threads.\n\
402
-o, --safe-recover Uses old recovery method; Slower than '-r' but can\n\
403
handle a couple of cases where '-r' reports that it\n\
404
can't fix the data file.\n\
405
--character-sets-dir=...\n\
406
Directory where character sets are.\n\
407
--set-collation=name\n\
408
Change the collation used by the index.\n\
409
-q, --quick Faster repair by not modifying the data file.\n\
410
One can give a second '-q' to force myisamchk to\n\
411
modify the original datafile in case of duplicate keys.\n\
412
NOTE: Tables where the data file is currupted can't be\n\
413
fixed with this option.\n\
414
-u, --unpack Unpack file packed with myisampack.\n\
417
puts("Other actions:\n\
418
-a, --analyze Analyze distribution of keys. Will make some joins in\n\
419
MySQL faster. You can check the calculated distribution\n\
420
by using '--description --verbose table_name'.\n\
421
--stats_method=name Specifies how index statistics collection code should\n\
422
treat NULLs. Possible values of name are \"nulls_unequal\"\n\
423
(default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
424
\"nulls_ignored\".\n\
425
-d, --description Prints some information about table.\n\
426
-A, --set-auto-increment[=value]\n\
427
Force auto_increment to start at this or higher value\n\
428
If no value is given, then sets the next auto_increment\n\
429
value to the highest used value for the auto key + 1.\n\
430
-S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
432
-R, --sort-records=#\n\
433
Sort records according to an index. This makes your\n\
434
data much more localized and may speed up things\n\
435
(It may be VERY slow to do a sort the first time!).\n\
436
-b, --block-search=#\n\
437
Find a record, a block at given offset belongs to.");
439
print_defaults("my", load_default_groups);
440
my_print_variables(my_long_options);
443
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
444
"nulls_ignored", NULL};
445
TYPELIB myisam_stats_method_typelib= {
446
array_elements(myisam_stats_method_names) - 1, "",
447
myisam_stats_method_names, NULL};
452
get_one_option(int optid,
453
const struct my_option *opt __attribute__((unused)),
458
if (argument == disabled_my_option)
459
check_param.testflag&= ~T_STATISTICS;
461
check_param.testflag|= T_STATISTICS;
465
check_param.auto_increment_value= strtoull(argument, NULL, 0);
467
check_param.auto_increment_value= 0; /* Set to max used value */
468
check_param.testflag|= T_AUTO_INC;
471
check_param.search_after_block= strtoul(argument, NULL, 10);
474
if (argument == disabled_my_option)
475
check_param.testflag&= ~T_BACKUP_DATA;
477
check_param.testflag|= T_BACKUP_DATA;
480
if (argument == disabled_my_option)
481
check_param.testflag&= ~T_CHECK;
483
check_param.testflag|= T_CHECK;
486
if (argument == disabled_my_option)
487
check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
489
check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
492
check_param.max_data_file_length=strtoll(argument, NULL, 10);
494
case 's': /* silent */
495
if (argument == disabled_my_option)
496
check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
499
if (check_param.testflag & T_SILENT)
500
check_param.testflag|= T_VERY_SILENT;
501
check_param.testflag|= T_SILENT;
502
check_param.testflag&= ~T_WRITE_LOOP;
506
if (argument == disabled_my_option)
507
check_param.testflag&= ~T_WAIT_FOREVER;
509
check_param.testflag|= T_WAIT_FOREVER;
511
case 'd': /* description if isam-file */
512
if (argument == disabled_my_option)
513
check_param.testflag&= ~T_DESCRIPT;
515
check_param.testflag|= T_DESCRIPT;
517
case 'e': /* extend check */
518
if (argument == disabled_my_option)
519
check_param.testflag&= ~T_EXTEND;
521
check_param.testflag|= T_EXTEND;
524
if (argument == disabled_my_option)
525
check_param.testflag&= ~T_INFO;
527
check_param.testflag|= T_INFO;
530
if (argument == disabled_my_option)
532
check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
533
check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
537
check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
538
check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
542
if (argument == disabled_my_option)
543
check_param.testflag&= ~T_FAST;
545
check_param.testflag|= T_FAST;
548
check_param.keys_in_use= (uint64_t) strtoll(argument, NULL, 10);
551
if (argument == disabled_my_option)
552
check_param.testflag&= ~T_MEDIUM;
554
check_param.testflag|= T_MEDIUM; /* Medium check */
556
case 'r': /* Repair table */
557
check_param.testflag&= ~T_REP_ANY;
558
if (argument != disabled_my_option)
559
check_param.testflag|= T_REP_BY_SORT;
562
check_param.testflag&= ~T_REP_ANY;
563
if (argument != disabled_my_option)
564
check_param.testflag|= T_REP_PARALLEL;
567
check_param.testflag&= ~T_REP_ANY;
568
check_param.force_sort= 0;
569
if (argument != disabled_my_option)
571
check_param.testflag|= T_REP;
572
my_disable_async_io= 1; /* More safety */
576
check_param.testflag&= ~T_REP_ANY;
577
if (argument == disabled_my_option)
578
check_param.force_sort= 0;
581
check_param.testflag|= T_REP_BY_SORT;
582
check_param.force_sort= 1;
586
if (argument == disabled_my_option)
587
check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
589
check_param.testflag|=
590
(check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
593
if (argument == disabled_my_option)
594
check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
596
check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
598
case 'v': /* Verbose */
599
if (argument == disabled_my_option)
601
check_param.testflag&= ~T_VERBOSE;
602
check_param.verbose=0;
606
check_param.testflag|= T_VERBOSE;
607
check_param.verbose++;
610
case 'R': /* Sort records */
611
if (argument == disabled_my_option)
612
check_param.testflag&= ~T_SORT_RECORDS;
615
check_param.testflag|= T_SORT_RECORDS;
616
check_param.opt_sort_key= (uint) atoi(argument) - 1;
617
if (check_param.opt_sort_key >= MI_MAX_KEY)
620
"The value of the sort key is bigger than max key: %d.\n",
626
case 'S': /* Sort index */
627
if (argument == disabled_my_option)
628
check_param.testflag&= ~T_SORT_INDEX;
630
check_param.testflag|= T_SORT_INDEX;
633
if (argument == disabled_my_option)
634
check_param.testflag&= ~T_READONLY;
636
check_param.testflag|= T_READONLY;
639
if (argument == disabled_my_option)
640
check_param.testflag&= ~T_UPDATE_STATE;
642
check_param.testflag|= T_UPDATE_STATE;
647
case OPT_CORRECT_CHECKSUM:
648
if (argument == disabled_my_option)
649
check_param.testflag&= ~T_CALC_CHECKSUM;
651
check_param.testflag|= T_CALC_CHECKSUM;
653
case OPT_STATS_METHOD:
656
enum_mi_stats_method method_conv;
657
myisam_stats_method_str= argument;
658
if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
660
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
665
method_conv= MI_STATS_METHOD_NULLS_EQUAL;
668
method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
671
method_conv= MI_STATS_METHOD_IGNORE_NULLS;
673
default: assert(0); /* Impossible */
675
check_param.stats_method= method_conv;
678
#ifdef DEBUG /* Only useful if debugging */
679
case OPT_START_CHECK_POS:
680
check_param.start_check_pos= strtoull(argument, NULL, 0);
684
my_print_help(my_long_options);
694
static void get_options(register int *argc,register char ***argv)
698
load_defaults("my", load_default_groups, argc, argv);
700
if (isatty(fileno(stdout)))
701
check_param.testflag|=T_WRITE_LOOP;
703
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
706
/* If using repair, then update checksum if one uses --update-state */
707
if ((check_param.testflag & T_UPDATE_STATE) &&
708
(check_param.testflag & T_REP_ANY))
709
check_param.testflag|= T_CALC_CHECKSUM;
717
if ((check_param.testflag & T_UNPACK) &&
718
(check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
721
"%s: --unpack can't be used with --quick or --sort-records\n",
725
if ((check_param.testflag & T_READONLY) &&
726
(check_param.testflag &
727
(T_REP_ANY | T_STATISTICS | T_AUTO_INC |
728
T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
731
"%s: Can't use --readonly when repairing or sorting\n",
736
if (init_tmpdir(&myisamchk_tmpdir, opt_tmpdir))
739
check_param.tmpdir=&myisamchk_tmpdir;
740
check_param.key_cache_block_size= opt_key_cache_block_size;
742
if (set_collation_name)
743
if (!(set_collation= get_charset_by_name(set_collation_name,
747
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
754
static int myisamchk(MI_CHECK *param, char * filename)
756
int error,lock_type,recreate;
757
int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
758
uint32_t raid_chunks;
761
char llbuff[22],llbuff2[22];
762
bool state_updated=0;
765
param->out_flag=error=param->warning_printed=param->error_printed=
768
param->isam_file_name=filename; /* For error messages */
769
if (!(info=mi_open(filename,
770
(param->testflag & (T_DESCRIPT | T_READONLY)) ?
773
((param->testflag & T_WAIT_FOREVER) ?
774
HA_OPEN_WAIT_IF_LOCKED :
775
(param->testflag & T_DESCRIPT) ?
776
HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
778
/* Avoid twice printing of isam file name */
779
param->error_printed=1;
782
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);
784
case HA_ERR_NOT_A_TABLE:
785
mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
787
case HA_ERR_CRASHED_ON_USAGE:
788
mi_check_print_error(param,"'%s' is marked as crashed",filename);
790
case HA_ERR_CRASHED_ON_REPAIR:
791
mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
793
case HA_ERR_OLD_FILE:
794
mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
796
case HA_ERR_END_OF_FILE:
797
mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
800
mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
803
mi_check_print_error(param,"File '%s' doesn't exist",filename);
806
mi_check_print_error(param,"You don't have permission to use '%s'",filename);
809
mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
816
share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
817
share->tot_locks-= share->r_locks;
819
raid_chunks=share->base.raid_chunks;
822
Skip the checking of the file if:
823
We are using --fast and the table is closed properly
824
We are using --check-only-changed-tables and the table hasn't changed
826
if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
828
bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
830
if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
831
((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
832
STATE_CRASHED_ON_REPAIR) ||
833
!(param->testflag & T_CHECK_ONLY_CHANGED))))
836
if (info->s->base.keys && info->state->records)
838
if ((param->testflag & T_STATISTICS) &&
839
(share->state.changed & STATE_NOT_ANALYZED))
841
if ((param->testflag & T_SORT_INDEX) &&
842
(share->state.changed & STATE_NOT_SORTED_PAGES))
844
if ((param->testflag & T_REP_BY_SORT) &&
845
(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
848
if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
849
(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
850
STATE_CRASHED_ON_REPAIR)))
854
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
855
printf("MyISAM file: %s is already checked\n",filename);
858
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
865
if ((param->testflag & (T_REP_ANY | T_STATISTICS |
866
T_SORT_RECORDS | T_SORT_INDEX)) &&
867
(((param->testflag & T_UNPACK) &&
868
share->data_file_type == COMPRESSED_RECORD) ||
869
mi_uint2korr(share->state.header.state_info_length) !=
870
MI_STATE_INFO_SIZE ||
871
mi_uint2korr(share->state.header.base_info_length) !=
873
mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
874
~share->state.key_map) ||
875
test_if_almost_full(info) ||
876
info->s->state.header.file_version[3] != myisam_file_magic[3] ||
878
set_collation->number != share->state.header.language) ||
879
myisam_block_size != MI_KEY_BLOCK_LENGTH))
882
param->language= set_collation->number;
883
if (recreate_table(param, &info,filename))
886
"MyISAM-table '%s' is not fixed because of errors\n",
891
if (!(param->testflag & T_REP_ANY))
893
param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
894
if (!(param->testflag & T_SILENT))
895
printf("- '%s' has old table-format. Recreating index\n",filename);
899
share->tot_locks-= share->r_locks;
903
if (param->testflag & T_DESCRIPT)
905
param->total_files++;
906
param->total_records+=info->state->records;
907
param->total_deleted+=info->state->del;
908
descript(param, info, filename);
913
if (!(param->testflag & T_READONLY))
914
lock_type = F_WRLCK; /* table is changed */
917
if (info->lock_type == F_RDLCK)
918
info->lock_type=F_UNLCK; /* Read only table */
919
if (_mi_readinfo(info,lock_type,0))
921
mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
923
param->error_printed=0;
927
_mi_readinfo() has locked the table.
928
We mark the table as locked (without doing file locks) to be able to
929
use functions that only works on locked tables (like row caching).
931
mi_lock_database(info, F_EXTRA_LCK);
932
datafile=info->dfile;
934
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
936
if (param->testflag & T_REP_ANY)
938
uint64_t tmp=share->state.key_map;
939
mi_copy_keys_active(share->state.key_map, share->base.keys,
941
if (tmp != share->state.key_map)
942
info->update|=HA_STATE_CHANGED;
944
if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
946
if (param->testflag & T_FORCE_CREATE)
949
mi_check_print_info(param,"Creating new data file\n");
954
mi_check_print_error(param,
955
"Quick-recover aborted; Run recovery without switch 'q'");
960
if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
961
(mi_is_any_key_active(share->state.key_map) ||
962
(rep_quick && !param->keys_in_use && !recreate)) &&
963
mi_test_if_sort_rep(info, info->state->records,
964
info->s->state.key_map,
967
if (param->testflag & T_REP_BY_SORT)
968
error=mi_repair_by_sort(param,info,filename,rep_quick);
970
error=mi_repair_parallel(param,info,filename,rep_quick);
973
else if (param->testflag & T_REP_ANY)
974
error=mi_repair(param, info,filename,rep_quick);
976
if (!error && param->testflag & T_SORT_RECORDS)
980
We can't update the index in mi_sort_records if we have a
981
prefix compressed or fulltext index
984
for (key=0 ; key < share->base.keys; key++)
985
if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY))
988
error=mi_sort_records(param,info,filename,param->opt_sort_key,
989
/* what is the following parameter for ? */
990
(bool) !(param->testflag & T_REP),
992
datafile=info->dfile; /* This is now locked */
993
if (!error && !update_index)
996
puts("Table had a compressed index; We must now recreate the index");
997
error=mi_repair_by_sort(param,info,filename,1);
1000
if (!error && param->testflag & T_SORT_INDEX)
1001
error=mi_sort_index(param,info,filename);
1003
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1004
STATE_CRASHED_ON_REPAIR);
1006
mi_mark_crashed(info);
1008
else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
1010
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1011
printf("Checking MyISAM file: %s\n",filename);
1012
if (!(param->testflag & T_SILENT))
1013
printf("Data records: %7s Deleted blocks: %7s\n",
1014
llstr(info->state->records,llbuff),
1015
llstr(info->state->del,llbuff2));
1016
error =chk_status(param,info);
1017
mi_intersect_keys_active(share->state.key_map, param->keys_in_use);
1018
error =chk_size(param,info);
1019
if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1020
error|=chk_del(param, info,param->testflag);
1021
if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1022
!param->start_check_pos)))
1024
error|=chk_key(param, info);
1025
if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1026
error=update_state_info(param, info,
1027
((param->testflag & T_STATISTICS) ?
1029
((param->testflag & T_AUTO_INC) ?
1030
UPDATE_AUTO_INC : 0));
1032
if ((!rep_quick && !error) ||
1033
!(param->testflag & (T_FAST | T_FORCE_CREATE)))
1035
if (param->testflag & (T_EXTEND | T_MEDIUM))
1036
init_key_cache(dflt_key_cache,opt_key_cache_block_size,
1037
param->use_buffers, 0, 0);
1038
init_io_cache(¶m->read_cache,datafile,
1039
(uint) param->read_buffer_length,
1041
(param->start_check_pos ?
1042
param->start_check_pos :
1043
share->pack.header_length),
1047
if ((info->s->options & (HA_OPTION_PACK_RECORD |
1048
HA_OPTION_COMPRESS_RECORD)) ||
1049
(param->testflag & (T_EXTEND | T_MEDIUM)))
1050
error|=chk_data_link(param, info, param->testflag & T_EXTEND);
1051
error|=flush_blocks(param, share->key_cache, share->kfile);
1052
end_io_cache(¶m->read_cache);
1056
if ((share->state.changed & STATE_CHANGED) &&
1057
(param->testflag & T_UPDATE_STATE))
1058
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1059
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1060
STATE_CRASHED_ON_REPAIR);
1062
else if (!mi_is_crashed(info) &&
1063
(param->testflag & T_UPDATE_STATE))
1064
{ /* Mark crashed */
1065
mi_mark_crashed(info);
1066
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1070
if ((param->testflag & T_AUTO_INC) ||
1071
((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1072
update_auto_increment_key(param, info,
1073
(bool) !test(param->testflag & T_AUTO_INC));
1075
if (!(param->testflag & T_DESCRIPT))
1077
if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1078
error|=update_state_info(param, info,
1080
(((param->testflag & T_REP_ANY) ?
1082
(state_updated ? UPDATE_STAT : 0) |
1083
((param->testflag & T_SORT_RECORDS) ?
1085
info->update&= ~HA_STATE_CHANGED;
1087
mi_lock_database(info, F_UNLCK);
1091
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
1096
if (param->out_flag & O_NEW_DATA)
1097
error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1099
((param->testflag & T_BACKUP_DATA) ?
1100
MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1101
if (param->out_flag & O_NEW_INDEX)
1102
error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1105
fflush(stdout); fflush(stderr);
1106
if (param->error_printed)
1108
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1111
"MyISAM-table '%s' is not fixed because of errors\n",
1113
if (param->testflag & T_REP_ANY)
1115
"Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n");
1117
else if (!(param->error_printed & 2) &&
1118
!(param->testflag & T_FORCE_CREATE))
1120
"MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
1123
else if (param->warning_printed &&
1124
! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1126
fprintf(stderr, "MyISAM-table '%s' is usable but should be fixed\n",
1133
/* Write info about table */
1135
static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
1137
uint32_t key,keyseg_nr,field,start;
1138
register MI_KEYDEF *keyinfo;
1139
register HA_KEYSEG *keyseg;
1140
register const char *text;
1141
char buff[160],length[10],*pos,*end;
1142
enum en_fieldtype type;
1143
MYISAM_SHARE *share=info->s;
1144
char llbuff[22],llbuff2[22];
1146
printf("\nMyISAM file: %s\n",name);
1147
fputs("Record format: ",stdout);
1148
if (share->options & HA_OPTION_COMPRESS_RECORD)
1150
else if (share->options & HA_OPTION_PACK_RECORD)
1153
puts("Fixed length");
1154
printf("Character set: %s (%d)\n",
1155
get_charset_name(share->state.header.language),
1156
share->state.header.language);
1158
if (param->testflag & T_VERBOSE)
1160
printf("File-version: %d\n",
1161
(int) share->state.header.file_version[3]);
1162
if (share->state.create_time)
1164
get_date(buff,1,share->state.create_time);
1165
printf("Creation time: %s\n",buff);
1167
if (share->state.check_time)
1169
get_date(buff,1,share->state.check_time);
1170
printf("Recover time: %s\n",buff);
1173
if (share->state.changed & STATE_CRASHED)
1174
my_stpcpy(buff,"crashed");
1177
if (share->state.open_count)
1178
pos=my_stpcpy(pos,"open,");
1179
if (share->state.changed & STATE_CHANGED)
1180
pos=my_stpcpy(pos,"changed,");
1182
pos=my_stpcpy(pos,"checked,");
1183
if (!(share->state.changed & STATE_NOT_ANALYZED))
1184
pos=my_stpcpy(pos,"analyzed,");
1185
if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1186
pos=my_stpcpy(pos,"optimized keys,");
1187
if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1188
pos=my_stpcpy(pos,"sorted index pages,");
1189
pos[-1]=0; /* Remove extra ',' */
1191
printf("Status: %s\n",buff);
1192
if (share->base.auto_key)
1194
printf("Auto increment key: %13d Last value: %13s\n",
1195
share->base.auto_key,
1196
llstr(share->state.auto_increment,llbuff));
1198
if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1199
printf("Checksum: %23s\n",llstr(info->state->checksum,llbuff));
1201
if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1202
printf("Keys are only flushed at close\n");
1205
printf("Data records: %13s Deleted blocks: %13s\n",
1206
llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1207
if (param->testflag & T_SILENT)
1208
return; /* This is enough */
1210
if (param->testflag & T_VERBOSE)
1213
printf("Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
1215
printf("Datafile parts: %13s Deleted data: %13s\n",
1216
llstr(share->state.split,llbuff),
1217
llstr(info->state->empty,llbuff2));
1218
printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
1219
share->rec_reflength,share->base.key_reflength);
1220
printf("Datafile length: %13s Keyfile length: %13s\n",
1221
llstr(info->state->data_file_length,llbuff),
1222
llstr(info->state->key_file_length,llbuff2));
1224
if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1225
puts("This is a one-record table");
1228
if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1229
share->base.max_key_file_length != HA_OFFSET_ERROR)
1230
printf("Max datafile length: %13s Max keyfile length: %13s\n",
1231
llstr(share->base.max_data_file_length-1,llbuff),
1232
llstr(share->base.max_key_file_length-1,llbuff2));
1236
printf("Recordlength: %13d\n",(int) share->base.pack_reclength);
1237
if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1239
int64_t2str(share->state.key_map,buff,2);
1240
printf("Using only keys '%s' of %d possibly keys\n",
1241
buff, share->base.keys);
1243
puts("\ntable description:");
1244
printf("Key Start Len Index Type");
1245
if (param->testflag & T_VERBOSE)
1246
printf(" Rec/key Root Blocksize");
1249
for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1250
key < share->base.keys;
1253
keyseg=keyinfo->seg;
1254
if (keyinfo->flag & HA_NOSAME) text="unique ";
1255
else text="multip.";
1258
if (keyseg->flag & HA_REVERSE_SORT)
1260
pos=my_stpcpy(pos,type_names[keyseg->type]);
1263
if (keyinfo->flag & HA_PACK_KEY)
1264
pos=my_stpcpy(pos,prefix_packed_txt);
1265
if (keyinfo->flag & HA_BINARY_PACK_KEY)
1266
pos=my_stpcpy(pos,bin_packed_txt);
1267
if (keyseg->flag & HA_SPACE_PACK)
1268
pos=my_stpcpy(pos,diff_txt);
1269
if (keyseg->flag & HA_BLOB_PART)
1270
pos=my_stpcpy(pos,blob_txt);
1271
if (keyseg->flag & HA_NULL_PART)
1272
pos=my_stpcpy(pos,null_txt);
1275
printf("%-4d%-6ld%-3d %-8s%-21s",
1276
key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1277
if (share->state.key_root[key] != HA_OFFSET_ERROR)
1278
llstr(share->state.key_root[key],buff);
1281
if (param->testflag & T_VERBOSE)
1282
printf("%11lu %12s %10d",
1283
share->state.rec_per_key_part[keyseg_nr++],
1284
buff,keyinfo->block_length);
1286
while ((++keyseg)->type != HA_KEYTYPE_END)
1289
if (keyseg->flag & HA_REVERSE_SORT)
1291
pos=my_stpcpy(pos,type_names[keyseg->type]);
1293
if (keyseg->flag & HA_SPACE_PACK)
1294
pos=my_stpcpy(pos,diff_txt);
1295
if (keyseg->flag & HA_BLOB_PART)
1296
pos=my_stpcpy(pos,blob_txt);
1297
if (keyseg->flag & HA_NULL_PART)
1298
pos=my_stpcpy(pos,null_txt);
1300
printf(" %-6ld%-3d %-21s",
1301
(long) keyseg->start+1,keyseg->length,buff);
1302
if (param->testflag & T_VERBOSE)
1303
printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1308
if (share->state.header.uniques)
1310
MI_UNIQUEDEF *uniqueinfo;
1311
puts("\nUnique Key Start Len Nullpos Nullbit Type");
1312
for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1313
key < share->state.header.uniques; key++, uniqueinfo++)
1316
char null_bit[8],null_pos[8];
1317
printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1318
for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1322
null_bit[0]=null_pos[0]=0;
1323
if (keyseg->null_bit)
1325
sprintf(null_bit,"%d",keyseg->null_bit);
1326
sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1328
printf("%-7ld%-5d%-9s%-10s%-30s\n",
1329
(long) keyseg->start+1,keyseg->length,
1331
type_names[keyseg->type]);
1336
if (param->verbose > 1)
1338
char null_bit[8],null_pos[8];
1339
printf("\nField Start Length Nullpos Nullbit Type");
1340
if (share->options & HA_OPTION_COMPRESS_RECORD)
1341
printf(" Huff tree Bits");
1344
for (field=0 ; field < share->base.fields ; field++)
1346
if (share->options & HA_OPTION_COMPRESS_RECORD)
1347
type=share->rec[field].base_type;
1349
type=(enum en_fieldtype) share->rec[field].type;
1350
end=my_stpcpy(buff,field_pack[type]);
1351
if (share->options & HA_OPTION_COMPRESS_RECORD)
1353
if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1354
end=my_stpcpy(end,", not_always");
1355
if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1356
end=my_stpcpy(end,", no empty");
1357
if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1359
sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
1360
end= strchr(end, '\0');
1364
my_stpcpy(buff,buff+2);
1365
int10_to_str((long) share->rec[field].length,length,10);
1366
null_bit[0]=null_pos[0]=0;
1367
if (share->rec[field].null_bit)
1369
sprintf(null_bit,"%d",share->rec[field].null_bit);
1370
sprintf(null_pos,"%d",share->rec[field].null_pos+1);
1372
printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1373
null_pos, null_bit, buff);
1374
if (share->options & HA_OPTION_COMPRESS_RECORD)
1376
if (share->rec[field].huff_tree)
1378
(uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1379
share->rec[field].huff_tree->quick_table_bits);
1382
start+=share->rec[field].length;
1389
/* Sort records according to one key */
1391
static int mi_sort_records(MI_CHECK *param,
1392
register MI_INFO *info, char * name,
1401
unsigned char *temp_buff;
1402
ha_rows old_record_count;
1403
MYISAM_SHARE *share=info->s;
1404
char llbuff[22],llbuff2[22];
1405
SORT_INFO sort_info;
1406
MI_SORT_PARAM sort_param;
1408
memset(&sort_info, 0, sizeof(sort_info));
1409
memset(&sort_param, 0, sizeof(sort_param));
1410
sort_param.sort_info=&sort_info;
1411
sort_info.param=param;
1412
keyinfo= &share->keyinfo[sort_key];
1417
if (! mi_is_key_active(share->state.key_map, sort_key))
1419
mi_check_print_warning(param,
1420
"Can't sort table '%s' on key %d; No such key",
1422
param->error_printed=0;
1423
return(0); /* Nothing to do */
1425
if (share->data_file_type == COMPRESSED_RECORD)
1427
mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
1428
param->error_printed=0;
1429
return(0); /* Nothing to do */
1431
if (!(param->testflag & T_SILENT))
1433
printf("- Sorting records for MyISAM-table '%s'\n",name);
1435
printf("Data records: %9s Deleted: %9s\n",
1436
llstr(info->state->records,llbuff),
1437
llstr(info->state->del,llbuff2));
1439
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1440
return(0); /* Nothing to do */
1442
init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers,
1444
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1445
WRITE_CACHE,share->pack.header_length,1,
1446
MYF(MY_WME | MY_WAIT_IF_FULL)))
1448
info->opt_flag|=WRITE_CACHE_USED;
1450
if (!(temp_buff=(unsigned char*) my_alloca((uint) keyinfo->block_length)))
1452
mi_check_print_error(param,"Not enough memory for key block");
1456
if (!mi_alloc_rec_buff(info, -1, &sort_param.record))
1458
mi_check_print_error(param,"Not enough memory for record");
1461
fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
1462
new_file=my_raid_create(fn_format(param->temp_filename,
1463
param->temp_filename,"",
1465
0,param->tmpfile_createflag,
1466
share->base.raid_type,
1467
share->base.raid_chunks,
1468
share->base.raid_chunksize,
1472
mi_check_print_error(param,"Can't create new tempfile: '%s'",
1473
param->temp_filename);
1476
if (share->pack.header_length)
1477
if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1480
info->rec_cache.file=new_file; /* Use this file for cacheing*/
1483
for (key=0 ; key < share->base.keys ; key++)
1484
share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1486
if (my_pread(share->kfile,(unsigned char*) temp_buff,
1487
(uint) keyinfo->block_length,
1488
share->state.key_root[sort_key],
1489
MYF(MY_NABP+MY_WME)))
1491
mi_check_print_error(param,"Can't read indexpage from filepos: %s",
1492
(ulong) share->state.key_root[sort_key]);
1496
/* Setup param for sort_write_record */
1497
sort_info.info=info;
1498
sort_info.new_data_file_type=share->data_file_type;
1499
sort_param.fix_datafile=1;
1500
sort_param.master=1;
1501
sort_param.filepos=share->pack.header_length;
1502
old_record_count=info->state->records;
1503
info->state->records=0;
1504
if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1505
info->state->checksum=0;
1507
if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1508
temp_buff, sort_key,new_file,update_index) ||
1509
write_data_suffix(&sort_info,1) ||
1510
flush_io_cache(&info->rec_cache))
1513
if (info->state->records != old_record_count)
1515
mi_check_print_error(param,"found %s of %s records",
1516
llstr(info->state->records,llbuff),
1517
llstr(old_record_count,llbuff2));
1521
my_close(info->dfile,MYF(MY_WME));
1522
param->out_flag|=O_NEW_DATA; /* Data in new file */
1523
info->dfile=new_file; /* Use new datafile */
1525
info->state->empty=0;
1526
share->state.dellink= HA_OFFSET_ERROR;
1527
info->state->data_file_length=sort_param.filepos;
1528
share->state.split=info->state->records; /* Only hole records */
1529
share->state.version=(ulong) time((time_t*) 0);
1531
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1533
if (param->testflag & T_WRITE_LOOP)
1535
fputs(" \r",stdout); fflush(stdout);
1540
if (got_error && new_file >= 0)
1542
end_io_cache(&info->rec_cache);
1543
(void) my_close(new_file,MYF(MY_WME));
1544
(void) my_raid_delete(param->temp_filename, share->base.raid_chunks,
1549
my_afree((unsigned char*) temp_buff);
1551
void * rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
1552
if (rec_buff_ptr != NULL)
1555
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1556
end_io_cache(&info->rec_cache);
1557
free(sort_info.buff);
1559
share->state.sortkey=sort_key;
1560
return(flush_blocks(param, share->key_cache, share->kfile) |
1562
} /* sort_records */
1565
/* Sort records recursive using one index */
1567
static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
1569
my_off_t page, unsigned char *buff, uint32_t sort_key,
1570
File new_file,bool update_index)
1572
uint nod_flag,used_length,key_length;
1573
unsigned char *temp_buff,*keypos,*endpos;
1574
my_off_t next_page,rec_pos;
1575
unsigned char lastkey[MI_MAX_KEY_BUFF];
1577
SORT_INFO *sort_info= sort_param->sort_info;
1578
MI_CHECK *param=sort_info->param;
1580
nod_flag=mi_test_if_nod(buff);
1585
if (!(temp_buff=(unsigned char*) my_alloca((uint) keyinfo->block_length)))
1587
mi_check_print_error(param,"Not Enough memory");
1591
used_length=mi_getint(buff);
1592
keypos=buff+2+nod_flag;
1593
endpos=buff+used_length;
1598
next_page=_mi_kpos(nod_flag,keypos);
1599
if (my_pread(info->s->kfile,(unsigned char*) temp_buff,
1600
(uint) keyinfo->block_length, next_page,
1601
MYF(MY_NABP+MY_WME)))
1603
mi_check_print_error(param,"Can't read keys from filepos: %s",
1604
llstr(next_page,llbuff));
1607
if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1608
new_file, update_index))
1611
if (keypos >= endpos ||
1612
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1615
rec_pos= _mi_dpos(info,0,lastkey+key_length);
1617
if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1619
mi_check_print_error(param,"%d when reading datafile",my_errno);
1622
if (rec_pos != sort_param->filepos && update_index)
1624
_mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1625
sort_param->filepos);
1626
if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1629
mi_check_print_error(param,"%d when updating key-pointers",my_errno);
1633
if (sort_write_record(sort_param))
1636
/* Clear end of block to get better compression if the table is backuped */
1637
memset(buff+used_length, 0, keyinfo->block_length-used_length);
1638
if (my_pwrite(info->s->kfile,(unsigned char*) buff,(uint) keyinfo->block_length,
1639
page,param->myf_rw))
1641
mi_check_print_error(param,"%d when updating keyblock",my_errno);
1645
my_afree((unsigned char*) temp_buff);
1649
my_afree((unsigned char*) temp_buff);
1651
} /* sort_record_index */
1656
Check if myisamchk was killed by a signal
1657
This is overloaded by other programs that want to be able to abort
1661
static int not_killed= 0;
1663
volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
1665
return ¬_killed; /* always NULL */
1668
/* print warnings and errors */
1671
void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
1672
const char *fmt,...)
1677
vfprintf(stdout, fmt, args);
1684
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
1689
if (!param->warning_printed && !param->error_printed)
1691
if (param->testflag & T_SILENT)
1692
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,
1693
param->isam_file_name);
1694
param->out_flag|= O_DATA_LOST;
1696
param->warning_printed=1;
1698
fprintf(stderr,"%s: warning: ",my_progname_short);
1699
vfprintf(stderr, fmt, args);
1708
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
1713
if (!param->warning_printed && !param->error_printed)
1715
if (param->testflag & T_SILENT)
1716
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1717
param->out_flag|= O_DATA_LOST;
1719
param->error_printed|=1;
1721
fprintf(stderr,"%s: error: ",my_progname_short);
1722
vfprintf(stderr, fmt, args);