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 "myisamdef.h"
21
#include <mystrings/m_ctype.h>
22
#include <mysys/my_getopt.h>
23
#include <mysys/my_bit.h>
24
#include <mystrings/m_string.h>
27
#ifdef HAVE_SYS_VADVICE_H
28
#include <sys/vadvise.h>
30
#ifdef HAVE_SYS_MMAN_H
33
#include <drizzled/util/test.h>
36
pthread_mutex_t THR_LOCK_myisam= PTHREAD_MUTEX_INITIALIZER;
38
static uint32_t decode_bits;
39
static char **default_argv;
40
static const char *load_default_groups[]= { "myisamchk", 0 };
41
static const char *set_collation_name, *opt_tmpdir;
42
static const CHARSET_INFO *set_collation;
43
static long opt_myisam_block_size;
44
static long opt_key_cache_block_size;
45
static const char *my_progname_short;
47
static const char *type_names[]=
48
{ "impossible","char","binary", "short", "long", "float",
49
"double","number","unsigned short",
50
"unsigned long","int64_t","uint64_t","int24",
51
"uint24","int8","varchar", "varbin","?",
54
static const char *prefix_packed_txt="packed ",
55
*bin_packed_txt="prefix ",
56
*diff_txt="stripped ",
60
static const char *field_pack[]=
61
{"","no endspace", "no prespace",
62
"no zeros", "blob", "constant", "table-lockup",
63
"always zero","varchar","unique-hash","?","?"};
65
static const char *myisam_stats_method_str="nulls_unequal";
67
static void get_options(int *argc,char * * *argv);
68
static void print_version(void);
69
static void usage(void);
70
static int myisamchk(MI_CHECK *param, char *filename);
71
static void descript(MI_CHECK *param, register MI_INFO *info, char * name);
72
static int mi_sort_records(MI_CHECK *param, register MI_INFO *info,
73
char * name, uint32_t sort_key,
74
bool write_info, bool update_index);
75
static int sort_record_index(MI_SORT_PARAM *sort_param, MI_INFO *info,
77
my_off_t page,unsigned char *buff,uint32_t sortkey,
78
File new_file, bool update_index);
80
bool get_one_option(int optid, const struct my_option *, char *argument);
86
int main(int argc, char **argv)
90
my_progname_short= my_progname+dirname_length(my_progname);
92
myisamchk_init(&check_param);
93
check_param.opt_lock_memory=1; /* Lock memory if possible */
94
check_param.using_global_keycache = 0;
95
get_options(&argc,(char***) &argv);
96
myisam_quick_table_bits=decode_bits;
100
int new_error=myisamchk(&check_param, *(argv++));
101
if ((check_param.testflag & T_REP_ANY) != T_REP)
102
check_param.testflag&= ~T_REP;
105
if ((check_param.error_printed | check_param.warning_printed) &&
106
(check_param.testflag & T_FORCE_CREATE) &&
107
(!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
110
uint32_t old_testflag=check_param.testflag;
111
if (!(check_param.testflag & T_REP))
112
check_param.testflag|= T_REP_BY_SORT;
113
check_param.testflag&= ~T_EXTEND; /* Don't needed */
114
error|=myisamchk(&check_param, argv[-1]);
115
check_param.testflag= old_testflag;
121
if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
123
puts("\n---------\n");
127
if (check_param.total_files > 1)
128
{ /* Only if descript */
129
char buff[22],buff2[22];
130
if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
131
puts("\n---------\n");
132
printf("\nTotal of all %d MyISAM-files:\nData records: %9s Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
133
llstr(check_param.total_deleted,buff2));
136
pthread_mutex_destroy(&THR_LOCK_myisam);
138
free_defaults(default_argv);
139
my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
144
OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
145
OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE,
146
OPT_KEY_CACHE_BLOCK_SIZE, OPT_MYISAM_BLOCK_SIZE,
147
OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
148
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS,
149
OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD
152
static struct my_option my_long_options[] =
155
"Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
156
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
158
"Make a backup of the .MYD file as 'filename-time.BAK'.",
159
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
161
"Check table for errors.",
162
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
163
{"check-only-changed", 'C',
164
"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).",
165
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
166
{"correct-checksum", OPT_CORRECT_CHECKSUM,
167
"Correct checksum information for table.",
168
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
170
"Prints some information about table.",
171
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
172
{"data-file-length", 'D',
173
"Max length of data file (when recreating data-file when it's full).",
174
(char**) &check_param.max_data_file_length,
175
(char**) &check_param.max_data_file_length,
176
0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
177
{"extend-check", 'e',
178
"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.",
179
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
181
"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).",
182
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
184
"Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
185
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
187
"Display this help and exit.",
188
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
190
"Display this help and exit.",
191
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
193
"Print statistics information about table that is checked.",
194
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
196
"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.",
197
(char**) &check_param.keys_in_use,
198
(char**) &check_param.keys_in_use,
199
0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
200
{"max-record-length", OPT_MAX_RECORD_LENGTH,
201
"Skip rows bigger than this if myisamchk can't allocate memory to hold it",
202
(char**) &check_param.max_record_length,
203
(char**) &check_param.max_record_length,
204
0, GET_ULL, REQUIRED_ARG, INT64_MAX, 0, INT64_MAX, 0, 0, 0},
205
{"medium-check", 'm',
206
"Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
207
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
208
{"quick", 'q', "Faster repair by not modifying the data file.",
209
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
211
"Don't mark table as checked.",
212
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
214
"Can fix almost anything except unique keys that aren't unique.",
215
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
216
{"parallel-recover", 'p',
217
"Same as '-r' but creates all the keys in parallel.",
218
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
219
{"safe-recover", 'o',
220
"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.",
221
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
222
{"sort-recover", 'n',
223
"Force recovering with sorting even if the temporary file was very big.",
224
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
226
{"start-check-pos", OPT_START_CHECK_POS,
227
"No help available.",
228
0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
230
{"set-auto-increment", 'A',
231
"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.",
232
(char**) &check_param.auto_increment_value,
233
(char**) &check_param.auto_increment_value,
234
0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
235
{"set-collation", OPT_SET_COLLATION,
236
"Change the collation used by the index",
237
(char**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
238
{"set-variable", 'O',
239
"Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
240
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
242
"Only print errors. One can use two -s to make myisamchk very silent.",
243
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
245
"Sort index blocks. This speeds up 'read-next' in applications.",
246
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
247
{"sort-records", 'R',
248
"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!)",
249
(char**) &check_param.opt_sort_key,
250
(char**) &check_param.opt_sort_key,
251
0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
253
"Path for temporary files.",
254
(char**) &opt_tmpdir,
255
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
256
{"update-state", 'U',
257
"Mark tables as crashed if any errors were found.",
258
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
260
"Unpack file packed with myisampack.",
261
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
263
"Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
264
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
266
"Print version and exit.",
267
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
269
"Wait if table is locked.",
270
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
271
{ "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
272
(char**) &check_param.use_buffers, (char**) &check_param.use_buffers, 0,
273
GET_UINT64, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
274
INT32_MAX, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
275
{ "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "",
276
(char**) &opt_key_cache_block_size,
277
(char**) &opt_key_cache_block_size, 0,
278
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
279
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
280
{ "myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "",
281
(char**) &opt_myisam_block_size, (char**) &opt_myisam_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
{ "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
285
(char**) &check_param.read_buffer_length,
286
(char**) &check_param.read_buffer_length, 0, GET_SIZE, REQUIRED_ARG,
287
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
288
SIZE_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
289
{ "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
290
(char**) &check_param.write_buffer_length,
291
(char**) &check_param.write_buffer_length, 0, GET_SIZE, REQUIRED_ARG,
292
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
293
SIZE_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
294
{ "sort_buffer_size", OPT_SORT_BUFFER_SIZE, "",
295
(char**) &check_param.sort_buffer_length,
296
(char**) &check_param.sort_buffer_length, 0, GET_SIZE, REQUIRED_ARG,
297
(long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
298
SIZE_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
299
{ "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
300
(char**) &check_param.sort_key_blocks,
301
(char**) &check_param.sort_key_blocks, 0, GET_SIZE, REQUIRED_ARG,
302
BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
303
{ "decode_bits", OPT_DECODE_BITS, "", (char**) &decode_bits,
304
(char**) &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
305
{"stats_method", OPT_STATS_METHOD,
306
"Specifies how index statistics collection code should treat NULLs. "
307
"Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
308
"\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
309
(char**) &myisam_stats_method_str, (char**) &myisam_stats_method_str, 0,
310
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
311
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
315
static void print_version(void)
317
printf("%s Ver 2.7 for %s-%s at %s\n", my_progname, HOST_VENDOR, HOST_OS,
322
static void usage(void)
325
puts("By Monty, for your professional use");
326
puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
327
puts("Description, check and repair of MyISAM tables.");
328
puts("Used without options all tables on the command will be checked for errors");
329
printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname_short);
330
printf("\nGlobal options:\n");
332
-?, --help Display this help and exit.\n\
333
-O, --set-variable var=option.\n\
334
Change the value of a variable. Please note that\n\
335
this option is deprecated; you can set variables\n\
336
directly with '--variable-name=value'.\n\
337
-t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
338
specified, separated by ");
339
#if defined( __WIN__)
340
printf("semicolon (;)");
344
printf(", they will be used\n\
345
in a round-robin fashion.\n\
346
-s, --silent Only print errors. One can use two -s to make\n\
347
myisamchk very silent.\n\
348
-v, --verbose Print more information. This can be used with\n\
349
--description and --check. Use many -v for more verbosity.\n\
350
-V, --version Print version and exit.\n\
351
-w, --wait Wait if table is locked.\n\n");
353
puts(" --start-check-pos=# Start reading file at given offset.\n");
356
puts("Check options (check is the default action for myisamchk):\n\
357
-c, --check Check table for errors.\n\
358
-e, --extend-check Check the table VERY throughly. Only use this in\n\
359
extreme cases as myisamchk should normally be able to\n\
360
find out if the table is ok even without this switch.\n\
361
-F, --fast Check only tables that haven't been closed properly.\n\
362
-C, --check-only-changed\n\
363
Check only tables that have changed since last check.\n\
364
-f, --force Restart with '-r' if there are any errors in the table.\n\
365
States will be updated as with '--update-state'.\n\
366
-i, --information Print statistics information about table that is checked.\n\
367
-m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
368
all errors. Should be good enough for most cases.\n\
369
-U --update-state Mark tables as crashed if you find any errors.\n\
370
-T, --read-only Don't mark table as checked.\n");
372
puts("Repair options (When using '-r' or '-o'):\n\
373
-B, --backup Make a backup of the .MYD file as 'filename-time.BAK'.\n\
374
--correct-checksum Correct checksum information for table.\n\
375
-D, --data-file-length=# Max length of data file (when recreating data\n\
376
file when it's full).\n\
377
-e, --extend-check Try to recover every possible row from the data file\n\
378
Normally this will also find a lot of garbage rows;\n\
379
Don't use this option if you are not totally desperate.\n\
380
-f, --force Overwrite old temporary files.\n\
381
-k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\
382
bit mask of which keys to use. This can be used to\n\
383
get faster inserts.\n\
384
--max-record-length=#\n\
385
Skip rows bigger than this if myisamchk can't allocate\n\
386
memory to hold it.\n\
387
-r, --recover Can fix almost anything except unique keys that aren't\n\
389
-n, --sort-recover Forces recovering with sorting even if the temporary\n\
390
file would be very big.\n\
391
-p, --parallel-recover\n\
392
Uses the same technique as '-r' and '-n', but creates\n\
393
all the keys in parallel, in different threads.\n\
394
-o, --safe-recover Uses old recovery method; Slower than '-r' but can\n\
395
handle a couple of cases where '-r' reports that it\n\
396
can't fix the data file.\n\
397
--character-sets-dir=...\n\
398
Directory where character sets are.\n\
399
--set-collation=name\n\
400
Change the collation used by the index.\n\
401
-q, --quick Faster repair by not modifying the data file.\n\
402
One can give a second '-q' to force myisamchk to\n\
403
modify the original datafile in case of duplicate keys.\n\
404
NOTE: Tables where the data file is currupted can't be\n\
405
fixed with this option.\n\
406
-u, --unpack Unpack file packed with myisampack.\n\
409
puts("Other actions:\n\
410
-a, --analyze Analyze distribution of keys. Will make some joins in\n\
411
MySQL faster. You can check the calculated distribution\n\
412
by using '--description --verbose table_name'.\n\
413
--stats_method=name Specifies how index statistics collection code should\n\
414
treat NULLs. Possible values of name are \"nulls_unequal\"\n\
415
(default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
416
\"nulls_ignored\".\n\
417
-d, --description Prints some information about table.\n\
418
-A, --set-auto-increment[=value]\n\
419
Force auto_increment to start at this or higher value\n\
420
If no value is given, then sets the next auto_increment\n\
421
value to the highest used value for the auto key + 1.\n\
422
-S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
424
-R, --sort-records=#\n\
425
Sort records according to an index. This makes your\n\
426
data much more localized and may speed up things\n\
427
(It may be VERY slow to do a sort the first time!).\n");
429
print_defaults("drizzle", load_default_groups);
430
my_print_variables(my_long_options);
433
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
434
"nulls_ignored", NULL};
435
TYPELIB myisam_stats_method_typelib= {
436
array_elements(myisam_stats_method_names) - 1, "",
437
myisam_stats_method_names, NULL};
441
bool get_one_option(int optid, const struct my_option *, char *argument)
445
if (argument == disabled_my_option)
446
check_param.testflag&= ~T_STATISTICS;
448
check_param.testflag|= T_STATISTICS;
452
check_param.auto_increment_value= strtoull(argument, NULL, 0);
454
check_param.auto_increment_value= 0; /* Set to max used value */
455
check_param.testflag|= T_AUTO_INC;
458
check_param.search_after_block= strtoul(argument, NULL, 10);
461
if (argument == disabled_my_option)
462
check_param.testflag&= ~T_BACKUP_DATA;
464
check_param.testflag|= T_BACKUP_DATA;
467
if (argument == disabled_my_option)
468
check_param.testflag&= ~T_CHECK;
470
check_param.testflag|= T_CHECK;
473
if (argument == disabled_my_option)
474
check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
476
check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
479
check_param.max_data_file_length=strtoll(argument, NULL, 10);
481
case 's': /* silent */
482
if (argument == disabled_my_option)
483
check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
486
if (check_param.testflag & T_SILENT)
487
check_param.testflag|= T_VERY_SILENT;
488
check_param.testflag|= T_SILENT;
489
check_param.testflag&= ~T_WRITE_LOOP;
493
if (argument == disabled_my_option)
494
check_param.testflag&= ~T_WAIT_FOREVER;
496
check_param.testflag|= T_WAIT_FOREVER;
498
case 'd': /* description if isam-file */
499
if (argument == disabled_my_option)
500
check_param.testflag&= ~T_DESCRIPT;
502
check_param.testflag|= T_DESCRIPT;
504
case 'e': /* extend check */
505
if (argument == disabled_my_option)
506
check_param.testflag&= ~T_EXTEND;
508
check_param.testflag|= T_EXTEND;
511
if (argument == disabled_my_option)
512
check_param.testflag&= ~T_INFO;
514
check_param.testflag|= T_INFO;
517
if (argument == disabled_my_option)
519
check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
520
check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
524
check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
525
check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
529
if (argument == disabled_my_option)
530
check_param.testflag&= ~T_FAST;
532
check_param.testflag|= T_FAST;
535
check_param.keys_in_use= (uint64_t) strtoll(argument, NULL, 10);
538
if (argument == disabled_my_option)
539
check_param.testflag&= ~T_MEDIUM;
541
check_param.testflag|= T_MEDIUM; /* Medium check */
543
case 'r': /* Repair table */
544
check_param.testflag&= ~T_REP_ANY;
545
if (argument != disabled_my_option)
546
check_param.testflag|= T_REP_BY_SORT;
549
check_param.testflag&= ~T_REP_ANY;
550
if (argument != disabled_my_option)
551
check_param.testflag|= T_REP_PARALLEL;
554
check_param.testflag&= ~T_REP_ANY;
555
check_param.force_sort= 0;
556
if (argument != disabled_my_option)
558
check_param.testflag|= T_REP;
559
my_disable_async_io= true; /* More safety */
563
check_param.testflag&= ~T_REP_ANY;
564
if (argument == disabled_my_option)
565
check_param.force_sort= 0;
568
check_param.testflag|= T_REP_BY_SORT;
569
check_param.force_sort= 1;
573
if (argument == disabled_my_option)
574
check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
576
check_param.testflag|=
577
(check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
580
if (argument == disabled_my_option)
581
check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
583
check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
585
case 'v': /* Verbose */
586
if (argument == disabled_my_option)
588
check_param.testflag&= ~T_VERBOSE;
589
check_param.verbose=0;
593
check_param.testflag|= T_VERBOSE;
594
check_param.verbose++;
597
case 'R': /* Sort records */
598
if (argument == disabled_my_option)
599
check_param.testflag&= ~T_SORT_RECORDS;
602
check_param.testflag|= T_SORT_RECORDS;
603
check_param.opt_sort_key= (uint) atoi(argument) - 1;
604
if (check_param.opt_sort_key >= MI_MAX_KEY)
607
"The value of the sort key is bigger than max key: %d.\n",
613
case 'S': /* Sort index */
614
if (argument == disabled_my_option)
615
check_param.testflag&= ~T_SORT_INDEX;
617
check_param.testflag|= T_SORT_INDEX;
620
if (argument == disabled_my_option)
621
check_param.testflag&= ~T_READONLY;
623
check_param.testflag|= T_READONLY;
626
if (argument == disabled_my_option)
627
check_param.testflag&= ~T_UPDATE_STATE;
629
check_param.testflag|= T_UPDATE_STATE;
634
case OPT_CORRECT_CHECKSUM:
635
if (argument == disabled_my_option)
636
check_param.testflag&= ~T_CALC_CHECKSUM;
638
check_param.testflag|= T_CALC_CHECKSUM;
640
case OPT_STATS_METHOD:
643
enum_mi_stats_method method_conv;
644
myisam_stats_method_str= argument;
645
if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
647
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
652
method_conv= MI_STATS_METHOD_NULLS_EQUAL;
655
method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
658
method_conv= MI_STATS_METHOD_IGNORE_NULLS;
660
default: assert(0); /* Impossible */
661
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
664
check_param.stats_method= method_conv;
667
#ifdef DEBUG /* Only useful if debugging */
668
case OPT_START_CHECK_POS:
669
check_param.start_check_pos= strtoull(argument, NULL, 0);
673
my_print_help(my_long_options);
683
static void get_options(register int *argc,register char ***argv)
687
load_defaults("drizzle", load_default_groups, argc, argv);
689
if (isatty(fileno(stdout)))
690
check_param.testflag|=T_WRITE_LOOP;
692
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
695
/* If using repair, then update checksum if one uses --update-state */
696
if ((check_param.testflag & T_UPDATE_STATE) &&
697
(check_param.testflag & T_REP_ANY))
698
check_param.testflag|= T_CALC_CHECKSUM;
706
if ((check_param.testflag & T_UNPACK) &&
707
(check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
710
"%s: --unpack can't be used with --quick or --sort-records\n",
714
if ((check_param.testflag & T_READONLY) &&
715
(check_param.testflag &
716
(T_REP_ANY | T_STATISTICS | T_AUTO_INC |
717
T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
720
"%s: Can't use --readonly when repairing or sorting\n",
725
check_param.key_cache_block_size= opt_key_cache_block_size;
727
if (set_collation_name)
728
if (!(set_collation= get_charset_by_name(set_collation_name)))
731
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
738
static int myisamchk(MI_CHECK *param, char * filename)
740
int error,lock_type,recreate;
741
int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
742
uint32_t raid_chunks;
745
char llbuff[22],llbuff2[22];
746
bool state_updated=0;
749
param->out_flag=error=param->warning_printed=param->error_printed=
752
param->isam_file_name=filename; /* For error messages */
753
if (!(info=mi_open(filename,
754
(param->testflag & (T_DESCRIPT | T_READONLY)) ?
757
((param->testflag & T_WAIT_FOREVER) ?
758
HA_OPEN_WAIT_IF_LOCKED :
759
(param->testflag & T_DESCRIPT) ?
760
HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
762
/* Avoid twice printing of isam file name */
763
param->error_printed=1;
766
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);
768
case HA_ERR_NOT_A_TABLE:
769
mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
771
case HA_ERR_CRASHED_ON_USAGE:
772
mi_check_print_error(param,"'%s' is marked as crashed",filename);
774
case HA_ERR_CRASHED_ON_REPAIR:
775
mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
777
case HA_ERR_OLD_FILE:
778
mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
780
case HA_ERR_END_OF_FILE:
781
mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
784
mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
787
mi_check_print_error(param,"File '%s' doesn't exist",filename);
790
mi_check_print_error(param,"You don't have permission to use '%s'",filename);
793
mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
800
share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
801
share->tot_locks-= share->r_locks;
803
raid_chunks=share->base.raid_chunks;
806
Skip the checking of the file if:
807
We are using --fast and the table is closed properly
808
We are using --check-only-changed-tables and the table hasn't changed
810
if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
812
bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
814
if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
815
((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
816
STATE_CRASHED_ON_REPAIR) ||
817
!(param->testflag & T_CHECK_ONLY_CHANGED))))
820
if (info->s->base.keys && info->state->records)
822
if ((param->testflag & T_STATISTICS) &&
823
(share->state.changed & STATE_NOT_ANALYZED))
825
if ((param->testflag & T_SORT_INDEX) &&
826
(share->state.changed & STATE_NOT_SORTED_PAGES))
828
if ((param->testflag & T_REP_BY_SORT) &&
829
(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
832
if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
833
(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
834
STATE_CRASHED_ON_REPAIR)))
838
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
839
printf("MyISAM file: %s is already checked\n",filename);
842
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
849
if ((param->testflag & (T_REP_ANY | T_STATISTICS |
850
T_SORT_RECORDS | T_SORT_INDEX)) &&
851
(((param->testflag & T_UNPACK) &&
852
share->data_file_type == COMPRESSED_RECORD) ||
853
mi_uint2korr(share->state.header.state_info_length) !=
854
MI_STATE_INFO_SIZE ||
855
mi_uint2korr(share->state.header.base_info_length) !=
857
mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
858
~share->state.key_map) ||
859
test_if_almost_full(info) ||
860
info->s->state.header.file_version[3] != myisam_file_magic[3] ||
862
set_collation->number != share->state.header.language) ||
863
myisam_block_size != MI_KEY_BLOCK_LENGTH))
866
param->language= set_collation->number;
867
if (recreate_table(param, &info,filename))
870
"MyISAM-table '%s' is not fixed because of errors\n",
875
if (!(param->testflag & T_REP_ANY))
877
param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
878
if (!(param->testflag & T_SILENT))
879
printf("- '%s' has old table-format. Recreating index\n",filename);
883
share->tot_locks-= share->r_locks;
887
if (param->testflag & T_DESCRIPT)
889
param->total_files++;
890
param->total_records+=info->state->records;
891
param->total_deleted+=info->state->del;
892
descript(param, info, filename);
897
if (!(param->testflag & T_READONLY))
898
lock_type = F_WRLCK; /* table is changed */
901
if (info->lock_type == F_RDLCK)
902
info->lock_type=F_UNLCK; /* Read only table */
903
if (_mi_readinfo(info,lock_type,0))
905
mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
907
param->error_printed=0;
911
_mi_readinfo() has locked the table.
912
We mark the table as locked (without doing file locks) to be able to
913
use functions that only works on locked tables (like row caching).
915
mi_lock_database(info, F_EXTRA_LCK);
916
datafile=info->dfile;
918
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
920
if (param->testflag & T_REP_ANY)
922
uint64_t tmp=share->state.key_map;
923
mi_copy_keys_active(share->state.key_map, share->base.keys,
925
if (tmp != share->state.key_map)
926
info->update|=HA_STATE_CHANGED;
928
if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
930
if (param->testflag & T_FORCE_CREATE)
933
mi_check_print_info(param,"Creating new data file\n");
938
mi_check_print_error(param,
939
"Quick-recover aborted; Run recovery without switch 'q'");
944
if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
945
(mi_is_any_key_active(share->state.key_map) ||
946
(rep_quick && !param->keys_in_use && !recreate)) &&
947
mi_test_if_sort_rep(info, info->state->records,
948
info->s->state.key_map,
951
if (param->testflag & T_REP_BY_SORT)
952
error=mi_repair_by_sort(param,info,filename,rep_quick);
954
error=mi_repair_parallel(param,info,filename,rep_quick);
957
else if (param->testflag & T_REP_ANY)
958
error=mi_repair(param, info,filename,rep_quick);
960
if (!error && param->testflag & T_SORT_RECORDS)
964
We can't update the index in mi_sort_records if we have a
965
prefix compressed or fulltext index
968
for (key=0 ; key < share->base.keys; key++)
969
if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY))
972
error=mi_sort_records(param,info,filename,param->opt_sort_key,
973
/* what is the following parameter for ? */
974
(bool) !(param->testflag & T_REP),
976
datafile=info->dfile; /* This is now locked */
977
if (!error && !update_index)
980
puts("Table had a compressed index; We must now recreate the index");
981
error=mi_repair_by_sort(param,info,filename,1);
984
if (!error && param->testflag & T_SORT_INDEX)
985
error=mi_sort_index(param,info,filename);
987
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
988
STATE_CRASHED_ON_REPAIR);
990
mi_mark_crashed(info);
992
else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
994
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
995
printf("Checking MyISAM file: %s\n",filename);
996
if (!(param->testflag & T_SILENT))
997
printf("Data records: %7s Deleted blocks: %7s\n",
998
llstr(info->state->records,llbuff),
999
llstr(info->state->del,llbuff2));
1000
error =chk_status(param,info);
1001
mi_intersect_keys_active(share->state.key_map, param->keys_in_use);
1002
error =chk_size(param,info);
1003
if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1004
error|=chk_del(param, info,param->testflag);
1005
if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1006
!param->start_check_pos)))
1008
error|=chk_key(param, info);
1009
if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1010
error=update_state_info(param, info,
1011
((param->testflag & T_STATISTICS) ?
1013
((param->testflag & T_AUTO_INC) ?
1014
UPDATE_AUTO_INC : 0));
1016
if ((!rep_quick && !error) ||
1017
!(param->testflag & (T_FAST | T_FORCE_CREATE)))
1019
if (param->testflag & (T_EXTEND | T_MEDIUM))
1020
init_key_cache(dflt_key_cache,opt_key_cache_block_size,
1021
(size_t)param->use_buffers, 0, 0);
1022
init_io_cache(¶m->read_cache,datafile,
1023
(uint) param->read_buffer_length,
1025
(param->start_check_pos ?
1026
param->start_check_pos :
1027
share->pack.header_length),
1031
if ((info->s->options & (HA_OPTION_PACK_RECORD |
1032
HA_OPTION_COMPRESS_RECORD)) ||
1033
(param->testflag & (T_EXTEND | T_MEDIUM)))
1034
error|=chk_data_link(param, info, param->testflag & T_EXTEND);
1035
error|=flush_blocks(param, share->key_cache, share->kfile);
1036
end_io_cache(¶m->read_cache);
1040
if ((share->state.changed & STATE_CHANGED) &&
1041
(param->testflag & T_UPDATE_STATE))
1042
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1043
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1044
STATE_CRASHED_ON_REPAIR);
1046
else if (!mi_is_crashed(info) &&
1047
(param->testflag & T_UPDATE_STATE))
1048
{ /* Mark crashed */
1049
mi_mark_crashed(info);
1050
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1054
if ((param->testflag & T_AUTO_INC) ||
1055
((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1056
update_auto_increment_key(param, info,
1057
(bool) !test(param->testflag & T_AUTO_INC));
1059
if (!(param->testflag & T_DESCRIPT))
1061
if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1062
error|=update_state_info(param, info,
1064
(((param->testflag & T_REP_ANY) ?
1066
(state_updated ? UPDATE_STAT : 0) |
1067
((param->testflag & T_SORT_RECORDS) ?
1069
info->update&= ~HA_STATE_CHANGED;
1071
mi_lock_database(info, F_UNLCK);
1075
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
1080
if (param->out_flag & O_NEW_DATA)
1081
error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1083
((param->testflag & T_BACKUP_DATA) ?
1084
MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1085
if (param->out_flag & O_NEW_INDEX)
1086
error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1089
fflush(stdout); fflush(stderr);
1090
if (param->error_printed)
1092
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1095
"MyISAM-table '%s' is not fixed because of errors\n",
1097
if (param->testflag & T_REP_ANY)
1099
"Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n");
1101
else if (!(param->error_printed & 2) &&
1102
!(param->testflag & T_FORCE_CREATE))
1104
"MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
1107
else if (param->warning_printed &&
1108
! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1110
fprintf(stderr, "MyISAM-table '%s' is usable but should be fixed\n",
1117
/* Write info about table */
1119
static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
1121
uint32_t key,keyseg_nr,field,start;
1122
register MI_KEYDEF *keyinfo;
1123
register HA_KEYSEG *keyseg;
1124
register const char *text;
1125
char buff[160],length[10],*pos,*end;
1126
enum en_fieldtype type;
1127
MYISAM_SHARE *share=info->s;
1128
char llbuff[22],llbuff2[22];
1130
printf("\nMyISAM file: %s\n",name);
1131
fputs("Record format: ",stdout);
1132
if (share->options & HA_OPTION_COMPRESS_RECORD)
1134
else if (share->options & HA_OPTION_PACK_RECORD)
1137
puts("Fixed length");
1138
printf("Character set: %s (%d)\n",
1139
get_charset_name(share->state.header.language),
1140
share->state.header.language);
1142
if (param->testflag & T_VERBOSE)
1144
printf("File-version: %d\n",
1145
(int) share->state.header.file_version[3]);
1146
if (share->state.create_time)
1148
get_date(buff,1,share->state.create_time);
1149
printf("Creation time: %s\n",buff);
1151
if (share->state.check_time)
1153
get_date(buff,1,share->state.check_time);
1154
printf("Recover time: %s\n",buff);
1157
if (share->state.changed & STATE_CRASHED)
1158
strcpy(buff,"crashed");
1161
if (share->state.open_count)
1162
pos= strcpy(pos,"open,")+5;
1163
if (share->state.changed & STATE_CHANGED)
1164
pos= strcpy(pos,"changed,")+8;
1166
pos= strcpy(pos,"checked,")+8;
1167
if (!(share->state.changed & STATE_NOT_ANALYZED))
1168
pos= strcpy(pos,"analyzed,")+9;
1169
if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1170
pos= strcpy(pos,"optimized keys,")+15;
1171
if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1172
pos= strcpy(pos,"sorted index pages,")+19;
1173
pos[-1]=0; /* Remove extra ',' */
1175
printf("Status: %s\n",buff);
1176
if (share->base.auto_key)
1178
printf("Auto increment key: %13d Last value: %13s\n",
1179
share->base.auto_key,
1180
llstr(share->state.auto_increment,llbuff));
1182
if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1183
printf("Checksum: %23s\n",llstr(info->state->checksum,llbuff));
1185
if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1186
printf("Keys are only flushed at close\n");
1189
printf("Data records: %13s Deleted blocks: %13s\n",
1190
llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1191
if (param->testflag & T_SILENT)
1192
return; /* This is enough */
1194
if (param->testflag & T_VERBOSE)
1197
printf("Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
1199
printf("Datafile parts: %13s Deleted data: %13s\n",
1200
llstr(share->state.split,llbuff),
1201
llstr(info->state->empty,llbuff2));
1202
printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
1203
share->rec_reflength,share->base.key_reflength);
1204
printf("Datafile length: %13s Keyfile length: %13s\n",
1205
llstr(info->state->data_file_length,llbuff),
1206
llstr(info->state->key_file_length,llbuff2));
1208
if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1209
puts("This is a one-record table");
1212
if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1213
share->base.max_key_file_length != HA_OFFSET_ERROR)
1214
printf("Max datafile length: %13s Max keyfile length: %13s\n",
1215
llstr(share->base.max_data_file_length-1,llbuff),
1216
llstr(share->base.max_key_file_length-1,llbuff2));
1220
printf("Recordlength: %13d\n",(int) share->base.pack_reclength);
1221
if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1223
int64_t2str(share->state.key_map,buff,2);
1224
printf("Using only keys '%s' of %d possibly keys\n",
1225
buff, share->base.keys);
1227
puts("\ntable description:");
1228
printf("Key Start Len Index Type");
1229
if (param->testflag & T_VERBOSE)
1230
printf(" Rec/key Root Blocksize");
1233
for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1234
key < share->base.keys;
1237
keyseg=keyinfo->seg;
1238
if (keyinfo->flag & HA_NOSAME) text="unique ";
1239
else text="multip.";
1242
if (keyseg->flag & HA_REVERSE_SORT)
1244
pos= strcpy(pos,type_names[keyseg->type]);
1245
pos+= strlen(type_names[keyseg->type]);
1248
if (keyinfo->flag & HA_PACK_KEY)
1249
pos= strcpy(pos,prefix_packed_txt) + strlen(prefix_packed_txt);
1250
if (keyinfo->flag & HA_BINARY_PACK_KEY)
1251
pos= strcpy(pos,bin_packed_txt) + strlen(bin_packed_txt);
1252
if (keyseg->flag & HA_SPACE_PACK)
1253
pos= strcpy(pos,diff_txt) + strlen(diff_txt);
1254
if (keyseg->flag & HA_BLOB_PART)
1255
pos= strcpy(pos,blob_txt) + strlen(blob_txt);
1256
if (keyseg->flag & HA_NULL_PART)
1257
pos= strcpy(pos,null_txt) + strlen(null_txt);
1260
printf("%-4d%-6ld%-3d %-8s%-21s",
1261
key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1262
if (share->state.key_root[key] != HA_OFFSET_ERROR)
1263
llstr(share->state.key_root[key],buff);
1266
if (param->testflag & T_VERBOSE)
1267
printf("%11lu %12s %10d",
1268
share->state.rec_per_key_part[keyseg_nr++],
1269
buff,keyinfo->block_length);
1271
while ((++keyseg)->type != HA_KEYTYPE_END)
1274
if (keyseg->flag & HA_REVERSE_SORT)
1276
pos= strcpy(pos,type_names[keyseg->type]);
1277
pos+= strlen(type_names[keyseg->type]);
1279
if (keyseg->flag & HA_SPACE_PACK)
1280
pos= strcpy(pos,diff_txt) + strlen(diff_txt);
1281
if (keyseg->flag & HA_BLOB_PART)
1282
pos= strcpy(pos,blob_txt) + strlen(blob_txt);
1283
if (keyseg->flag & HA_NULL_PART)
1284
pos= strcpy(pos,null_txt) + strlen(null_txt);
1286
printf(" %-6ld%-3d %-21s",
1287
(long) keyseg->start+1,keyseg->length,buff);
1288
if (param->testflag & T_VERBOSE)
1289
printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1294
if (share->state.header.uniques)
1296
MI_UNIQUEDEF *uniqueinfo;
1297
puts("\nUnique Key Start Len Nullpos Nullbit Type");
1298
for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1299
key < share->state.header.uniques; key++, uniqueinfo++)
1302
char null_bit[8],null_pos[8];
1303
printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1304
for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1308
null_bit[0]=null_pos[0]=0;
1309
if (keyseg->null_bit)
1311
sprintf(null_bit,"%d",keyseg->null_bit);
1312
sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1314
printf("%-7ld%-5d%-9s%-10s%-30s\n",
1315
(long) keyseg->start+1,keyseg->length,
1317
type_names[keyseg->type]);
1322
if (param->verbose > 1)
1324
char null_bit[8],null_pos[8];
1325
printf("\nField Start Length Nullpos Nullbit Type");
1326
if (share->options & HA_OPTION_COMPRESS_RECORD)
1327
printf(" Huff tree Bits");
1330
for (field=0 ; field < share->base.fields ; field++)
1332
if (share->options & HA_OPTION_COMPRESS_RECORD)
1333
type=share->rec[field].base_type;
1335
type=(enum en_fieldtype) share->rec[field].type;
1336
end= strcpy(buff, field_pack[type]);
1337
end+= strlen(field_pack[type]);
1338
if (share->options & HA_OPTION_COMPRESS_RECORD)
1340
if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1341
end= strcpy(end,", not_always")+12;
1342
if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1343
end= strcpy(end,", no empty")+10;
1344
if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1346
sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
1347
end= strchr(end, '\0');
1351
strcpy(buff,buff+2);
1352
int10_to_str((long) share->rec[field].length,length,10);
1353
null_bit[0]=null_pos[0]=0;
1354
if (share->rec[field].null_bit)
1356
sprintf(null_bit,"%d",share->rec[field].null_bit);
1357
sprintf(null_pos,"%d",share->rec[field].null_pos+1);
1359
printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1360
null_pos, null_bit, buff);
1361
if (share->options & HA_OPTION_COMPRESS_RECORD)
1363
if (share->rec[field].huff_tree)
1365
(uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1366
share->rec[field].huff_tree->quick_table_bits);
1369
start+=share->rec[field].length;
1376
/* Sort records according to one key */
1378
static int mi_sort_records(MI_CHECK *param,
1379
register MI_INFO *info, char * name,
1388
unsigned char *temp_buff;
1389
ha_rows old_record_count;
1390
MYISAM_SHARE *share=info->s;
1391
char llbuff[22],llbuff2[22];
1392
SORT_INFO sort_info;
1393
MI_SORT_PARAM sort_param;
1395
memset(&sort_info, 0, sizeof(sort_info));
1396
memset(&sort_param, 0, sizeof(sort_param));
1397
sort_param.sort_info=&sort_info;
1398
sort_info.param=param;
1399
keyinfo= &share->keyinfo[sort_key];
1404
if (! mi_is_key_active(share->state.key_map, sort_key))
1406
mi_check_print_warning(param,
1407
"Can't sort table '%s' on key %d; No such key",
1409
param->error_printed=0;
1410
return(0); /* Nothing to do */
1412
if (share->data_file_type == COMPRESSED_RECORD)
1414
mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
1415
param->error_printed=0;
1416
return(0); /* Nothing to do */
1418
if (!(param->testflag & T_SILENT))
1420
printf("- Sorting records for MyISAM-table '%s'\n",name);
1422
printf("Data records: %9s Deleted: %9s\n",
1423
llstr(info->state->records,llbuff),
1424
llstr(info->state->del,llbuff2));
1426
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1427
return(0); /* Nothing to do */
1429
init_key_cache(dflt_key_cache, opt_key_cache_block_size,
1430
(size_t)param->use_buffers,
1432
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1433
WRITE_CACHE,share->pack.header_length,1,
1434
MYF(MY_WME | MY_WAIT_IF_FULL)))
1436
info->opt_flag|=WRITE_CACHE_USED;
1438
if (!(temp_buff=(unsigned char*) malloc(keyinfo->block_length)))
1440
mi_check_print_error(param,"Not enough memory for key block");
1444
if (!mi_alloc_rec_buff(info, (ulong)-1, &sort_param.record))
1446
mi_check_print_error(param,"Not enough memory for record");
1449
fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
1450
new_file=my_create(fn_format(param->temp_filename,
1451
param->temp_filename,"",
1453
0,param->tmpfile_createflag,
1457
mi_check_print_error(param,"Can't create new tempfile: '%s'",
1458
param->temp_filename);
1461
if (share->pack.header_length)
1462
if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1465
info->rec_cache.file=new_file; /* Use this file for cacheing*/
1468
for (key=0 ; key < share->base.keys ; key++)
1469
share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1471
if (my_pread(share->kfile,(unsigned char*) temp_buff,
1472
(uint) keyinfo->block_length,
1473
share->state.key_root[sort_key],
1474
MYF(MY_NABP+MY_WME)))
1476
mi_check_print_error(param,"Can't read indexpage from filepos: %s",
1477
(ulong) share->state.key_root[sort_key]);
1481
/* Setup param for sort_write_record */
1482
sort_info.info=info;
1483
sort_info.new_data_file_type=share->data_file_type;
1484
sort_param.fix_datafile=1;
1485
sort_param.master=1;
1486
sort_param.filepos=share->pack.header_length;
1487
old_record_count=info->state->records;
1488
info->state->records=0;
1489
if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1490
info->state->checksum=0;
1492
if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1493
temp_buff, sort_key,new_file,update_index) ||
1494
write_data_suffix(&sort_info,1) ||
1495
flush_io_cache(&info->rec_cache))
1498
if (info->state->records != old_record_count)
1500
mi_check_print_error(param,"found %s of %s records",
1501
llstr(info->state->records,llbuff),
1502
llstr(old_record_count,llbuff2));
1506
my_close(info->dfile,MYF(MY_WME));
1507
param->out_flag|=O_NEW_DATA; /* Data in new file */
1508
info->dfile=new_file; /* Use new datafile */
1510
info->state->empty=0;
1511
share->state.dellink= HA_OFFSET_ERROR;
1512
info->state->data_file_length=sort_param.filepos;
1513
share->state.split=info->state->records; /* Only hole records */
1514
share->state.version=(ulong) time((time_t*) 0);
1516
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1518
if (param->testflag & T_WRITE_LOOP)
1520
fputs(" \r",stdout); fflush(stdout);
1525
if (got_error && new_file >= 0)
1527
end_io_cache(&info->rec_cache);
1528
(void) my_close(new_file,MYF(MY_WME));
1529
(void) my_delete(param->temp_filename, MYF(MY_WME));
1533
free((unsigned char*) temp_buff);
1535
void * rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
1536
if (rec_buff_ptr != NULL)
1539
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1540
end_io_cache(&info->rec_cache);
1541
free(sort_info.buff);
1543
share->state.sortkey=sort_key;
1544
return(flush_blocks(param, share->key_cache, share->kfile) |
1546
} /* sort_records */
1549
/* Sort records recursive using one index */
1551
static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
1553
my_off_t page, unsigned char *buff, uint32_t sort_key,
1554
File new_file,bool update_index)
1556
uint nod_flag,used_length,key_length;
1557
unsigned char *temp_buff,*keypos,*endpos;
1558
my_off_t next_page,rec_pos;
1559
unsigned char lastkey[MI_MAX_KEY_BUFF];
1561
SORT_INFO *sort_info= sort_param->sort_info;
1562
MI_CHECK *param=sort_info->param;
1564
nod_flag=mi_test_if_nod(buff);
1569
if (!(temp_buff=(unsigned char*) malloc(keyinfo->block_length)))
1571
mi_check_print_error(param,"Not Enough memory");
1575
used_length=mi_getint(buff);
1576
keypos=buff+2+nod_flag;
1577
endpos=buff+used_length;
1582
next_page=_mi_kpos(nod_flag,keypos);
1583
if (my_pread(info->s->kfile,(unsigned char*) temp_buff,
1584
(uint) keyinfo->block_length, next_page,
1585
MYF(MY_NABP+MY_WME)))
1587
mi_check_print_error(param,"Can't read keys from filepos: %s",
1588
llstr(next_page,llbuff));
1591
if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1592
new_file, update_index))
1595
if (keypos >= endpos ||
1596
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1599
rec_pos= _mi_dpos(info,0,lastkey+key_length);
1601
if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1603
mi_check_print_error(param,"%d when reading datafile",my_errno);
1606
if (rec_pos != sort_param->filepos && update_index)
1608
_mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1609
sort_param->filepos);
1610
if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1613
mi_check_print_error(param,"%d when updating key-pointers",my_errno);
1617
if (sort_write_record(sort_param))
1620
/* Clear end of block to get better compression if the table is backuped */
1621
memset(buff+used_length, 0, keyinfo->block_length-used_length);
1622
if (my_pwrite(info->s->kfile,(unsigned char*) buff,(uint) keyinfo->block_length,
1623
page,param->myf_rw))
1625
mi_check_print_error(param,"%d when updating keyblock",my_errno);
1629
free((unsigned char*) temp_buff);
1633
free((unsigned char*) temp_buff);
1635
} /* sort_record_index */
1640
Check if myisamchk was killed by a signal
1641
This is overloaded by other programs that want to be able to abort
1645
static int not_killed= 0;
1647
volatile int *killed_ptr(MI_CHECK *)
1649
return ¬_killed; /* always NULL */
1652
/* print warnings and errors */
1655
void mi_check_print_info(MI_CHECK *,
1656
const char *fmt,...)
1661
vfprintf(stdout, fmt, args);
1668
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
1673
if (!param->warning_printed && !param->error_printed)
1675
if (param->testflag & T_SILENT)
1676
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,
1677
param->isam_file_name);
1678
param->out_flag|= O_DATA_LOST;
1680
param->warning_printed=1;
1682
fprintf(stderr,"%s: warning: ",my_progname_short);
1683
vfprintf(stderr, fmt, args);
1692
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
1697
if (!param->warning_printed && !param->error_printed)
1699
if (param->testflag & T_SILENT)
1700
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1701
param->out_flag|= O_DATA_LOST;
1703
param->error_printed|=1;
1705
fprintf(stderr,"%s: error: ",my_progname_short);
1706
vfprintf(stderr, fmt, args);