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);
84
int main(int argc, char **argv)
88
my_progname_short= my_progname+dirname_length(my_progname);
90
myisamchk_init(&check_param);
91
check_param.opt_lock_memory=1; /* Lock memory if possible */
92
check_param.using_global_keycache = 0;
93
get_options(&argc,(char***) &argv);
94
myisam_quick_table_bits=decode_bits;
98
int new_error=myisamchk(&check_param, *(argv++));
99
if ((check_param.testflag & T_REP_ANY) != T_REP)
100
check_param.testflag&= ~T_REP;
103
if ((check_param.error_printed | check_param.warning_printed) &&
104
(check_param.testflag & T_FORCE_CREATE) &&
105
(!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
108
uint32_t old_testflag=check_param.testflag;
109
if (!(check_param.testflag & T_REP))
110
check_param.testflag|= T_REP_BY_SORT;
111
check_param.testflag&= ~T_EXTEND; /* Don't needed */
112
error|=myisamchk(&check_param, argv[-1]);
113
check_param.testflag= old_testflag;
119
if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
121
puts("\n---------\n");
125
if (check_param.total_files > 1)
126
{ /* Only if descript */
127
char buff[22],buff2[22];
128
if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
129
puts("\n---------\n");
130
printf("\nTotal of all %d MyISAM-files:\nData records: %9s Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
131
llstr(check_param.total_deleted,buff2));
134
pthread_mutex_destroy(&THR_LOCK_myisam);
136
free_defaults(default_argv);
137
my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
140
return 0; /* No compiler warning */
145
OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
146
OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE,
147
OPT_KEY_CACHE_BLOCK_SIZE, OPT_MYISAM_BLOCK_SIZE,
148
OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
149
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS,
150
OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD
153
static struct my_option my_long_options[] =
156
"Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
157
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
158
{"block-search", 'b',
159
"No help available.",
160
0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
162
"Make a backup of the .MYD file as 'filename-time.BAK'.",
163
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
164
{"character-sets-dir", OPT_CHARSETS_DIR,
165
"Directory where character sets are.",
166
(char**) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
168
"Check table for errors.",
169
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
170
{"check-only-changed", 'C',
171
"Check only tables that have changed since last check. It also applies to other requested actions (e.g. --analyze will be ignored if the table is already analyzed).",
172
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
173
{"correct-checksum", OPT_CORRECT_CHECKSUM,
174
"Correct checksum information for table.",
175
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
177
"Prints some information about table.",
178
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
179
{"data-file-length", 'D',
180
"Max length of data file (when recreating data-file when it's full).",
181
(char**) &check_param.max_data_file_length,
182
(char**) &check_param.max_data_file_length,
183
0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
184
{"extend-check", 'e',
185
"If used when checking a table, ensure that the table is 100 percent consistent, which will take a long time. If used when repairing a table, try to recover every possible row from the data file. Normally this will also find a lot of garbage rows; Don't use this option with repair if you are not totally desperate.",
186
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
188
"Check only tables that haven't been closed properly. It also applies to other requested actions (e.g. --analyze will be ignored if the table is already analyzed).",
189
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
191
"Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
192
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
194
"Display this help and exit.",
195
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
197
"Display this help and exit.",
198
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
200
"Print statistics information about table that is checked.",
201
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
203
"Tell MyISAM to update only some specific keys. # is a bit mask of which keys to use. This can be used to get faster inserts.",
204
(char**) &check_param.keys_in_use,
205
(char**) &check_param.keys_in_use,
206
0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
207
{"max-record-length", OPT_MAX_RECORD_LENGTH,
208
"Skip rows bigger than this if myisamchk can't allocate memory to hold it",
209
(char**) &check_param.max_record_length,
210
(char**) &check_param.max_record_length,
211
0, GET_ULL, REQUIRED_ARG, INT64_MAX, 0, INT64_MAX, 0, 0, 0},
212
{"medium-check", 'm',
213
"Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
214
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
215
{"quick", 'q', "Faster repair by not modifying the data file.",
216
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
218
"Don't mark table as checked.",
219
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
221
"Can fix almost anything except unique keys that aren't unique.",
222
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
223
{"parallel-recover", 'p',
224
"Same as '-r' but creates all the keys in parallel.",
225
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
226
{"safe-recover", 'o',
227
"Uses old recovery method; Slower than '-r' but can handle a couple of cases where '-r' reports that it can't fix the data file.",
228
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
229
{"sort-recover", 'n',
230
"Force recovering with sorting even if the temporary file was very big.",
231
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
233
{"start-check-pos", OPT_START_CHECK_POS,
234
"No help available.",
235
0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
237
{"set-auto-increment", 'A',
238
"Force auto_increment to start at this or higher value. If no value is given, then sets the next auto_increment value to the highest used value for the auto key + 1.",
239
(char**) &check_param.auto_increment_value,
240
(char**) &check_param.auto_increment_value,
241
0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
242
{"set-collation", OPT_SET_COLLATION,
243
"Change the collation used by the index",
244
(char**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
245
{"set-variable", 'O',
246
"Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
247
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
249
"Only print errors. One can use two -s to make myisamchk very silent.",
250
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
252
"Sort index blocks. This speeds up 'read-next' in applications.",
253
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
254
{"sort-records", 'R',
255
"Sort records according to an index. This makes your data much more localized and may speed up things. (It may be VERY slow to do a sort the first time!)",
256
(char**) &check_param.opt_sort_key,
257
(char**) &check_param.opt_sort_key,
258
0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
260
"Path for temporary files.",
261
(char**) &opt_tmpdir,
262
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
263
{"update-state", 'U',
264
"Mark tables as crashed if any errors were found.",
265
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
267
"Unpack file packed with myisampack.",
268
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
270
"Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
271
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
273
"Print version and exit.",
274
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
276
"Wait if table is locked.",
277
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
278
{ "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
279
(char**) &check_param.use_buffers, (char**) &check_param.use_buffers, 0,
280
GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
281
INT32_MAX, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
282
{ "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "",
283
(char**) &opt_key_cache_block_size,
284
(char**) &opt_key_cache_block_size, 0,
285
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
286
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
287
{ "myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "",
288
(char**) &opt_myisam_block_size, (char**) &opt_myisam_block_size, 0,
289
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
290
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
291
{ "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
292
(char**) &check_param.read_buffer_length,
293
(char**) &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
294
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
295
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
296
{ "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
297
(char**) &check_param.write_buffer_length,
298
(char**) &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
299
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
300
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
301
{ "sort_buffer_size", OPT_SORT_BUFFER_SIZE, "",
302
(char**) &check_param.sort_buffer_length,
303
(char**) &check_param.sort_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
304
(long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
305
INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
306
{ "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
307
(char**) &check_param.sort_key_blocks,
308
(char**) &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
309
BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
310
{ "decode_bits", OPT_DECODE_BITS, "", (char**) &decode_bits,
311
(char**) &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
312
{"stats_method", OPT_STATS_METHOD,
313
"Specifies how index statistics collection code should treat NULLs. "
314
"Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
315
"\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
316
(char**) &myisam_stats_method_str, (char**) &myisam_stats_method_str, 0,
317
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
318
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
322
static void print_version(void)
324
printf("%s Ver 2.7 for %s at %s\n", my_progname, SYSTEM_TYPE,
329
static void usage(void)
332
puts("By Monty, for your professional use");
333
puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
334
puts("Description, check and repair of MyISAM tables.");
335
puts("Used without options all tables on the command will be checked for errors");
336
printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname_short);
337
printf("\nGlobal options:\n");
339
-?, --help Display this help and exit.\n\
340
-O, --set-variable var=option.\n\
341
Change the value of a variable. Please note that\n\
342
this option is deprecated; you can set variables\n\
343
directly with '--variable-name=value'.\n\
344
-t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
345
specified, separated by ");
346
#if defined( __WIN__)
347
printf("semicolon (;)");
351
printf(", they will be used\n\
352
in a round-robin fashion.\n\
353
-s, --silent Only print errors. One can use two -s to make\n\
354
myisamchk very silent.\n\
355
-v, --verbose Print more information. This can be used with\n\
356
--description and --check. Use many -v for more verbosity.\n\
357
-V, --version Print version and exit.\n\
358
-w, --wait Wait if table is locked.\n\n");
360
puts(" --start-check-pos=# Start reading file at given offset.\n");
363
puts("Check options (check is the default action for myisamchk):\n\
364
-c, --check Check table for errors.\n\
365
-e, --extend-check Check the table VERY throughly. Only use this in\n\
366
extreme cases as myisamchk should normally be able to\n\
367
find out if the table is ok even without this switch.\n\
368
-F, --fast Check only tables that haven't been closed properly.\n\
369
-C, --check-only-changed\n\
370
Check only tables that have changed since last check.\n\
371
-f, --force Restart with '-r' if there are any errors in the table.\n\
372
States will be updated as with '--update-state'.\n\
373
-i, --information Print statistics information about table that is checked.\n\
374
-m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
375
all errors. Should be good enough for most cases.\n\
376
-U --update-state Mark tables as crashed if you find any errors.\n\
377
-T, --read-only Don't mark table as checked.\n");
379
puts("Repair options (When using '-r' or '-o'):\n\
380
-B, --backup Make a backup of the .MYD file as 'filename-time.BAK'.\n\
381
--correct-checksum Correct checksum information for table.\n\
382
-D, --data-file-length=# Max length of data file (when recreating data\n\
383
file when it's full).\n\
384
-e, --extend-check Try to recover every possible row from the data file\n\
385
Normally this will also find a lot of garbage rows;\n\
386
Don't use this option if you are not totally desperate.\n\
387
-f, --force Overwrite old temporary files.\n\
388
-k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\
389
bit mask of which keys to use. This can be used to\n\
390
get faster inserts.\n\
391
--max-record-length=#\n\
392
Skip rows bigger than this if myisamchk can't allocate\n\
393
memory to hold it.\n\
394
-r, --recover Can fix almost anything except unique keys that aren't\n\
396
-n, --sort-recover Forces recovering with sorting even if the temporary\n\
397
file would be very big.\n\
398
-p, --parallel-recover\n\
399
Uses the same technique as '-r' and '-n', but creates\n\
400
all the keys in parallel, in different threads.\n\
401
-o, --safe-recover Uses old recovery method; Slower than '-r' but can\n\
402
handle a couple of cases where '-r' reports that it\n\
403
can't fix the data file.\n\
404
--character-sets-dir=...\n\
405
Directory where character sets are.\n\
406
--set-collation=name\n\
407
Change the collation used by the index.\n\
408
-q, --quick Faster repair by not modifying the data file.\n\
409
One can give a second '-q' to force myisamchk to\n\
410
modify the original datafile in case of duplicate keys.\n\
411
NOTE: Tables where the data file is currupted can't be\n\
412
fixed with this option.\n\
413
-u, --unpack Unpack file packed with myisampack.\n\
416
puts("Other actions:\n\
417
-a, --analyze Analyze distribution of keys. Will make some joins in\n\
418
MySQL faster. You can check the calculated distribution\n\
419
by using '--description --verbose table_name'.\n\
420
--stats_method=name Specifies how index statistics collection code should\n\
421
treat NULLs. Possible values of name are \"nulls_unequal\"\n\
422
(default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
423
\"nulls_ignored\".\n\
424
-d, --description Prints some information about table.\n\
425
-A, --set-auto-increment[=value]\n\
426
Force auto_increment to start at this or higher value\n\
427
If no value is given, then sets the next auto_increment\n\
428
value to the highest used value for the auto key + 1.\n\
429
-S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
431
-R, --sort-records=#\n\
432
Sort records according to an index. This makes your\n\
433
data much more localized and may speed up things\n\
434
(It may be VERY slow to do a sort the first time!).\n\
435
-b, --block-search=#\n\
436
Find a record, a block at given offset belongs to.");
438
print_defaults("drizzle", load_default_groups);
439
my_print_variables(my_long_options);
442
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
443
"nulls_ignored", NULL};
444
TYPELIB myisam_stats_method_typelib= {
445
array_elements(myisam_stats_method_names) - 1, "",
446
myisam_stats_method_names, NULL};
451
get_one_option(int optid,
452
const struct my_option *opt __attribute__((unused)),
457
if (argument == disabled_my_option)
458
check_param.testflag&= ~T_STATISTICS;
460
check_param.testflag|= T_STATISTICS;
464
check_param.auto_increment_value= strtoull(argument, NULL, 0);
466
check_param.auto_increment_value= 0; /* Set to max used value */
467
check_param.testflag|= T_AUTO_INC;
470
check_param.search_after_block= strtoul(argument, NULL, 10);
473
if (argument == disabled_my_option)
474
check_param.testflag&= ~T_BACKUP_DATA;
476
check_param.testflag|= T_BACKUP_DATA;
479
if (argument == disabled_my_option)
480
check_param.testflag&= ~T_CHECK;
482
check_param.testflag|= T_CHECK;
485
if (argument == disabled_my_option)
486
check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
488
check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
491
check_param.max_data_file_length=strtoll(argument, NULL, 10);
493
case 's': /* silent */
494
if (argument == disabled_my_option)
495
check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
498
if (check_param.testflag & T_SILENT)
499
check_param.testflag|= T_VERY_SILENT;
500
check_param.testflag|= T_SILENT;
501
check_param.testflag&= ~T_WRITE_LOOP;
505
if (argument == disabled_my_option)
506
check_param.testflag&= ~T_WAIT_FOREVER;
508
check_param.testflag|= T_WAIT_FOREVER;
510
case 'd': /* description if isam-file */
511
if (argument == disabled_my_option)
512
check_param.testflag&= ~T_DESCRIPT;
514
check_param.testflag|= T_DESCRIPT;
516
case 'e': /* extend check */
517
if (argument == disabled_my_option)
518
check_param.testflag&= ~T_EXTEND;
520
check_param.testflag|= T_EXTEND;
523
if (argument == disabled_my_option)
524
check_param.testflag&= ~T_INFO;
526
check_param.testflag|= T_INFO;
529
if (argument == disabled_my_option)
531
check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
532
check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
536
check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
537
check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
541
if (argument == disabled_my_option)
542
check_param.testflag&= ~T_FAST;
544
check_param.testflag|= T_FAST;
547
check_param.keys_in_use= (uint64_t) strtoll(argument, NULL, 10);
550
if (argument == disabled_my_option)
551
check_param.testflag&= ~T_MEDIUM;
553
check_param.testflag|= T_MEDIUM; /* Medium check */
555
case 'r': /* Repair table */
556
check_param.testflag&= ~T_REP_ANY;
557
if (argument != disabled_my_option)
558
check_param.testflag|= T_REP_BY_SORT;
561
check_param.testflag&= ~T_REP_ANY;
562
if (argument != disabled_my_option)
563
check_param.testflag|= T_REP_PARALLEL;
566
check_param.testflag&= ~T_REP_ANY;
567
check_param.force_sort= 0;
568
if (argument != disabled_my_option)
570
check_param.testflag|= T_REP;
571
my_disable_async_io= 1; /* More safety */
575
check_param.testflag&= ~T_REP_ANY;
576
if (argument == disabled_my_option)
577
check_param.force_sort= 0;
580
check_param.testflag|= T_REP_BY_SORT;
581
check_param.force_sort= 1;
585
if (argument == disabled_my_option)
586
check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
588
check_param.testflag|=
589
(check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
592
if (argument == disabled_my_option)
593
check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
595
check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
597
case 'v': /* Verbose */
598
if (argument == disabled_my_option)
600
check_param.testflag&= ~T_VERBOSE;
601
check_param.verbose=0;
605
check_param.testflag|= T_VERBOSE;
606
check_param.verbose++;
609
case 'R': /* Sort records */
610
if (argument == disabled_my_option)
611
check_param.testflag&= ~T_SORT_RECORDS;
614
check_param.testflag|= T_SORT_RECORDS;
615
check_param.opt_sort_key= (uint) atoi(argument) - 1;
616
if (check_param.opt_sort_key >= MI_MAX_KEY)
619
"The value of the sort key is bigger than max key: %d.\n",
625
case 'S': /* Sort index */
626
if (argument == disabled_my_option)
627
check_param.testflag&= ~T_SORT_INDEX;
629
check_param.testflag|= T_SORT_INDEX;
632
if (argument == disabled_my_option)
633
check_param.testflag&= ~T_READONLY;
635
check_param.testflag|= T_READONLY;
638
if (argument == disabled_my_option)
639
check_param.testflag&= ~T_UPDATE_STATE;
641
check_param.testflag|= T_UPDATE_STATE;
646
case OPT_CORRECT_CHECKSUM:
647
if (argument == disabled_my_option)
648
check_param.testflag&= ~T_CALC_CHECKSUM;
650
check_param.testflag|= T_CALC_CHECKSUM;
652
case OPT_STATS_METHOD:
655
enum_mi_stats_method method_conv;
656
myisam_stats_method_str= argument;
657
if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
659
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
664
method_conv= MI_STATS_METHOD_NULLS_EQUAL;
667
method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
670
method_conv= MI_STATS_METHOD_IGNORE_NULLS;
672
default: assert(0); /* Impossible */
673
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
676
check_param.stats_method= method_conv;
679
#ifdef DEBUG /* Only useful if debugging */
680
case OPT_START_CHECK_POS:
681
check_param.start_check_pos= strtoull(argument, NULL, 0);
685
my_print_help(my_long_options);
695
static void get_options(register int *argc,register char ***argv)
699
load_defaults("drizzle", load_default_groups, argc, argv);
701
if (isatty(fileno(stdout)))
702
check_param.testflag|=T_WRITE_LOOP;
704
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
707
/* If using repair, then update checksum if one uses --update-state */
708
if ((check_param.testflag & T_UPDATE_STATE) &&
709
(check_param.testflag & T_REP_ANY))
710
check_param.testflag|= T_CALC_CHECKSUM;
718
if ((check_param.testflag & T_UNPACK) &&
719
(check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
722
"%s: --unpack can't be used with --quick or --sort-records\n",
726
if ((check_param.testflag & T_READONLY) &&
727
(check_param.testflag &
728
(T_REP_ANY | T_STATISTICS | T_AUTO_INC |
729
T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
732
"%s: Can't use --readonly when repairing or sorting\n",
737
check_param.key_cache_block_size= opt_key_cache_block_size;
739
if (set_collation_name)
740
if (!(set_collation= get_charset_by_name(set_collation_name,
744
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
751
static int myisamchk(MI_CHECK *param, char * filename)
753
int error,lock_type,recreate;
754
int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
755
uint32_t raid_chunks;
758
char llbuff[22],llbuff2[22];
759
bool state_updated=0;
762
param->out_flag=error=param->warning_printed=param->error_printed=
765
param->isam_file_name=filename; /* For error messages */
766
if (!(info=mi_open(filename,
767
(param->testflag & (T_DESCRIPT | T_READONLY)) ?
770
((param->testflag & T_WAIT_FOREVER) ?
771
HA_OPEN_WAIT_IF_LOCKED :
772
(param->testflag & T_DESCRIPT) ?
773
HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
775
/* Avoid twice printing of isam file name */
776
param->error_printed=1;
779
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);
781
case HA_ERR_NOT_A_TABLE:
782
mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
784
case HA_ERR_CRASHED_ON_USAGE:
785
mi_check_print_error(param,"'%s' is marked as crashed",filename);
787
case HA_ERR_CRASHED_ON_REPAIR:
788
mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
790
case HA_ERR_OLD_FILE:
791
mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
793
case HA_ERR_END_OF_FILE:
794
mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
797
mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
800
mi_check_print_error(param,"File '%s' doesn't exist",filename);
803
mi_check_print_error(param,"You don't have permission to use '%s'",filename);
806
mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
813
share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
814
share->tot_locks-= share->r_locks;
816
raid_chunks=share->base.raid_chunks;
819
Skip the checking of the file if:
820
We are using --fast and the table is closed properly
821
We are using --check-only-changed-tables and the table hasn't changed
823
if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
825
bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
827
if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
828
((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
829
STATE_CRASHED_ON_REPAIR) ||
830
!(param->testflag & T_CHECK_ONLY_CHANGED))))
833
if (info->s->base.keys && info->state->records)
835
if ((param->testflag & T_STATISTICS) &&
836
(share->state.changed & STATE_NOT_ANALYZED))
838
if ((param->testflag & T_SORT_INDEX) &&
839
(share->state.changed & STATE_NOT_SORTED_PAGES))
841
if ((param->testflag & T_REP_BY_SORT) &&
842
(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
845
if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
846
(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
847
STATE_CRASHED_ON_REPAIR)))
851
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
852
printf("MyISAM file: %s is already checked\n",filename);
855
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
862
if ((param->testflag & (T_REP_ANY | T_STATISTICS |
863
T_SORT_RECORDS | T_SORT_INDEX)) &&
864
(((param->testflag & T_UNPACK) &&
865
share->data_file_type == COMPRESSED_RECORD) ||
866
mi_uint2korr(share->state.header.state_info_length) !=
867
MI_STATE_INFO_SIZE ||
868
mi_uint2korr(share->state.header.base_info_length) !=
870
mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
871
~share->state.key_map) ||
872
test_if_almost_full(info) ||
873
info->s->state.header.file_version[3] != myisam_file_magic[3] ||
875
set_collation->number != share->state.header.language) ||
876
myisam_block_size != MI_KEY_BLOCK_LENGTH))
879
param->language= set_collation->number;
880
if (recreate_table(param, &info,filename))
883
"MyISAM-table '%s' is not fixed because of errors\n",
888
if (!(param->testflag & T_REP_ANY))
890
param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
891
if (!(param->testflag & T_SILENT))
892
printf("- '%s' has old table-format. Recreating index\n",filename);
896
share->tot_locks-= share->r_locks;
900
if (param->testflag & T_DESCRIPT)
902
param->total_files++;
903
param->total_records+=info->state->records;
904
param->total_deleted+=info->state->del;
905
descript(param, info, filename);
910
if (!(param->testflag & T_READONLY))
911
lock_type = F_WRLCK; /* table is changed */
914
if (info->lock_type == F_RDLCK)
915
info->lock_type=F_UNLCK; /* Read only table */
916
if (_mi_readinfo(info,lock_type,0))
918
mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
920
param->error_printed=0;
924
_mi_readinfo() has locked the table.
925
We mark the table as locked (without doing file locks) to be able to
926
use functions that only works on locked tables (like row caching).
928
mi_lock_database(info, F_EXTRA_LCK);
929
datafile=info->dfile;
931
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
933
if (param->testflag & T_REP_ANY)
935
uint64_t tmp=share->state.key_map;
936
mi_copy_keys_active(share->state.key_map, share->base.keys,
938
if (tmp != share->state.key_map)
939
info->update|=HA_STATE_CHANGED;
941
if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
943
if (param->testflag & T_FORCE_CREATE)
946
mi_check_print_info(param,"Creating new data file\n");
951
mi_check_print_error(param,
952
"Quick-recover aborted; Run recovery without switch 'q'");
957
if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
958
(mi_is_any_key_active(share->state.key_map) ||
959
(rep_quick && !param->keys_in_use && !recreate)) &&
960
mi_test_if_sort_rep(info, info->state->records,
961
info->s->state.key_map,
964
if (param->testflag & T_REP_BY_SORT)
965
error=mi_repair_by_sort(param,info,filename,rep_quick);
967
error=mi_repair_parallel(param,info,filename,rep_quick);
970
else if (param->testflag & T_REP_ANY)
971
error=mi_repair(param, info,filename,rep_quick);
973
if (!error && param->testflag & T_SORT_RECORDS)
977
We can't update the index in mi_sort_records if we have a
978
prefix compressed or fulltext index
981
for (key=0 ; key < share->base.keys; key++)
982
if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY))
985
error=mi_sort_records(param,info,filename,param->opt_sort_key,
986
/* what is the following parameter for ? */
987
(bool) !(param->testflag & T_REP),
989
datafile=info->dfile; /* This is now locked */
990
if (!error && !update_index)
993
puts("Table had a compressed index; We must now recreate the index");
994
error=mi_repair_by_sort(param,info,filename,1);
997
if (!error && param->testflag & T_SORT_INDEX)
998
error=mi_sort_index(param,info,filename);
1000
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1001
STATE_CRASHED_ON_REPAIR);
1003
mi_mark_crashed(info);
1005
else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
1007
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1008
printf("Checking MyISAM file: %s\n",filename);
1009
if (!(param->testflag & T_SILENT))
1010
printf("Data records: %7s Deleted blocks: %7s\n",
1011
llstr(info->state->records,llbuff),
1012
llstr(info->state->del,llbuff2));
1013
error =chk_status(param,info);
1014
mi_intersect_keys_active(share->state.key_map, param->keys_in_use);
1015
error =chk_size(param,info);
1016
if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1017
error|=chk_del(param, info,param->testflag);
1018
if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1019
!param->start_check_pos)))
1021
error|=chk_key(param, info);
1022
if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1023
error=update_state_info(param, info,
1024
((param->testflag & T_STATISTICS) ?
1026
((param->testflag & T_AUTO_INC) ?
1027
UPDATE_AUTO_INC : 0));
1029
if ((!rep_quick && !error) ||
1030
!(param->testflag & (T_FAST | T_FORCE_CREATE)))
1032
if (param->testflag & (T_EXTEND | T_MEDIUM))
1033
init_key_cache(dflt_key_cache,opt_key_cache_block_size,
1034
param->use_buffers, 0, 0);
1035
init_io_cache(¶m->read_cache,datafile,
1036
(uint) param->read_buffer_length,
1038
(param->start_check_pos ?
1039
param->start_check_pos :
1040
share->pack.header_length),
1044
if ((info->s->options & (HA_OPTION_PACK_RECORD |
1045
HA_OPTION_COMPRESS_RECORD)) ||
1046
(param->testflag & (T_EXTEND | T_MEDIUM)))
1047
error|=chk_data_link(param, info, param->testflag & T_EXTEND);
1048
error|=flush_blocks(param, share->key_cache, share->kfile);
1049
end_io_cache(¶m->read_cache);
1053
if ((share->state.changed & STATE_CHANGED) &&
1054
(param->testflag & T_UPDATE_STATE))
1055
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1056
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1057
STATE_CRASHED_ON_REPAIR);
1059
else if (!mi_is_crashed(info) &&
1060
(param->testflag & T_UPDATE_STATE))
1061
{ /* Mark crashed */
1062
mi_mark_crashed(info);
1063
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1067
if ((param->testflag & T_AUTO_INC) ||
1068
((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1069
update_auto_increment_key(param, info,
1070
(bool) !test(param->testflag & T_AUTO_INC));
1072
if (!(param->testflag & T_DESCRIPT))
1074
if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1075
error|=update_state_info(param, info,
1077
(((param->testflag & T_REP_ANY) ?
1079
(state_updated ? UPDATE_STAT : 0) |
1080
((param->testflag & T_SORT_RECORDS) ?
1082
info->update&= ~HA_STATE_CHANGED;
1084
mi_lock_database(info, F_UNLCK);
1088
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
1093
if (param->out_flag & O_NEW_DATA)
1094
error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1096
((param->testflag & T_BACKUP_DATA) ?
1097
MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1098
if (param->out_flag & O_NEW_INDEX)
1099
error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1102
fflush(stdout); fflush(stderr);
1103
if (param->error_printed)
1105
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1108
"MyISAM-table '%s' is not fixed because of errors\n",
1110
if (param->testflag & T_REP_ANY)
1112
"Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n");
1114
else if (!(param->error_printed & 2) &&
1115
!(param->testflag & T_FORCE_CREATE))
1117
"MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
1120
else if (param->warning_printed &&
1121
! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1123
fprintf(stderr, "MyISAM-table '%s' is usable but should be fixed\n",
1130
/* Write info about table */
1132
static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
1134
uint32_t key,keyseg_nr,field,start;
1135
register MI_KEYDEF *keyinfo;
1136
register HA_KEYSEG *keyseg;
1137
register const char *text;
1138
char buff[160],length[10],*pos,*end;
1139
enum en_fieldtype type;
1140
MYISAM_SHARE *share=info->s;
1141
char llbuff[22],llbuff2[22];
1143
printf("\nMyISAM file: %s\n",name);
1144
fputs("Record format: ",stdout);
1145
if (share->options & HA_OPTION_COMPRESS_RECORD)
1147
else if (share->options & HA_OPTION_PACK_RECORD)
1150
puts("Fixed length");
1151
printf("Character set: %s (%d)\n",
1152
get_charset_name(share->state.header.language),
1153
share->state.header.language);
1155
if (param->testflag & T_VERBOSE)
1157
printf("File-version: %d\n",
1158
(int) share->state.header.file_version[3]);
1159
if (share->state.create_time)
1161
get_date(buff,1,share->state.create_time);
1162
printf("Creation time: %s\n",buff);
1164
if (share->state.check_time)
1166
get_date(buff,1,share->state.check_time);
1167
printf("Recover time: %s\n",buff);
1170
if (share->state.changed & STATE_CRASHED)
1171
strcpy(buff,"crashed");
1174
if (share->state.open_count)
1175
pos= strcpy(pos,"open,")+5;
1176
if (share->state.changed & STATE_CHANGED)
1177
pos= strcpy(pos,"changed,")+8;
1179
pos= strcpy(pos,"checked,")+8;
1180
if (!(share->state.changed & STATE_NOT_ANALYZED))
1181
pos= strcpy(pos,"analyzed,")+9;
1182
if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1183
pos= strcpy(pos,"optimized keys,")+15;
1184
if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1185
pos= strcpy(pos,"sorted index pages,")+19;
1186
pos[-1]=0; /* Remove extra ',' */
1188
printf("Status: %s\n",buff);
1189
if (share->base.auto_key)
1191
printf("Auto increment key: %13d Last value: %13s\n",
1192
share->base.auto_key,
1193
llstr(share->state.auto_increment,llbuff));
1195
if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1196
printf("Checksum: %23s\n",llstr(info->state->checksum,llbuff));
1198
if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1199
printf("Keys are only flushed at close\n");
1202
printf("Data records: %13s Deleted blocks: %13s\n",
1203
llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1204
if (param->testflag & T_SILENT)
1205
return; /* This is enough */
1207
if (param->testflag & T_VERBOSE)
1210
printf("Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
1212
printf("Datafile parts: %13s Deleted data: %13s\n",
1213
llstr(share->state.split,llbuff),
1214
llstr(info->state->empty,llbuff2));
1215
printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
1216
share->rec_reflength,share->base.key_reflength);
1217
printf("Datafile length: %13s Keyfile length: %13s\n",
1218
llstr(info->state->data_file_length,llbuff),
1219
llstr(info->state->key_file_length,llbuff2));
1221
if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1222
puts("This is a one-record table");
1225
if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1226
share->base.max_key_file_length != HA_OFFSET_ERROR)
1227
printf("Max datafile length: %13s Max keyfile length: %13s\n",
1228
llstr(share->base.max_data_file_length-1,llbuff),
1229
llstr(share->base.max_key_file_length-1,llbuff2));
1233
printf("Recordlength: %13d\n",(int) share->base.pack_reclength);
1234
if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1236
int64_t2str(share->state.key_map,buff,2);
1237
printf("Using only keys '%s' of %d possibly keys\n",
1238
buff, share->base.keys);
1240
puts("\ntable description:");
1241
printf("Key Start Len Index Type");
1242
if (param->testflag & T_VERBOSE)
1243
printf(" Rec/key Root Blocksize");
1246
for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1247
key < share->base.keys;
1250
keyseg=keyinfo->seg;
1251
if (keyinfo->flag & HA_NOSAME) text="unique ";
1252
else text="multip.";
1255
if (keyseg->flag & HA_REVERSE_SORT)
1257
pos= strcpy(pos,type_names[keyseg->type]);
1258
pos+= strlen(type_names[keyseg->type]);
1261
if (keyinfo->flag & HA_PACK_KEY)
1262
pos= strcpy(pos,prefix_packed_txt) + strlen(prefix_packed_txt);
1263
if (keyinfo->flag & HA_BINARY_PACK_KEY)
1264
pos= strcpy(pos,bin_packed_txt) + strlen(bin_packed_txt);
1265
if (keyseg->flag & HA_SPACE_PACK)
1266
pos= strcpy(pos,diff_txt) + strlen(diff_txt);
1267
if (keyseg->flag & HA_BLOB_PART)
1268
pos= strcpy(pos,blob_txt) + strlen(blob_txt);
1269
if (keyseg->flag & HA_NULL_PART)
1270
pos= strcpy(pos,null_txt) + strlen(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= strcpy(pos,type_names[keyseg->type]);
1290
pos+= strlen(type_names[keyseg->type]);
1292
if (keyseg->flag & HA_SPACE_PACK)
1293
pos= strcpy(pos,diff_txt) + strlen(diff_txt);
1294
if (keyseg->flag & HA_BLOB_PART)
1295
pos= strcpy(pos,blob_txt) + strlen(blob_txt);
1296
if (keyseg->flag & HA_NULL_PART)
1297
pos= strcpy(pos,null_txt) + strlen(null_txt);
1299
printf(" %-6ld%-3d %-21s",
1300
(long) keyseg->start+1,keyseg->length,buff);
1301
if (param->testflag & T_VERBOSE)
1302
printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1307
if (share->state.header.uniques)
1309
MI_UNIQUEDEF *uniqueinfo;
1310
puts("\nUnique Key Start Len Nullpos Nullbit Type");
1311
for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1312
key < share->state.header.uniques; key++, uniqueinfo++)
1315
char null_bit[8],null_pos[8];
1316
printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1317
for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1321
null_bit[0]=null_pos[0]=0;
1322
if (keyseg->null_bit)
1324
sprintf(null_bit,"%d",keyseg->null_bit);
1325
sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1327
printf("%-7ld%-5d%-9s%-10s%-30s\n",
1328
(long) keyseg->start+1,keyseg->length,
1330
type_names[keyseg->type]);
1335
if (param->verbose > 1)
1337
char null_bit[8],null_pos[8];
1338
printf("\nField Start Length Nullpos Nullbit Type");
1339
if (share->options & HA_OPTION_COMPRESS_RECORD)
1340
printf(" Huff tree Bits");
1343
for (field=0 ; field < share->base.fields ; field++)
1345
if (share->options & HA_OPTION_COMPRESS_RECORD)
1346
type=share->rec[field].base_type;
1348
type=(enum en_fieldtype) share->rec[field].type;
1349
end= strcpy(buff, field_pack[type]);
1350
end+= strlen(field_pack[type]);
1351
if (share->options & HA_OPTION_COMPRESS_RECORD)
1353
if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1354
end= strcpy(end,", not_always")+12;
1355
if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1356
end= strcpy(end,", no empty")+10;
1357
if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1359
sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
1360
end= strchr(end, '\0');
1364
strcpy(buff,buff+2);
1365
int10_to_str((long) share->rec[field].length,length,10);
1366
null_bit[0]=null_pos[0]=0;
1367
if (share->rec[field].null_bit)
1369
sprintf(null_bit,"%d",share->rec[field].null_bit);
1370
sprintf(null_pos,"%d",share->rec[field].null_pos+1);
1372
printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1373
null_pos, null_bit, buff);
1374
if (share->options & HA_OPTION_COMPRESS_RECORD)
1376
if (share->rec[field].huff_tree)
1378
(uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1379
share->rec[field].huff_tree->quick_table_bits);
1382
start+=share->rec[field].length;
1389
/* Sort records according to one key */
1391
static int mi_sort_records(MI_CHECK *param,
1392
register MI_INFO *info, char * name,
1401
unsigned char *temp_buff;
1402
ha_rows old_record_count;
1403
MYISAM_SHARE *share=info->s;
1404
char llbuff[22],llbuff2[22];
1405
SORT_INFO sort_info;
1406
MI_SORT_PARAM sort_param;
1408
memset(&sort_info, 0, sizeof(sort_info));
1409
memset(&sort_param, 0, sizeof(sort_param));
1410
sort_param.sort_info=&sort_info;
1411
sort_info.param=param;
1412
keyinfo= &share->keyinfo[sort_key];
1417
if (! mi_is_key_active(share->state.key_map, sort_key))
1419
mi_check_print_warning(param,
1420
"Can't sort table '%s' on key %d; No such key",
1422
param->error_printed=0;
1423
return(0); /* Nothing to do */
1425
if (share->data_file_type == COMPRESSED_RECORD)
1427
mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
1428
param->error_printed=0;
1429
return(0); /* Nothing to do */
1431
if (!(param->testflag & T_SILENT))
1433
printf("- Sorting records for MyISAM-table '%s'\n",name);
1435
printf("Data records: %9s Deleted: %9s\n",
1436
llstr(info->state->records,llbuff),
1437
llstr(info->state->del,llbuff2));
1439
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1440
return(0); /* Nothing to do */
1442
init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers,
1444
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1445
WRITE_CACHE,share->pack.header_length,1,
1446
MYF(MY_WME | MY_WAIT_IF_FULL)))
1448
info->opt_flag|=WRITE_CACHE_USED;
1450
if (!(temp_buff=(unsigned char*) malloc(keyinfo->block_length)))
1452
mi_check_print_error(param,"Not enough memory for key block");
1456
if (!mi_alloc_rec_buff(info, (ulong)-1, &sort_param.record))
1458
mi_check_print_error(param,"Not enough memory for record");
1461
fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
1462
new_file=my_create(fn_format(param->temp_filename,
1463
param->temp_filename,"",
1465
0,param->tmpfile_createflag,
1469
mi_check_print_error(param,"Can't create new tempfile: '%s'",
1470
param->temp_filename);
1473
if (share->pack.header_length)
1474
if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1477
info->rec_cache.file=new_file; /* Use this file for cacheing*/
1480
for (key=0 ; key < share->base.keys ; key++)
1481
share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1483
if (my_pread(share->kfile,(unsigned char*) temp_buff,
1484
(uint) keyinfo->block_length,
1485
share->state.key_root[sort_key],
1486
MYF(MY_NABP+MY_WME)))
1488
mi_check_print_error(param,"Can't read indexpage from filepos: %s",
1489
(ulong) share->state.key_root[sort_key]);
1493
/* Setup param for sort_write_record */
1494
sort_info.info=info;
1495
sort_info.new_data_file_type=share->data_file_type;
1496
sort_param.fix_datafile=1;
1497
sort_param.master=1;
1498
sort_param.filepos=share->pack.header_length;
1499
old_record_count=info->state->records;
1500
info->state->records=0;
1501
if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1502
info->state->checksum=0;
1504
if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1505
temp_buff, sort_key,new_file,update_index) ||
1506
write_data_suffix(&sort_info,1) ||
1507
flush_io_cache(&info->rec_cache))
1510
if (info->state->records != old_record_count)
1512
mi_check_print_error(param,"found %s of %s records",
1513
llstr(info->state->records,llbuff),
1514
llstr(old_record_count,llbuff2));
1518
my_close(info->dfile,MYF(MY_WME));
1519
param->out_flag|=O_NEW_DATA; /* Data in new file */
1520
info->dfile=new_file; /* Use new datafile */
1522
info->state->empty=0;
1523
share->state.dellink= HA_OFFSET_ERROR;
1524
info->state->data_file_length=sort_param.filepos;
1525
share->state.split=info->state->records; /* Only hole records */
1526
share->state.version=(ulong) time((time_t*) 0);
1528
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1530
if (param->testflag & T_WRITE_LOOP)
1532
fputs(" \r",stdout); fflush(stdout);
1537
if (got_error && new_file >= 0)
1539
end_io_cache(&info->rec_cache);
1540
(void) my_close(new_file,MYF(MY_WME));
1541
(void) my_delete(param->temp_filename, MYF(MY_WME));
1545
free((unsigned char*) temp_buff);
1547
void * rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
1548
if (rec_buff_ptr != NULL)
1551
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1552
end_io_cache(&info->rec_cache);
1553
free(sort_info.buff);
1555
share->state.sortkey=sort_key;
1556
return(flush_blocks(param, share->key_cache, share->kfile) |
1558
} /* sort_records */
1561
/* Sort records recursive using one index */
1563
static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
1565
my_off_t page, unsigned char *buff, uint32_t sort_key,
1566
File new_file,bool update_index)
1568
uint nod_flag,used_length,key_length;
1569
unsigned char *temp_buff,*keypos,*endpos;
1570
my_off_t next_page,rec_pos;
1571
unsigned char lastkey[MI_MAX_KEY_BUFF];
1573
SORT_INFO *sort_info= sort_param->sort_info;
1574
MI_CHECK *param=sort_info->param;
1576
nod_flag=mi_test_if_nod(buff);
1581
if (!(temp_buff=(unsigned char*) malloc(keyinfo->block_length)))
1583
mi_check_print_error(param,"Not Enough memory");
1587
used_length=mi_getint(buff);
1588
keypos=buff+2+nod_flag;
1589
endpos=buff+used_length;
1594
next_page=_mi_kpos(nod_flag,keypos);
1595
if (my_pread(info->s->kfile,(unsigned char*) temp_buff,
1596
(uint) keyinfo->block_length, next_page,
1597
MYF(MY_NABP+MY_WME)))
1599
mi_check_print_error(param,"Can't read keys from filepos: %s",
1600
llstr(next_page,llbuff));
1603
if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1604
new_file, update_index))
1607
if (keypos >= endpos ||
1608
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1611
rec_pos= _mi_dpos(info,0,lastkey+key_length);
1613
if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1615
mi_check_print_error(param,"%d when reading datafile",my_errno);
1618
if (rec_pos != sort_param->filepos && update_index)
1620
_mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1621
sort_param->filepos);
1622
if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1625
mi_check_print_error(param,"%d when updating key-pointers",my_errno);
1629
if (sort_write_record(sort_param))
1632
/* Clear end of block to get better compression if the table is backuped */
1633
memset(buff+used_length, 0, keyinfo->block_length-used_length);
1634
if (my_pwrite(info->s->kfile,(unsigned char*) buff,(uint) keyinfo->block_length,
1635
page,param->myf_rw))
1637
mi_check_print_error(param,"%d when updating keyblock",my_errno);
1641
free((unsigned char*) temp_buff);
1645
free((unsigned char*) temp_buff);
1647
} /* sort_record_index */
1652
Check if myisamchk was killed by a signal
1653
This is overloaded by other programs that want to be able to abort
1657
static int not_killed= 0;
1659
volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
1661
return ¬_killed; /* always NULL */
1664
/* print warnings and errors */
1667
void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
1668
const char *fmt,...)
1673
vfprintf(stdout, fmt, args);
1680
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
1685
if (!param->warning_printed && !param->error_printed)
1687
if (param->testflag & T_SILENT)
1688
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,
1689
param->isam_file_name);
1690
param->out_flag|= O_DATA_LOST;
1692
param->warning_printed=1;
1694
fprintf(stderr,"%s: warning: ",my_progname_short);
1695
vfprintf(stderr, fmt, args);
1704
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
1709
if (!param->warning_printed && !param->error_printed)
1711
if (param->testflag & T_SILENT)
1712
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1713
param->out_flag|= O_DATA_LOST;
1715
param->error_printed|=1;
1717
fprintf(stderr,"%s: error: ",my_progname_short);
1718
vfprintf(stderr, fmt, args);