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>
34
#include "myisamdef.h"
36
static uint32_t decode_bits;
37
static char **default_argv;
38
static const char *load_default_groups[]= { "myisamchk", 0 };
39
static const char *set_collation_name, *opt_tmpdir;
40
static const CHARSET_INFO *set_collation;
41
static long opt_myisam_block_size;
42
static long opt_key_cache_block_size;
43
static const char *my_progname_short;
44
static MY_TMPDIR myisamchk_tmpdir;
46
static const char *type_names[]=
47
{ "impossible","char","binary", "short", "long", "float",
48
"double","number","unsigned short",
49
"unsigned long","int64_t","uint64_t","int24",
50
"uint24","int8","varchar", "varbin","?",
53
static const char *prefix_packed_txt="packed ",
54
*bin_packed_txt="prefix ",
55
*diff_txt="stripped ",
59
static const char *field_pack[]=
60
{"","no endspace", "no prespace",
61
"no zeros", "blob", "constant", "table-lockup",
62
"always zero","varchar","unique-hash","?","?"};
64
static const char *myisam_stats_method_str="nulls_unequal";
66
static void get_options(int *argc,char * * *argv);
67
static void print_version(void);
68
static void usage(void);
69
static int myisamchk(MI_CHECK *param, char *filename);
70
static void descript(MI_CHECK *param, register MI_INFO *info, char * name);
71
static int mi_sort_records(MI_CHECK *param, register MI_INFO *info,
72
char * name, uint32_t sort_key,
73
bool write_info, bool update_index);
74
static int sort_record_index(MI_SORT_PARAM *sort_param, MI_INFO *info,
76
my_off_t page,unsigned char *buff,uint32_t sortkey,
77
File new_file, bool update_index);
83
int main(int argc, char **argv)
87
my_progname_short= my_progname+dirname_length(my_progname);
89
myisamchk_init(&check_param);
90
check_param.opt_lock_memory=1; /* Lock memory if possible */
91
check_param.using_global_keycache = 0;
92
get_options(&argc,(char***) &argv);
93
myisam_quick_table_bits=decode_bits;
97
int new_error=myisamchk(&check_param, *(argv++));
98
if ((check_param.testflag & T_REP_ANY) != T_REP)
99
check_param.testflag&= ~T_REP;
102
if ((check_param.error_printed | check_param.warning_printed) &&
103
(check_param.testflag & T_FORCE_CREATE) &&
104
(!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
107
uint32_t old_testflag=check_param.testflag;
108
if (!(check_param.testflag & T_REP))
109
check_param.testflag|= T_REP_BY_SORT;
110
check_param.testflag&= ~T_EXTEND; /* Don't needed */
111
error|=myisamchk(&check_param, argv[-1]);
112
check_param.testflag= old_testflag;
118
if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
120
puts("\n---------\n");
124
if (check_param.total_files > 1)
125
{ /* Only if descript */
126
char buff[22],buff2[22];
127
if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
128
puts("\n---------\n");
129
printf("\nTotal of all %d MyISAM-files:\nData records: %9s Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
130
llstr(check_param.total_deleted,buff2));
132
free_defaults(default_argv);
133
free_tmpdir(&myisamchk_tmpdir);
134
my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
137
return 0; /* No compiler warning */
142
OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
143
OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE,
144
OPT_KEY_CACHE_BLOCK_SIZE, OPT_MYISAM_BLOCK_SIZE,
145
OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
146
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS,
147
OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD
150
static struct my_option my_long_options[] =
153
"Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
154
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
155
{"block-search", 'b',
156
"No help available.",
157
0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
159
"Make a backup of the .MYD file as 'filename-time.BAK'.",
160
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
161
{"character-sets-dir", OPT_CHARSETS_DIR,
162
"Directory where character sets are.",
163
(char**) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
165
"Check table for errors.",
166
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
167
{"check-only-changed", 'C',
168
"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).",
169
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
170
{"correct-checksum", OPT_CORRECT_CHECKSUM,
171
"Correct checksum information for table.",
172
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
174
"Prints some information about table.",
175
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
176
{"data-file-length", 'D',
177
"Max length of data file (when recreating data-file when it's full).",
178
(char**) &check_param.max_data_file_length,
179
(char**) &check_param.max_data_file_length,
180
0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
181
{"extend-check", 'e',
182
"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.",
183
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
185
"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).",
186
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
188
"Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
189
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
191
"Display this help and exit.",
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
"Print statistics information about table that is checked.",
198
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
200
"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.",
201
(char**) &check_param.keys_in_use,
202
(char**) &check_param.keys_in_use,
203
0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
204
{"max-record-length", OPT_MAX_RECORD_LENGTH,
205
"Skip rows bigger than this if myisamchk can't allocate memory to hold it",
206
(char**) &check_param.max_record_length,
207
(char**) &check_param.max_record_length,
208
0, GET_ULL, REQUIRED_ARG, INT64_MAX, 0, INT64_MAX, 0, 0, 0},
209
{"medium-check", 'm',
210
"Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
211
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
212
{"quick", 'q', "Faster repair by not modifying the data file.",
213
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
215
"Don't mark table as checked.",
216
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
218
"Can fix almost anything except unique keys that aren't unique.",
219
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
220
{"parallel-recover", 'p',
221
"Same as '-r' but creates all the keys in parallel.",
222
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
223
{"safe-recover", 'o',
224
"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.",
225
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
226
{"sort-recover", 'n',
227
"Force recovering with sorting even if the temporary file was very big.",
228
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
230
{"start-check-pos", OPT_START_CHECK_POS,
231
"No help available.",
232
0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
234
{"set-auto-increment", 'A',
235
"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.",
236
(char**) &check_param.auto_increment_value,
237
(char**) &check_param.auto_increment_value,
238
0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
239
{"set-collation", OPT_SET_COLLATION,
240
"Change the collation used by the index",
241
(char**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
242
{"set-variable", 'O',
243
"Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
244
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
246
"Only print errors. One can use two -s to make myisamchk very silent.",
247
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
249
"Sort index blocks. This speeds up 'read-next' in applications.",
250
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
251
{"sort-records", 'R',
252
"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!)",
253
(char**) &check_param.opt_sort_key,
254
(char**) &check_param.opt_sort_key,
255
0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
257
"Path for temporary files.",
258
(char**) &opt_tmpdir,
259
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
260
{"update-state", 'U',
261
"Mark tables as crashed if any errors were found.",
262
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
264
"Unpack file packed with myisampack.",
265
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
267
"Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
268
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
270
"Print version and exit.",
271
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
273
"Wait if table is locked.",
274
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
275
{ "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
276
(char**) &check_param.use_buffers, (char**) &check_param.use_buffers, 0,
277
GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
278
INT32_MAX, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
279
{ "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "",
280
(char**) &opt_key_cache_block_size,
281
(char**) &opt_key_cache_block_size, 0,
282
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
283
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
284
{ "myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "",
285
(char**) &opt_myisam_block_size, (char**) &opt_myisam_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
{ "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
289
(char**) &check_param.read_buffer_length,
290
(char**) &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
291
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
292
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
293
{ "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
294
(char**) &check_param.write_buffer_length,
295
(char**) &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
296
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
297
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
298
{ "sort_buffer_size", OPT_SORT_BUFFER_SIZE, "",
299
(char**) &check_param.sort_buffer_length,
300
(char**) &check_param.sort_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
301
(long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
302
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
303
{ "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
304
(char**) &check_param.sort_key_blocks,
305
(char**) &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
306
BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
307
{ "decode_bits", OPT_DECODE_BITS, "", (char**) &decode_bits,
308
(char**) &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
309
{"stats_method", OPT_STATS_METHOD,
310
"Specifies how index statistics collection code should treat NULLs. "
311
"Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
312
"\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
313
(char**) &myisam_stats_method_str, (char**) &myisam_stats_method_str, 0,
314
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
315
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
319
static void print_version(void)
321
printf("%s Ver 2.7 for %s at %s\n", my_progname, SYSTEM_TYPE,
326
static void usage(void)
329
puts("By Monty, for your professional use");
330
puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
331
puts("Description, check and repair of MyISAM tables.");
332
puts("Used without options all tables on the command will be checked for errors");
333
printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname_short);
334
printf("\nGlobal options:\n");
336
-?, --help Display this help and exit.\n\
337
-O, --set-variable var=option.\n\
338
Change the value of a variable. Please note that\n\
339
this option is deprecated; you can set variables\n\
340
directly with '--variable-name=value'.\n\
341
-t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
342
specified, separated by ");
343
#if defined( __WIN__)
344
printf("semicolon (;)");
348
printf(", they will be used\n\
349
in a round-robin fashion.\n\
350
-s, --silent Only print errors. One can use two -s to make\n\
351
myisamchk very silent.\n\
352
-v, --verbose Print more information. This can be used with\n\
353
--description and --check. Use many -v for more verbosity.\n\
354
-V, --version Print version and exit.\n\
355
-w, --wait Wait if table is locked.\n\n");
357
puts(" --start-check-pos=# Start reading file at given offset.\n");
360
puts("Check options (check is the default action for myisamchk):\n\
361
-c, --check Check table for errors.\n\
362
-e, --extend-check Check the table VERY throughly. Only use this in\n\
363
extreme cases as myisamchk should normally be able to\n\
364
find out if the table is ok even without this switch.\n\
365
-F, --fast Check only tables that haven't been closed properly.\n\
366
-C, --check-only-changed\n\
367
Check only tables that have changed since last check.\n\
368
-f, --force Restart with '-r' if there are any errors in the table.\n\
369
States will be updated as with '--update-state'.\n\
370
-i, --information Print statistics information about table that is checked.\n\
371
-m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
372
all errors. Should be good enough for most cases.\n\
373
-U --update-state Mark tables as crashed if you find any errors.\n\
374
-T, --read-only Don't mark table as checked.\n");
376
puts("Repair options (When using '-r' or '-o'):\n\
377
-B, --backup Make a backup of the .MYD file as 'filename-time.BAK'.\n\
378
--correct-checksum Correct checksum information for table.\n\
379
-D, --data-file-length=# Max length of data file (when recreating data\n\
380
file when it's full).\n\
381
-e, --extend-check Try to recover every possible row from the data file\n\
382
Normally this will also find a lot of garbage rows;\n\
383
Don't use this option if you are not totally desperate.\n\
384
-f, --force Overwrite old temporary files.\n\
385
-k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\
386
bit mask of which keys to use. This can be used to\n\
387
get faster inserts.\n\
388
--max-record-length=#\n\
389
Skip rows bigger than this if myisamchk can't allocate\n\
390
memory to hold it.\n\
391
-r, --recover Can fix almost anything except unique keys that aren't\n\
393
-n, --sort-recover Forces recovering with sorting even if the temporary\n\
394
file would be very big.\n\
395
-p, --parallel-recover\n\
396
Uses the same technique as '-r' and '-n', but creates\n\
397
all the keys in parallel, in different threads.\n\
398
-o, --safe-recover Uses old recovery method; Slower than '-r' but can\n\
399
handle a couple of cases where '-r' reports that it\n\
400
can't fix the data file.\n\
401
--character-sets-dir=...\n\
402
Directory where character sets are.\n\
403
--set-collation=name\n\
404
Change the collation used by the index.\n\
405
-q, --quick Faster repair by not modifying the data file.\n\
406
One can give a second '-q' to force myisamchk to\n\
407
modify the original datafile in case of duplicate keys.\n\
408
NOTE: Tables where the data file is currupted can't be\n\
409
fixed with this option.\n\
410
-u, --unpack Unpack file packed with myisampack.\n\
413
puts("Other actions:\n\
414
-a, --analyze Analyze distribution of keys. Will make some joins in\n\
415
MySQL faster. You can check the calculated distribution\n\
416
by using '--description --verbose table_name'.\n\
417
--stats_method=name Specifies how index statistics collection code should\n\
418
treat NULLs. Possible values of name are \"nulls_unequal\"\n\
419
(default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
420
\"nulls_ignored\".\n\
421
-d, --description Prints some information about table.\n\
422
-A, --set-auto-increment[=value]\n\
423
Force auto_increment to start at this or higher value\n\
424
If no value is given, then sets the next auto_increment\n\
425
value to the highest used value for the auto key + 1.\n\
426
-S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
428
-R, --sort-records=#\n\
429
Sort records according to an index. This makes your\n\
430
data much more localized and may speed up things\n\
431
(It may be VERY slow to do a sort the first time!).\n\
432
-b, --block-search=#\n\
433
Find a record, a block at given offset belongs to.");
435
print_defaults("my", load_default_groups);
436
my_print_variables(my_long_options);
439
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
440
"nulls_ignored", NULL};
441
TYPELIB myisam_stats_method_typelib= {
442
array_elements(myisam_stats_method_names) - 1, "",
443
myisam_stats_method_names, NULL};
448
get_one_option(int optid,
449
const struct my_option *opt __attribute__((unused)),
454
if (argument == disabled_my_option)
455
check_param.testflag&= ~T_STATISTICS;
457
check_param.testflag|= T_STATISTICS;
461
check_param.auto_increment_value= strtoull(argument, NULL, 0);
463
check_param.auto_increment_value= 0; /* Set to max used value */
464
check_param.testflag|= T_AUTO_INC;
467
check_param.search_after_block= strtoul(argument, NULL, 10);
470
if (argument == disabled_my_option)
471
check_param.testflag&= ~T_BACKUP_DATA;
473
check_param.testflag|= T_BACKUP_DATA;
476
if (argument == disabled_my_option)
477
check_param.testflag&= ~T_CHECK;
479
check_param.testflag|= T_CHECK;
482
if (argument == disabled_my_option)
483
check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
485
check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
488
check_param.max_data_file_length=strtoll(argument, NULL, 10);
490
case 's': /* silent */
491
if (argument == disabled_my_option)
492
check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
495
if (check_param.testflag & T_SILENT)
496
check_param.testflag|= T_VERY_SILENT;
497
check_param.testflag|= T_SILENT;
498
check_param.testflag&= ~T_WRITE_LOOP;
502
if (argument == disabled_my_option)
503
check_param.testflag&= ~T_WAIT_FOREVER;
505
check_param.testflag|= T_WAIT_FOREVER;
507
case 'd': /* description if isam-file */
508
if (argument == disabled_my_option)
509
check_param.testflag&= ~T_DESCRIPT;
511
check_param.testflag|= T_DESCRIPT;
513
case 'e': /* extend check */
514
if (argument == disabled_my_option)
515
check_param.testflag&= ~T_EXTEND;
517
check_param.testflag|= T_EXTEND;
520
if (argument == disabled_my_option)
521
check_param.testflag&= ~T_INFO;
523
check_param.testflag|= T_INFO;
526
if (argument == disabled_my_option)
528
check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
529
check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
533
check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
534
check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
538
if (argument == disabled_my_option)
539
check_param.testflag&= ~T_FAST;
541
check_param.testflag|= T_FAST;
544
check_param.keys_in_use= (uint64_t) strtoll(argument, NULL, 10);
547
if (argument == disabled_my_option)
548
check_param.testflag&= ~T_MEDIUM;
550
check_param.testflag|= T_MEDIUM; /* Medium check */
552
case 'r': /* Repair table */
553
check_param.testflag&= ~T_REP_ANY;
554
if (argument != disabled_my_option)
555
check_param.testflag|= T_REP_BY_SORT;
558
check_param.testflag&= ~T_REP_ANY;
559
if (argument != disabled_my_option)
560
check_param.testflag|= T_REP_PARALLEL;
563
check_param.testflag&= ~T_REP_ANY;
564
check_param.force_sort= 0;
565
if (argument != disabled_my_option)
567
check_param.testflag|= T_REP;
568
my_disable_async_io= 1; /* More safety */
572
check_param.testflag&= ~T_REP_ANY;
573
if (argument == disabled_my_option)
574
check_param.force_sort= 0;
577
check_param.testflag|= T_REP_BY_SORT;
578
check_param.force_sort= 1;
582
if (argument == disabled_my_option)
583
check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
585
check_param.testflag|=
586
(check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
589
if (argument == disabled_my_option)
590
check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
592
check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
594
case 'v': /* Verbose */
595
if (argument == disabled_my_option)
597
check_param.testflag&= ~T_VERBOSE;
598
check_param.verbose=0;
602
check_param.testflag|= T_VERBOSE;
603
check_param.verbose++;
606
case 'R': /* Sort records */
607
if (argument == disabled_my_option)
608
check_param.testflag&= ~T_SORT_RECORDS;
611
check_param.testflag|= T_SORT_RECORDS;
612
check_param.opt_sort_key= (uint) atoi(argument) - 1;
613
if (check_param.opt_sort_key >= MI_MAX_KEY)
616
"The value of the sort key is bigger than max key: %d.\n",
622
case 'S': /* Sort index */
623
if (argument == disabled_my_option)
624
check_param.testflag&= ~T_SORT_INDEX;
626
check_param.testflag|= T_SORT_INDEX;
629
if (argument == disabled_my_option)
630
check_param.testflag&= ~T_READONLY;
632
check_param.testflag|= T_READONLY;
635
if (argument == disabled_my_option)
636
check_param.testflag&= ~T_UPDATE_STATE;
638
check_param.testflag|= T_UPDATE_STATE;
643
case OPT_CORRECT_CHECKSUM:
644
if (argument == disabled_my_option)
645
check_param.testflag&= ~T_CALC_CHECKSUM;
647
check_param.testflag|= T_CALC_CHECKSUM;
649
case OPT_STATS_METHOD:
652
enum_mi_stats_method method_conv;
653
myisam_stats_method_str= argument;
654
if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
656
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
661
method_conv= MI_STATS_METHOD_NULLS_EQUAL;
664
method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
667
method_conv= MI_STATS_METHOD_IGNORE_NULLS;
669
default: assert(0); /* Impossible */
671
check_param.stats_method= method_conv;
674
#ifdef DEBUG /* Only useful if debugging */
675
case OPT_START_CHECK_POS:
676
check_param.start_check_pos= strtoull(argument, NULL, 0);
680
my_print_help(my_long_options);
690
static void get_options(register int *argc,register char ***argv)
694
load_defaults("my", load_default_groups, argc, argv);
696
if (isatty(fileno(stdout)))
697
check_param.testflag|=T_WRITE_LOOP;
699
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
702
/* If using repair, then update checksum if one uses --update-state */
703
if ((check_param.testflag & T_UPDATE_STATE) &&
704
(check_param.testflag & T_REP_ANY))
705
check_param.testflag|= T_CALC_CHECKSUM;
713
if ((check_param.testflag & T_UNPACK) &&
714
(check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
717
"%s: --unpack can't be used with --quick or --sort-records\n",
721
if ((check_param.testflag & T_READONLY) &&
722
(check_param.testflag &
723
(T_REP_ANY | T_STATISTICS | T_AUTO_INC |
724
T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
727
"%s: Can't use --readonly when repairing or sorting\n",
732
if (init_tmpdir(&myisamchk_tmpdir, opt_tmpdir))
735
check_param.tmpdir=&myisamchk_tmpdir;
736
check_param.key_cache_block_size= opt_key_cache_block_size;
738
if (set_collation_name)
739
if (!(set_collation= get_charset_by_name(set_collation_name,
743
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
750
static int myisamchk(MI_CHECK *param, char * filename)
752
int error,lock_type,recreate;
753
int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
754
uint32_t raid_chunks;
757
char llbuff[22],llbuff2[22];
758
bool state_updated=0;
761
param->out_flag=error=param->warning_printed=param->error_printed=
764
param->isam_file_name=filename; /* For error messages */
765
if (!(info=mi_open(filename,
766
(param->testflag & (T_DESCRIPT | T_READONLY)) ?
769
((param->testflag & T_WAIT_FOREVER) ?
770
HA_OPEN_WAIT_IF_LOCKED :
771
(param->testflag & T_DESCRIPT) ?
772
HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
774
/* Avoid twice printing of isam file name */
775
param->error_printed=1;
778
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);
780
case HA_ERR_NOT_A_TABLE:
781
mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
783
case HA_ERR_CRASHED_ON_USAGE:
784
mi_check_print_error(param,"'%s' is marked as crashed",filename);
786
case HA_ERR_CRASHED_ON_REPAIR:
787
mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
789
case HA_ERR_OLD_FILE:
790
mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
792
case HA_ERR_END_OF_FILE:
793
mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
796
mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
799
mi_check_print_error(param,"File '%s' doesn't exist",filename);
802
mi_check_print_error(param,"You don't have permission to use '%s'",filename);
805
mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
812
share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
813
share->tot_locks-= share->r_locks;
815
raid_chunks=share->base.raid_chunks;
818
Skip the checking of the file if:
819
We are using --fast and the table is closed properly
820
We are using --check-only-changed-tables and the table hasn't changed
822
if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
824
bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
826
if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
827
((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
828
STATE_CRASHED_ON_REPAIR) ||
829
!(param->testflag & T_CHECK_ONLY_CHANGED))))
832
if (info->s->base.keys && info->state->records)
834
if ((param->testflag & T_STATISTICS) &&
835
(share->state.changed & STATE_NOT_ANALYZED))
837
if ((param->testflag & T_SORT_INDEX) &&
838
(share->state.changed & STATE_NOT_SORTED_PAGES))
840
if ((param->testflag & T_REP_BY_SORT) &&
841
(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
844
if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
845
(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
846
STATE_CRASHED_ON_REPAIR)))
850
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
851
printf("MyISAM file: %s is already checked\n",filename);
854
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
861
if ((param->testflag & (T_REP_ANY | T_STATISTICS |
862
T_SORT_RECORDS | T_SORT_INDEX)) &&
863
(((param->testflag & T_UNPACK) &&
864
share->data_file_type == COMPRESSED_RECORD) ||
865
mi_uint2korr(share->state.header.state_info_length) !=
866
MI_STATE_INFO_SIZE ||
867
mi_uint2korr(share->state.header.base_info_length) !=
869
mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
870
~share->state.key_map) ||
871
test_if_almost_full(info) ||
872
info->s->state.header.file_version[3] != myisam_file_magic[3] ||
874
set_collation->number != share->state.header.language) ||
875
myisam_block_size != MI_KEY_BLOCK_LENGTH))
878
param->language= set_collation->number;
879
if (recreate_table(param, &info,filename))
882
"MyISAM-table '%s' is not fixed because of errors\n",
887
if (!(param->testflag & T_REP_ANY))
889
param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
890
if (!(param->testflag & T_SILENT))
891
printf("- '%s' has old table-format. Recreating index\n",filename);
895
share->tot_locks-= share->r_locks;
899
if (param->testflag & T_DESCRIPT)
901
param->total_files++;
902
param->total_records+=info->state->records;
903
param->total_deleted+=info->state->del;
904
descript(param, info, filename);
909
if (!(param->testflag & T_READONLY))
910
lock_type = F_WRLCK; /* table is changed */
913
if (info->lock_type == F_RDLCK)
914
info->lock_type=F_UNLCK; /* Read only table */
915
if (_mi_readinfo(info,lock_type,0))
917
mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
919
param->error_printed=0;
923
_mi_readinfo() has locked the table.
924
We mark the table as locked (without doing file locks) to be able to
925
use functions that only works on locked tables (like row caching).
927
mi_lock_database(info, F_EXTRA_LCK);
928
datafile=info->dfile;
930
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
932
if (param->testflag & T_REP_ANY)
934
uint64_t tmp=share->state.key_map;
935
mi_copy_keys_active(share->state.key_map, share->base.keys,
937
if (tmp != share->state.key_map)
938
info->update|=HA_STATE_CHANGED;
940
if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
942
if (param->testflag & T_FORCE_CREATE)
945
mi_check_print_info(param,"Creating new data file\n");
950
mi_check_print_error(param,
951
"Quick-recover aborted; Run recovery without switch 'q'");
956
if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
957
(mi_is_any_key_active(share->state.key_map) ||
958
(rep_quick && !param->keys_in_use && !recreate)) &&
959
mi_test_if_sort_rep(info, info->state->records,
960
info->s->state.key_map,
963
if (param->testflag & T_REP_BY_SORT)
964
error=mi_repair_by_sort(param,info,filename,rep_quick);
966
error=mi_repair_parallel(param,info,filename,rep_quick);
969
else if (param->testflag & T_REP_ANY)
970
error=mi_repair(param, info,filename,rep_quick);
972
if (!error && param->testflag & T_SORT_RECORDS)
976
We can't update the index in mi_sort_records if we have a
977
prefix compressed or fulltext index
980
for (key=0 ; key < share->base.keys; key++)
981
if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY))
984
error=mi_sort_records(param,info,filename,param->opt_sort_key,
985
/* what is the following parameter for ? */
986
(bool) !(param->testflag & T_REP),
988
datafile=info->dfile; /* This is now locked */
989
if (!error && !update_index)
992
puts("Table had a compressed index; We must now recreate the index");
993
error=mi_repair_by_sort(param,info,filename,1);
996
if (!error && param->testflag & T_SORT_INDEX)
997
error=mi_sort_index(param,info,filename);
999
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1000
STATE_CRASHED_ON_REPAIR);
1002
mi_mark_crashed(info);
1004
else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
1006
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1007
printf("Checking MyISAM file: %s\n",filename);
1008
if (!(param->testflag & T_SILENT))
1009
printf("Data records: %7s Deleted blocks: %7s\n",
1010
llstr(info->state->records,llbuff),
1011
llstr(info->state->del,llbuff2));
1012
error =chk_status(param,info);
1013
mi_intersect_keys_active(share->state.key_map, param->keys_in_use);
1014
error =chk_size(param,info);
1015
if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1016
error|=chk_del(param, info,param->testflag);
1017
if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1018
!param->start_check_pos)))
1020
error|=chk_key(param, info);
1021
if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1022
error=update_state_info(param, info,
1023
((param->testflag & T_STATISTICS) ?
1025
((param->testflag & T_AUTO_INC) ?
1026
UPDATE_AUTO_INC : 0));
1028
if ((!rep_quick && !error) ||
1029
!(param->testflag & (T_FAST | T_FORCE_CREATE)))
1031
if (param->testflag & (T_EXTEND | T_MEDIUM))
1032
init_key_cache(dflt_key_cache,opt_key_cache_block_size,
1033
param->use_buffers, 0, 0);
1034
init_io_cache(¶m->read_cache,datafile,
1035
(uint) param->read_buffer_length,
1037
(param->start_check_pos ?
1038
param->start_check_pos :
1039
share->pack.header_length),
1043
if ((info->s->options & (HA_OPTION_PACK_RECORD |
1044
HA_OPTION_COMPRESS_RECORD)) ||
1045
(param->testflag & (T_EXTEND | T_MEDIUM)))
1046
error|=chk_data_link(param, info, param->testflag & T_EXTEND);
1047
error|=flush_blocks(param, share->key_cache, share->kfile);
1048
end_io_cache(¶m->read_cache);
1052
if ((share->state.changed & STATE_CHANGED) &&
1053
(param->testflag & T_UPDATE_STATE))
1054
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1055
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1056
STATE_CRASHED_ON_REPAIR);
1058
else if (!mi_is_crashed(info) &&
1059
(param->testflag & T_UPDATE_STATE))
1060
{ /* Mark crashed */
1061
mi_mark_crashed(info);
1062
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1066
if ((param->testflag & T_AUTO_INC) ||
1067
((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1068
update_auto_increment_key(param, info,
1069
(bool) !test(param->testflag & T_AUTO_INC));
1071
if (!(param->testflag & T_DESCRIPT))
1073
if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1074
error|=update_state_info(param, info,
1076
(((param->testflag & T_REP_ANY) ?
1078
(state_updated ? UPDATE_STAT : 0) |
1079
((param->testflag & T_SORT_RECORDS) ?
1081
info->update&= ~HA_STATE_CHANGED;
1083
mi_lock_database(info, F_UNLCK);
1087
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
1092
if (param->out_flag & O_NEW_DATA)
1093
error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1095
((param->testflag & T_BACKUP_DATA) ?
1096
MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1097
if (param->out_flag & O_NEW_INDEX)
1098
error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1101
fflush(stdout); fflush(stderr);
1102
if (param->error_printed)
1104
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1107
"MyISAM-table '%s' is not fixed because of errors\n",
1109
if (param->testflag & T_REP_ANY)
1111
"Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n");
1113
else if (!(param->error_printed & 2) &&
1114
!(param->testflag & T_FORCE_CREATE))
1116
"MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
1119
else if (param->warning_printed &&
1120
! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1122
fprintf(stderr, "MyISAM-table '%s' is usable but should be fixed\n",
1129
/* Write info about table */
1131
static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
1133
uint32_t key,keyseg_nr,field,start;
1134
register MI_KEYDEF *keyinfo;
1135
register HA_KEYSEG *keyseg;
1136
register const char *text;
1137
char buff[160],length[10],*pos,*end;
1138
enum en_fieldtype type;
1139
MYISAM_SHARE *share=info->s;
1140
char llbuff[22],llbuff2[22];
1142
printf("\nMyISAM file: %s\n",name);
1143
fputs("Record format: ",stdout);
1144
if (share->options & HA_OPTION_COMPRESS_RECORD)
1146
else if (share->options & HA_OPTION_PACK_RECORD)
1149
puts("Fixed length");
1150
printf("Character set: %s (%d)\n",
1151
get_charset_name(share->state.header.language),
1152
share->state.header.language);
1154
if (param->testflag & T_VERBOSE)
1156
printf("File-version: %d\n",
1157
(int) share->state.header.file_version[3]);
1158
if (share->state.create_time)
1160
get_date(buff,1,share->state.create_time);
1161
printf("Creation time: %s\n",buff);
1163
if (share->state.check_time)
1165
get_date(buff,1,share->state.check_time);
1166
printf("Recover time: %s\n",buff);
1169
if (share->state.changed & STATE_CRASHED)
1170
my_stpcpy(buff,"crashed");
1173
if (share->state.open_count)
1174
pos=my_stpcpy(pos,"open,");
1175
if (share->state.changed & STATE_CHANGED)
1176
pos=my_stpcpy(pos,"changed,");
1178
pos=my_stpcpy(pos,"checked,");
1179
if (!(share->state.changed & STATE_NOT_ANALYZED))
1180
pos=my_stpcpy(pos,"analyzed,");
1181
if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1182
pos=my_stpcpy(pos,"optimized keys,");
1183
if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1184
pos=my_stpcpy(pos,"sorted index pages,");
1185
pos[-1]=0; /* Remove extra ',' */
1187
printf("Status: %s\n",buff);
1188
if (share->base.auto_key)
1190
printf("Auto increment key: %13d Last value: %13s\n",
1191
share->base.auto_key,
1192
llstr(share->state.auto_increment,llbuff));
1194
if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1195
printf("Checksum: %23s\n",llstr(info->state->checksum,llbuff));
1197
if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1198
printf("Keys are only flushed at close\n");
1201
printf("Data records: %13s Deleted blocks: %13s\n",
1202
llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1203
if (param->testflag & T_SILENT)
1204
return; /* This is enough */
1206
if (param->testflag & T_VERBOSE)
1209
printf("Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
1211
printf("Datafile parts: %13s Deleted data: %13s\n",
1212
llstr(share->state.split,llbuff),
1213
llstr(info->state->empty,llbuff2));
1214
printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
1215
share->rec_reflength,share->base.key_reflength);
1216
printf("Datafile length: %13s Keyfile length: %13s\n",
1217
llstr(info->state->data_file_length,llbuff),
1218
llstr(info->state->key_file_length,llbuff2));
1220
if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1221
puts("This is a one-record table");
1224
if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1225
share->base.max_key_file_length != HA_OFFSET_ERROR)
1226
printf("Max datafile length: %13s Max keyfile length: %13s\n",
1227
llstr(share->base.max_data_file_length-1,llbuff),
1228
llstr(share->base.max_key_file_length-1,llbuff2));
1232
printf("Recordlength: %13d\n",(int) share->base.pack_reclength);
1233
if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1235
int64_t2str(share->state.key_map,buff,2);
1236
printf("Using only keys '%s' of %d possibly keys\n",
1237
buff, share->base.keys);
1239
puts("\ntable description:");
1240
printf("Key Start Len Index Type");
1241
if (param->testflag & T_VERBOSE)
1242
printf(" Rec/key Root Blocksize");
1245
for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1246
key < share->base.keys;
1249
keyseg=keyinfo->seg;
1250
if (keyinfo->flag & HA_NOSAME) text="unique ";
1251
else text="multip.";
1254
if (keyseg->flag & HA_REVERSE_SORT)
1256
pos=my_stpcpy(pos,type_names[keyseg->type]);
1259
if (keyinfo->flag & HA_PACK_KEY)
1260
pos=my_stpcpy(pos,prefix_packed_txt);
1261
if (keyinfo->flag & HA_BINARY_PACK_KEY)
1262
pos=my_stpcpy(pos,bin_packed_txt);
1263
if (keyseg->flag & HA_SPACE_PACK)
1264
pos=my_stpcpy(pos,diff_txt);
1265
if (keyseg->flag & HA_BLOB_PART)
1266
pos=my_stpcpy(pos,blob_txt);
1267
if (keyseg->flag & HA_NULL_PART)
1268
pos=my_stpcpy(pos,null_txt);
1271
printf("%-4d%-6ld%-3d %-8s%-21s",
1272
key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1273
if (share->state.key_root[key] != HA_OFFSET_ERROR)
1274
llstr(share->state.key_root[key],buff);
1277
if (param->testflag & T_VERBOSE)
1278
printf("%11lu %12s %10d",
1279
share->state.rec_per_key_part[keyseg_nr++],
1280
buff,keyinfo->block_length);
1282
while ((++keyseg)->type != HA_KEYTYPE_END)
1285
if (keyseg->flag & HA_REVERSE_SORT)
1287
pos=my_stpcpy(pos,type_names[keyseg->type]);
1289
if (keyseg->flag & HA_SPACE_PACK)
1290
pos=my_stpcpy(pos,diff_txt);
1291
if (keyseg->flag & HA_BLOB_PART)
1292
pos=my_stpcpy(pos,blob_txt);
1293
if (keyseg->flag & HA_NULL_PART)
1294
pos=my_stpcpy(pos,null_txt);
1296
printf(" %-6ld%-3d %-21s",
1297
(long) keyseg->start+1,keyseg->length,buff);
1298
if (param->testflag & T_VERBOSE)
1299
printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1304
if (share->state.header.uniques)
1306
MI_UNIQUEDEF *uniqueinfo;
1307
puts("\nUnique Key Start Len Nullpos Nullbit Type");
1308
for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1309
key < share->state.header.uniques; key++, uniqueinfo++)
1312
char null_bit[8],null_pos[8];
1313
printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1314
for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1318
null_bit[0]=null_pos[0]=0;
1319
if (keyseg->null_bit)
1321
sprintf(null_bit,"%d",keyseg->null_bit);
1322
sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1324
printf("%-7ld%-5d%-9s%-10s%-30s\n",
1325
(long) keyseg->start+1,keyseg->length,
1327
type_names[keyseg->type]);
1332
if (param->verbose > 1)
1334
char null_bit[8],null_pos[8];
1335
printf("\nField Start Length Nullpos Nullbit Type");
1336
if (share->options & HA_OPTION_COMPRESS_RECORD)
1337
printf(" Huff tree Bits");
1340
for (field=0 ; field < share->base.fields ; field++)
1342
if (share->options & HA_OPTION_COMPRESS_RECORD)
1343
type=share->rec[field].base_type;
1345
type=(enum en_fieldtype) share->rec[field].type;
1346
end=my_stpcpy(buff,field_pack[type]);
1347
if (share->options & HA_OPTION_COMPRESS_RECORD)
1349
if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1350
end=my_stpcpy(end,", not_always");
1351
if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1352
end=my_stpcpy(end,", no empty");
1353
if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1355
sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
1356
end= strchr(end, '\0');
1360
my_stpcpy(buff,buff+2);
1361
int10_to_str((long) share->rec[field].length,length,10);
1362
null_bit[0]=null_pos[0]=0;
1363
if (share->rec[field].null_bit)
1365
sprintf(null_bit,"%d",share->rec[field].null_bit);
1366
sprintf(null_pos,"%d",share->rec[field].null_pos+1);
1368
printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1369
null_pos, null_bit, buff);
1370
if (share->options & HA_OPTION_COMPRESS_RECORD)
1372
if (share->rec[field].huff_tree)
1374
(uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1375
share->rec[field].huff_tree->quick_table_bits);
1378
start+=share->rec[field].length;
1385
/* Sort records according to one key */
1387
static int mi_sort_records(MI_CHECK *param,
1388
register MI_INFO *info, char * name,
1397
unsigned char *temp_buff;
1398
ha_rows old_record_count;
1399
MYISAM_SHARE *share=info->s;
1400
char llbuff[22],llbuff2[22];
1401
SORT_INFO sort_info;
1402
MI_SORT_PARAM sort_param;
1404
memset(&sort_info, 0, sizeof(sort_info));
1405
memset(&sort_param, 0, sizeof(sort_param));
1406
sort_param.sort_info=&sort_info;
1407
sort_info.param=param;
1408
keyinfo= &share->keyinfo[sort_key];
1413
if (! mi_is_key_active(share->state.key_map, sort_key))
1415
mi_check_print_warning(param,
1416
"Can't sort table '%s' on key %d; No such key",
1418
param->error_printed=0;
1419
return(0); /* Nothing to do */
1421
if (share->data_file_type == COMPRESSED_RECORD)
1423
mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
1424
param->error_printed=0;
1425
return(0); /* Nothing to do */
1427
if (!(param->testflag & T_SILENT))
1429
printf("- Sorting records for MyISAM-table '%s'\n",name);
1431
printf("Data records: %9s Deleted: %9s\n",
1432
llstr(info->state->records,llbuff),
1433
llstr(info->state->del,llbuff2));
1435
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1436
return(0); /* Nothing to do */
1438
init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers,
1440
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1441
WRITE_CACHE,share->pack.header_length,1,
1442
MYF(MY_WME | MY_WAIT_IF_FULL)))
1444
info->opt_flag|=WRITE_CACHE_USED;
1446
if (!(temp_buff=(unsigned char*) my_alloca((uint) keyinfo->block_length)))
1448
mi_check_print_error(param,"Not enough memory for key block");
1452
if (!mi_alloc_rec_buff(info, -1, &sort_param.record))
1454
mi_check_print_error(param,"Not enough memory for record");
1457
fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
1458
new_file=my_create(fn_format(param->temp_filename,
1459
param->temp_filename,"",
1461
0,param->tmpfile_createflag,
1465
mi_check_print_error(param,"Can't create new tempfile: '%s'",
1466
param->temp_filename);
1469
if (share->pack.header_length)
1470
if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1473
info->rec_cache.file=new_file; /* Use this file for cacheing*/
1476
for (key=0 ; key < share->base.keys ; key++)
1477
share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1479
if (my_pread(share->kfile,(unsigned char*) temp_buff,
1480
(uint) keyinfo->block_length,
1481
share->state.key_root[sort_key],
1482
MYF(MY_NABP+MY_WME)))
1484
mi_check_print_error(param,"Can't read indexpage from filepos: %s",
1485
(ulong) share->state.key_root[sort_key]);
1489
/* Setup param for sort_write_record */
1490
sort_info.info=info;
1491
sort_info.new_data_file_type=share->data_file_type;
1492
sort_param.fix_datafile=1;
1493
sort_param.master=1;
1494
sort_param.filepos=share->pack.header_length;
1495
old_record_count=info->state->records;
1496
info->state->records=0;
1497
if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1498
info->state->checksum=0;
1500
if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1501
temp_buff, sort_key,new_file,update_index) ||
1502
write_data_suffix(&sort_info,1) ||
1503
flush_io_cache(&info->rec_cache))
1506
if (info->state->records != old_record_count)
1508
mi_check_print_error(param,"found %s of %s records",
1509
llstr(info->state->records,llbuff),
1510
llstr(old_record_count,llbuff2));
1514
my_close(info->dfile,MYF(MY_WME));
1515
param->out_flag|=O_NEW_DATA; /* Data in new file */
1516
info->dfile=new_file; /* Use new datafile */
1518
info->state->empty=0;
1519
share->state.dellink= HA_OFFSET_ERROR;
1520
info->state->data_file_length=sort_param.filepos;
1521
share->state.split=info->state->records; /* Only hole records */
1522
share->state.version=(ulong) time((time_t*) 0);
1524
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1526
if (param->testflag & T_WRITE_LOOP)
1528
fputs(" \r",stdout); fflush(stdout);
1533
if (got_error && new_file >= 0)
1535
end_io_cache(&info->rec_cache);
1536
(void) my_close(new_file,MYF(MY_WME));
1537
(void) my_delete(param->temp_filename, MYF(MY_WME));
1541
my_afree((unsigned char*) temp_buff);
1543
void * rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
1544
if (rec_buff_ptr != NULL)
1547
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1548
end_io_cache(&info->rec_cache);
1549
free(sort_info.buff);
1551
share->state.sortkey=sort_key;
1552
return(flush_blocks(param, share->key_cache, share->kfile) |
1554
} /* sort_records */
1557
/* Sort records recursive using one index */
1559
static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
1561
my_off_t page, unsigned char *buff, uint32_t sort_key,
1562
File new_file,bool update_index)
1564
uint nod_flag,used_length,key_length;
1565
unsigned char *temp_buff,*keypos,*endpos;
1566
my_off_t next_page,rec_pos;
1567
unsigned char lastkey[MI_MAX_KEY_BUFF];
1569
SORT_INFO *sort_info= sort_param->sort_info;
1570
MI_CHECK *param=sort_info->param;
1572
nod_flag=mi_test_if_nod(buff);
1577
if (!(temp_buff=(unsigned char*) my_alloca((uint) keyinfo->block_length)))
1579
mi_check_print_error(param,"Not Enough memory");
1583
used_length=mi_getint(buff);
1584
keypos=buff+2+nod_flag;
1585
endpos=buff+used_length;
1590
next_page=_mi_kpos(nod_flag,keypos);
1591
if (my_pread(info->s->kfile,(unsigned char*) temp_buff,
1592
(uint) keyinfo->block_length, next_page,
1593
MYF(MY_NABP+MY_WME)))
1595
mi_check_print_error(param,"Can't read keys from filepos: %s",
1596
llstr(next_page,llbuff));
1599
if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1600
new_file, update_index))
1603
if (keypos >= endpos ||
1604
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1607
rec_pos= _mi_dpos(info,0,lastkey+key_length);
1609
if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1611
mi_check_print_error(param,"%d when reading datafile",my_errno);
1614
if (rec_pos != sort_param->filepos && update_index)
1616
_mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1617
sort_param->filepos);
1618
if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1621
mi_check_print_error(param,"%d when updating key-pointers",my_errno);
1625
if (sort_write_record(sort_param))
1628
/* Clear end of block to get better compression if the table is backuped */
1629
memset(buff+used_length, 0, keyinfo->block_length-used_length);
1630
if (my_pwrite(info->s->kfile,(unsigned char*) buff,(uint) keyinfo->block_length,
1631
page,param->myf_rw))
1633
mi_check_print_error(param,"%d when updating keyblock",my_errno);
1637
my_afree((unsigned char*) temp_buff);
1641
my_afree((unsigned char*) temp_buff);
1643
} /* sort_record_index */
1648
Check if myisamchk was killed by a signal
1649
This is overloaded by other programs that want to be able to abort
1653
static int not_killed= 0;
1655
volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
1657
return ¬_killed; /* always NULL */
1660
/* print warnings and errors */
1663
void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
1664
const char *fmt,...)
1669
vfprintf(stdout, fmt, args);
1676
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
1681
if (!param->warning_printed && !param->error_printed)
1683
if (param->testflag & T_SILENT)
1684
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,
1685
param->isam_file_name);
1686
param->out_flag|= O_DATA_LOST;
1688
param->warning_printed=1;
1690
fprintf(stderr,"%s: warning: ",my_progname_short);
1691
vfprintf(stderr, fmt, args);
1700
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
1705
if (!param->warning_printed && !param->error_printed)
1707
if (param->testflag & T_SILENT)
1708
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1709
param->out_flag|= O_DATA_LOST;
1711
param->error_printed|=1;
1713
fprintf(stderr,"%s: error: ",my_progname_short);
1714
vfprintf(stderr, fmt, args);