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("drizzle", 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 */
670
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
673
check_param.stats_method= method_conv;
676
#ifdef DEBUG /* Only useful if debugging */
677
case OPT_START_CHECK_POS:
678
check_param.start_check_pos= strtoull(argument, NULL, 0);
682
my_print_help(my_long_options);
692
static void get_options(register int *argc,register char ***argv)
696
load_defaults("drizzle", load_default_groups, argc, argv);
698
if (isatty(fileno(stdout)))
699
check_param.testflag|=T_WRITE_LOOP;
701
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
704
/* If using repair, then update checksum if one uses --update-state */
705
if ((check_param.testflag & T_UPDATE_STATE) &&
706
(check_param.testflag & T_REP_ANY))
707
check_param.testflag|= T_CALC_CHECKSUM;
715
if ((check_param.testflag & T_UNPACK) &&
716
(check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
719
"%s: --unpack can't be used with --quick or --sort-records\n",
723
if ((check_param.testflag & T_READONLY) &&
724
(check_param.testflag &
725
(T_REP_ANY | T_STATISTICS | T_AUTO_INC |
726
T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
729
"%s: Can't use --readonly when repairing or sorting\n",
734
if (init_tmpdir(&myisamchk_tmpdir, opt_tmpdir))
737
check_param.tmpdir=&myisamchk_tmpdir;
738
check_param.key_cache_block_size= opt_key_cache_block_size;
740
if (set_collation_name)
741
if (!(set_collation= get_charset_by_name(set_collation_name,
745
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
752
static int myisamchk(MI_CHECK *param, char * filename)
754
int error,lock_type,recreate;
755
int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
756
uint32_t raid_chunks;
759
char llbuff[22],llbuff2[22];
760
bool state_updated=0;
763
param->out_flag=error=param->warning_printed=param->error_printed=
766
param->isam_file_name=filename; /* For error messages */
767
if (!(info=mi_open(filename,
768
(param->testflag & (T_DESCRIPT | T_READONLY)) ?
771
((param->testflag & T_WAIT_FOREVER) ?
772
HA_OPEN_WAIT_IF_LOCKED :
773
(param->testflag & T_DESCRIPT) ?
774
HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
776
/* Avoid twice printing of isam file name */
777
param->error_printed=1;
780
mi_check_print_error(param,"'%s' doesn't have a correct index definition. You need to recreate it before you can do a repair",filename);
782
case HA_ERR_NOT_A_TABLE:
783
mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
785
case HA_ERR_CRASHED_ON_USAGE:
786
mi_check_print_error(param,"'%s' is marked as crashed",filename);
788
case HA_ERR_CRASHED_ON_REPAIR:
789
mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
791
case HA_ERR_OLD_FILE:
792
mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
794
case HA_ERR_END_OF_FILE:
795
mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
798
mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
801
mi_check_print_error(param,"File '%s' doesn't exist",filename);
804
mi_check_print_error(param,"You don't have permission to use '%s'",filename);
807
mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
814
share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
815
share->tot_locks-= share->r_locks;
817
raid_chunks=share->base.raid_chunks;
820
Skip the checking of the file if:
821
We are using --fast and the table is closed properly
822
We are using --check-only-changed-tables and the table hasn't changed
824
if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
826
bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
828
if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
829
((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
830
STATE_CRASHED_ON_REPAIR) ||
831
!(param->testflag & T_CHECK_ONLY_CHANGED))))
834
if (info->s->base.keys && info->state->records)
836
if ((param->testflag & T_STATISTICS) &&
837
(share->state.changed & STATE_NOT_ANALYZED))
839
if ((param->testflag & T_SORT_INDEX) &&
840
(share->state.changed & STATE_NOT_SORTED_PAGES))
842
if ((param->testflag & T_REP_BY_SORT) &&
843
(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
846
if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
847
(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
848
STATE_CRASHED_ON_REPAIR)))
852
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
853
printf("MyISAM file: %s is already checked\n",filename);
856
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
863
if ((param->testflag & (T_REP_ANY | T_STATISTICS |
864
T_SORT_RECORDS | T_SORT_INDEX)) &&
865
(((param->testflag & T_UNPACK) &&
866
share->data_file_type == COMPRESSED_RECORD) ||
867
mi_uint2korr(share->state.header.state_info_length) !=
868
MI_STATE_INFO_SIZE ||
869
mi_uint2korr(share->state.header.base_info_length) !=
871
mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
872
~share->state.key_map) ||
873
test_if_almost_full(info) ||
874
info->s->state.header.file_version[3] != myisam_file_magic[3] ||
876
set_collation->number != share->state.header.language) ||
877
myisam_block_size != MI_KEY_BLOCK_LENGTH))
880
param->language= set_collation->number;
881
if (recreate_table(param, &info,filename))
884
"MyISAM-table '%s' is not fixed because of errors\n",
889
if (!(param->testflag & T_REP_ANY))
891
param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
892
if (!(param->testflag & T_SILENT))
893
printf("- '%s' has old table-format. Recreating index\n",filename);
897
share->tot_locks-= share->r_locks;
901
if (param->testflag & T_DESCRIPT)
903
param->total_files++;
904
param->total_records+=info->state->records;
905
param->total_deleted+=info->state->del;
906
descript(param, info, filename);
911
if (!(param->testflag & T_READONLY))
912
lock_type = F_WRLCK; /* table is changed */
915
if (info->lock_type == F_RDLCK)
916
info->lock_type=F_UNLCK; /* Read only table */
917
if (_mi_readinfo(info,lock_type,0))
919
mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
921
param->error_printed=0;
925
_mi_readinfo() has locked the table.
926
We mark the table as locked (without doing file locks) to be able to
927
use functions that only works on locked tables (like row caching).
929
mi_lock_database(info, F_EXTRA_LCK);
930
datafile=info->dfile;
932
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
934
if (param->testflag & T_REP_ANY)
936
uint64_t tmp=share->state.key_map;
937
mi_copy_keys_active(share->state.key_map, share->base.keys,
939
if (tmp != share->state.key_map)
940
info->update|=HA_STATE_CHANGED;
942
if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
944
if (param->testflag & T_FORCE_CREATE)
947
mi_check_print_info(param,"Creating new data file\n");
952
mi_check_print_error(param,
953
"Quick-recover aborted; Run recovery without switch 'q'");
958
if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
959
(mi_is_any_key_active(share->state.key_map) ||
960
(rep_quick && !param->keys_in_use && !recreate)) &&
961
mi_test_if_sort_rep(info, info->state->records,
962
info->s->state.key_map,
965
if (param->testflag & T_REP_BY_SORT)
966
error=mi_repair_by_sort(param,info,filename,rep_quick);
968
error=mi_repair_parallel(param,info,filename,rep_quick);
971
else if (param->testflag & T_REP_ANY)
972
error=mi_repair(param, info,filename,rep_quick);
974
if (!error && param->testflag & T_SORT_RECORDS)
978
We can't update the index in mi_sort_records if we have a
979
prefix compressed or fulltext index
982
for (key=0 ; key < share->base.keys; key++)
983
if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY))
986
error=mi_sort_records(param,info,filename,param->opt_sort_key,
987
/* what is the following parameter for ? */
988
(bool) !(param->testflag & T_REP),
990
datafile=info->dfile; /* This is now locked */
991
if (!error && !update_index)
994
puts("Table had a compressed index; We must now recreate the index");
995
error=mi_repair_by_sort(param,info,filename,1);
998
if (!error && param->testflag & T_SORT_INDEX)
999
error=mi_sort_index(param,info,filename);
1001
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1002
STATE_CRASHED_ON_REPAIR);
1004
mi_mark_crashed(info);
1006
else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
1008
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1009
printf("Checking MyISAM file: %s\n",filename);
1010
if (!(param->testflag & T_SILENT))
1011
printf("Data records: %7s Deleted blocks: %7s\n",
1012
llstr(info->state->records,llbuff),
1013
llstr(info->state->del,llbuff2));
1014
error =chk_status(param,info);
1015
mi_intersect_keys_active(share->state.key_map, param->keys_in_use);
1016
error =chk_size(param,info);
1017
if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1018
error|=chk_del(param, info,param->testflag);
1019
if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1020
!param->start_check_pos)))
1022
error|=chk_key(param, info);
1023
if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1024
error=update_state_info(param, info,
1025
((param->testflag & T_STATISTICS) ?
1027
((param->testflag & T_AUTO_INC) ?
1028
UPDATE_AUTO_INC : 0));
1030
if ((!rep_quick && !error) ||
1031
!(param->testflag & (T_FAST | T_FORCE_CREATE)))
1033
if (param->testflag & (T_EXTEND | T_MEDIUM))
1034
init_key_cache(dflt_key_cache,opt_key_cache_block_size,
1035
param->use_buffers, 0, 0);
1036
init_io_cache(¶m->read_cache,datafile,
1037
(uint) param->read_buffer_length,
1039
(param->start_check_pos ?
1040
param->start_check_pos :
1041
share->pack.header_length),
1045
if ((info->s->options & (HA_OPTION_PACK_RECORD |
1046
HA_OPTION_COMPRESS_RECORD)) ||
1047
(param->testflag & (T_EXTEND | T_MEDIUM)))
1048
error|=chk_data_link(param, info, param->testflag & T_EXTEND);
1049
error|=flush_blocks(param, share->key_cache, share->kfile);
1050
end_io_cache(¶m->read_cache);
1054
if ((share->state.changed & STATE_CHANGED) &&
1055
(param->testflag & T_UPDATE_STATE))
1056
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1057
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1058
STATE_CRASHED_ON_REPAIR);
1060
else if (!mi_is_crashed(info) &&
1061
(param->testflag & T_UPDATE_STATE))
1062
{ /* Mark crashed */
1063
mi_mark_crashed(info);
1064
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1068
if ((param->testflag & T_AUTO_INC) ||
1069
((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1070
update_auto_increment_key(param, info,
1071
(bool) !test(param->testflag & T_AUTO_INC));
1073
if (!(param->testflag & T_DESCRIPT))
1075
if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1076
error|=update_state_info(param, info,
1078
(((param->testflag & T_REP_ANY) ?
1080
(state_updated ? UPDATE_STAT : 0) |
1081
((param->testflag & T_SORT_RECORDS) ?
1083
info->update&= ~HA_STATE_CHANGED;
1085
mi_lock_database(info, F_UNLCK);
1089
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
1094
if (param->out_flag & O_NEW_DATA)
1095
error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1097
((param->testflag & T_BACKUP_DATA) ?
1098
MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1099
if (param->out_flag & O_NEW_INDEX)
1100
error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1103
fflush(stdout); fflush(stderr);
1104
if (param->error_printed)
1106
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1109
"MyISAM-table '%s' is not fixed because of errors\n",
1111
if (param->testflag & T_REP_ANY)
1113
"Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n");
1115
else if (!(param->error_printed & 2) &&
1116
!(param->testflag & T_FORCE_CREATE))
1118
"MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
1121
else if (param->warning_printed &&
1122
! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1124
fprintf(stderr, "MyISAM-table '%s' is usable but should be fixed\n",
1131
/* Write info about table */
1133
static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
1135
uint32_t key,keyseg_nr,field,start;
1136
register MI_KEYDEF *keyinfo;
1137
register HA_KEYSEG *keyseg;
1138
register const char *text;
1139
char buff[160],length[10],*pos,*end;
1140
enum en_fieldtype type;
1141
MYISAM_SHARE *share=info->s;
1142
char llbuff[22],llbuff2[22];
1144
printf("\nMyISAM file: %s\n",name);
1145
fputs("Record format: ",stdout);
1146
if (share->options & HA_OPTION_COMPRESS_RECORD)
1148
else if (share->options & HA_OPTION_PACK_RECORD)
1151
puts("Fixed length");
1152
printf("Character set: %s (%d)\n",
1153
get_charset_name(share->state.header.language),
1154
share->state.header.language);
1156
if (param->testflag & T_VERBOSE)
1158
printf("File-version: %d\n",
1159
(int) share->state.header.file_version[3]);
1160
if (share->state.create_time)
1162
get_date(buff,1,share->state.create_time);
1163
printf("Creation time: %s\n",buff);
1165
if (share->state.check_time)
1167
get_date(buff,1,share->state.check_time);
1168
printf("Recover time: %s\n",buff);
1171
if (share->state.changed & STATE_CRASHED)
1172
my_stpcpy(buff,"crashed");
1175
if (share->state.open_count)
1176
pos=my_stpcpy(pos,"open,");
1177
if (share->state.changed & STATE_CHANGED)
1178
pos=my_stpcpy(pos,"changed,");
1180
pos=my_stpcpy(pos,"checked,");
1181
if (!(share->state.changed & STATE_NOT_ANALYZED))
1182
pos=my_stpcpy(pos,"analyzed,");
1183
if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1184
pos=my_stpcpy(pos,"optimized keys,");
1185
if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1186
pos=my_stpcpy(pos,"sorted index pages,");
1187
pos[-1]=0; /* Remove extra ',' */
1189
printf("Status: %s\n",buff);
1190
if (share->base.auto_key)
1192
printf("Auto increment key: %13d Last value: %13s\n",
1193
share->base.auto_key,
1194
llstr(share->state.auto_increment,llbuff));
1196
if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1197
printf("Checksum: %23s\n",llstr(info->state->checksum,llbuff));
1199
if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1200
printf("Keys are only flushed at close\n");
1203
printf("Data records: %13s Deleted blocks: %13s\n",
1204
llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1205
if (param->testflag & T_SILENT)
1206
return; /* This is enough */
1208
if (param->testflag & T_VERBOSE)
1211
printf("Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
1213
printf("Datafile parts: %13s Deleted data: %13s\n",
1214
llstr(share->state.split,llbuff),
1215
llstr(info->state->empty,llbuff2));
1216
printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
1217
share->rec_reflength,share->base.key_reflength);
1218
printf("Datafile length: %13s Keyfile length: %13s\n",
1219
llstr(info->state->data_file_length,llbuff),
1220
llstr(info->state->key_file_length,llbuff2));
1222
if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1223
puts("This is a one-record table");
1226
if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1227
share->base.max_key_file_length != HA_OFFSET_ERROR)
1228
printf("Max datafile length: %13s Max keyfile length: %13s\n",
1229
llstr(share->base.max_data_file_length-1,llbuff),
1230
llstr(share->base.max_key_file_length-1,llbuff2));
1234
printf("Recordlength: %13d\n",(int) share->base.pack_reclength);
1235
if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1237
int64_t2str(share->state.key_map,buff,2);
1238
printf("Using only keys '%s' of %d possibly keys\n",
1239
buff, share->base.keys);
1241
puts("\ntable description:");
1242
printf("Key Start Len Index Type");
1243
if (param->testflag & T_VERBOSE)
1244
printf(" Rec/key Root Blocksize");
1247
for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1248
key < share->base.keys;
1251
keyseg=keyinfo->seg;
1252
if (keyinfo->flag & HA_NOSAME) text="unique ";
1253
else text="multip.";
1256
if (keyseg->flag & HA_REVERSE_SORT)
1258
pos=my_stpcpy(pos,type_names[keyseg->type]);
1261
if (keyinfo->flag & HA_PACK_KEY)
1262
pos=my_stpcpy(pos,prefix_packed_txt);
1263
if (keyinfo->flag & HA_BINARY_PACK_KEY)
1264
pos=my_stpcpy(pos,bin_packed_txt);
1265
if (keyseg->flag & HA_SPACE_PACK)
1266
pos=my_stpcpy(pos,diff_txt);
1267
if (keyseg->flag & HA_BLOB_PART)
1268
pos=my_stpcpy(pos,blob_txt);
1269
if (keyseg->flag & HA_NULL_PART)
1270
pos=my_stpcpy(pos,null_txt);
1273
printf("%-4d%-6ld%-3d %-8s%-21s",
1274
key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1275
if (share->state.key_root[key] != HA_OFFSET_ERROR)
1276
llstr(share->state.key_root[key],buff);
1279
if (param->testflag & T_VERBOSE)
1280
printf("%11lu %12s %10d",
1281
share->state.rec_per_key_part[keyseg_nr++],
1282
buff,keyinfo->block_length);
1284
while ((++keyseg)->type != HA_KEYTYPE_END)
1287
if (keyseg->flag & HA_REVERSE_SORT)
1289
pos=my_stpcpy(pos,type_names[keyseg->type]);
1291
if (keyseg->flag & HA_SPACE_PACK)
1292
pos=my_stpcpy(pos,diff_txt);
1293
if (keyseg->flag & HA_BLOB_PART)
1294
pos=my_stpcpy(pos,blob_txt);
1295
if (keyseg->flag & HA_NULL_PART)
1296
pos=my_stpcpy(pos,null_txt);
1298
printf(" %-6ld%-3d %-21s",
1299
(long) keyseg->start+1,keyseg->length,buff);
1300
if (param->testflag & T_VERBOSE)
1301
printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1306
if (share->state.header.uniques)
1308
MI_UNIQUEDEF *uniqueinfo;
1309
puts("\nUnique Key Start Len Nullpos Nullbit Type");
1310
for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1311
key < share->state.header.uniques; key++, uniqueinfo++)
1314
char null_bit[8],null_pos[8];
1315
printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1316
for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1320
null_bit[0]=null_pos[0]=0;
1321
if (keyseg->null_bit)
1323
sprintf(null_bit,"%d",keyseg->null_bit);
1324
sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1326
printf("%-7ld%-5d%-9s%-10s%-30s\n",
1327
(long) keyseg->start+1,keyseg->length,
1329
type_names[keyseg->type]);
1334
if (param->verbose > 1)
1336
char null_bit[8],null_pos[8];
1337
printf("\nField Start Length Nullpos Nullbit Type");
1338
if (share->options & HA_OPTION_COMPRESS_RECORD)
1339
printf(" Huff tree Bits");
1342
for (field=0 ; field < share->base.fields ; field++)
1344
if (share->options & HA_OPTION_COMPRESS_RECORD)
1345
type=share->rec[field].base_type;
1347
type=(enum en_fieldtype) share->rec[field].type;
1348
end=my_stpcpy(buff,field_pack[type]);
1349
if (share->options & HA_OPTION_COMPRESS_RECORD)
1351
if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1352
end=my_stpcpy(end,", not_always");
1353
if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1354
end=my_stpcpy(end,", no empty");
1355
if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1357
sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
1358
end= strchr(end, '\0');
1362
my_stpcpy(buff,buff+2);
1363
int10_to_str((long) share->rec[field].length,length,10);
1364
null_bit[0]=null_pos[0]=0;
1365
if (share->rec[field].null_bit)
1367
sprintf(null_bit,"%d",share->rec[field].null_bit);
1368
sprintf(null_pos,"%d",share->rec[field].null_pos+1);
1370
printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1371
null_pos, null_bit, buff);
1372
if (share->options & HA_OPTION_COMPRESS_RECORD)
1374
if (share->rec[field].huff_tree)
1376
(uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1377
share->rec[field].huff_tree->quick_table_bits);
1380
start+=share->rec[field].length;
1387
/* Sort records according to one key */
1389
static int mi_sort_records(MI_CHECK *param,
1390
register MI_INFO *info, char * name,
1399
unsigned char *temp_buff;
1400
ha_rows old_record_count;
1401
MYISAM_SHARE *share=info->s;
1402
char llbuff[22],llbuff2[22];
1403
SORT_INFO sort_info;
1404
MI_SORT_PARAM sort_param;
1406
memset(&sort_info, 0, sizeof(sort_info));
1407
memset(&sort_param, 0, sizeof(sort_param));
1408
sort_param.sort_info=&sort_info;
1409
sort_info.param=param;
1410
keyinfo= &share->keyinfo[sort_key];
1415
if (! mi_is_key_active(share->state.key_map, sort_key))
1417
mi_check_print_warning(param,
1418
"Can't sort table '%s' on key %d; No such key",
1420
param->error_printed=0;
1421
return(0); /* Nothing to do */
1423
if (share->data_file_type == COMPRESSED_RECORD)
1425
mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
1426
param->error_printed=0;
1427
return(0); /* Nothing to do */
1429
if (!(param->testflag & T_SILENT))
1431
printf("- Sorting records for MyISAM-table '%s'\n",name);
1433
printf("Data records: %9s Deleted: %9s\n",
1434
llstr(info->state->records,llbuff),
1435
llstr(info->state->del,llbuff2));
1437
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1438
return(0); /* Nothing to do */
1440
init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers,
1442
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1443
WRITE_CACHE,share->pack.header_length,1,
1444
MYF(MY_WME | MY_WAIT_IF_FULL)))
1446
info->opt_flag|=WRITE_CACHE_USED;
1448
if (!(temp_buff=(unsigned char*) my_alloca((uint) keyinfo->block_length)))
1450
mi_check_print_error(param,"Not enough memory for key block");
1454
if (!mi_alloc_rec_buff(info, -1, &sort_param.record))
1456
mi_check_print_error(param,"Not enough memory for record");
1459
fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
1460
new_file=my_create(fn_format(param->temp_filename,
1461
param->temp_filename,"",
1463
0,param->tmpfile_createflag,
1467
mi_check_print_error(param,"Can't create new tempfile: '%s'",
1468
param->temp_filename);
1471
if (share->pack.header_length)
1472
if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1475
info->rec_cache.file=new_file; /* Use this file for cacheing*/
1478
for (key=0 ; key < share->base.keys ; key++)
1479
share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1481
if (my_pread(share->kfile,(unsigned char*) temp_buff,
1482
(uint) keyinfo->block_length,
1483
share->state.key_root[sort_key],
1484
MYF(MY_NABP+MY_WME)))
1486
mi_check_print_error(param,"Can't read indexpage from filepos: %s",
1487
(ulong) share->state.key_root[sort_key]);
1491
/* Setup param for sort_write_record */
1492
sort_info.info=info;
1493
sort_info.new_data_file_type=share->data_file_type;
1494
sort_param.fix_datafile=1;
1495
sort_param.master=1;
1496
sort_param.filepos=share->pack.header_length;
1497
old_record_count=info->state->records;
1498
info->state->records=0;
1499
if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1500
info->state->checksum=0;
1502
if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1503
temp_buff, sort_key,new_file,update_index) ||
1504
write_data_suffix(&sort_info,1) ||
1505
flush_io_cache(&info->rec_cache))
1508
if (info->state->records != old_record_count)
1510
mi_check_print_error(param,"found %s of %s records",
1511
llstr(info->state->records,llbuff),
1512
llstr(old_record_count,llbuff2));
1516
my_close(info->dfile,MYF(MY_WME));
1517
param->out_flag|=O_NEW_DATA; /* Data in new file */
1518
info->dfile=new_file; /* Use new datafile */
1520
info->state->empty=0;
1521
share->state.dellink= HA_OFFSET_ERROR;
1522
info->state->data_file_length=sort_param.filepos;
1523
share->state.split=info->state->records; /* Only hole records */
1524
share->state.version=(ulong) time((time_t*) 0);
1526
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1528
if (param->testflag & T_WRITE_LOOP)
1530
fputs(" \r",stdout); fflush(stdout);
1535
if (got_error && new_file >= 0)
1537
end_io_cache(&info->rec_cache);
1538
(void) my_close(new_file,MYF(MY_WME));
1539
(void) my_delete(param->temp_filename, MYF(MY_WME));
1543
my_afree((unsigned char*) temp_buff);
1545
void * rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
1546
if (rec_buff_ptr != NULL)
1549
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1550
end_io_cache(&info->rec_cache);
1551
free(sort_info.buff);
1553
share->state.sortkey=sort_key;
1554
return(flush_blocks(param, share->key_cache, share->kfile) |
1556
} /* sort_records */
1559
/* Sort records recursive using one index */
1561
static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
1563
my_off_t page, unsigned char *buff, uint32_t sort_key,
1564
File new_file,bool update_index)
1566
uint nod_flag,used_length,key_length;
1567
unsigned char *temp_buff,*keypos,*endpos;
1568
my_off_t next_page,rec_pos;
1569
unsigned char lastkey[MI_MAX_KEY_BUFF];
1571
SORT_INFO *sort_info= sort_param->sort_info;
1572
MI_CHECK *param=sort_info->param;
1574
nod_flag=mi_test_if_nod(buff);
1579
if (!(temp_buff=(unsigned char*) my_alloca((uint) keyinfo->block_length)))
1581
mi_check_print_error(param,"Not Enough memory");
1585
used_length=mi_getint(buff);
1586
keypos=buff+2+nod_flag;
1587
endpos=buff+used_length;
1592
next_page=_mi_kpos(nod_flag,keypos);
1593
if (my_pread(info->s->kfile,(unsigned char*) temp_buff,
1594
(uint) keyinfo->block_length, next_page,
1595
MYF(MY_NABP+MY_WME)))
1597
mi_check_print_error(param,"Can't read keys from filepos: %s",
1598
llstr(next_page,llbuff));
1601
if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1602
new_file, update_index))
1605
if (keypos >= endpos ||
1606
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1609
rec_pos= _mi_dpos(info,0,lastkey+key_length);
1611
if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1613
mi_check_print_error(param,"%d when reading datafile",my_errno);
1616
if (rec_pos != sort_param->filepos && update_index)
1618
_mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1619
sort_param->filepos);
1620
if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1623
mi_check_print_error(param,"%d when updating key-pointers",my_errno);
1627
if (sort_write_record(sort_param))
1630
/* Clear end of block to get better compression if the table is backuped */
1631
memset(buff+used_length, 0, keyinfo->block_length-used_length);
1632
if (my_pwrite(info->s->kfile,(unsigned char*) buff,(uint) keyinfo->block_length,
1633
page,param->myf_rw))
1635
mi_check_print_error(param,"%d when updating keyblock",my_errno);
1639
my_afree((unsigned char*) temp_buff);
1643
my_afree((unsigned char*) temp_buff);
1645
} /* sort_record_index */
1650
Check if myisamchk was killed by a signal
1651
This is overloaded by other programs that want to be able to abort
1655
static int not_killed= 0;
1657
volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
1659
return ¬_killed; /* always NULL */
1662
/* print warnings and errors */
1665
void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
1666
const char *fmt,...)
1671
vfprintf(stdout, fmt, args);
1678
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
1683
if (!param->warning_printed && !param->error_printed)
1685
if (param->testflag & T_SILENT)
1686
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,
1687
param->isam_file_name);
1688
param->out_flag|= O_DATA_LOST;
1690
param->warning_printed=1;
1692
fprintf(stderr,"%s: warning: ",my_progname_short);
1693
vfprintf(stderr, fmt, args);
1702
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
1707
if (!param->warning_printed && !param->error_printed)
1709
if (param->testflag & T_SILENT)
1710
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1711
param->out_flag|= O_DATA_LOST;
1713
param->error_printed|=1;
1715
fprintf(stderr,"%s: error: ",my_progname_short);
1716
vfprintf(stderr, fmt, args);