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},
157
{"block-search", 'b',
158
"No help available.",
159
0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
161
"Make a backup of the .MYD file as 'filename-time.BAK'.",
162
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
164
"Check table for errors.",
165
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
166
{"check-only-changed", 'C',
167
"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).",
168
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
169
{"correct-checksum", OPT_CORRECT_CHECKSUM,
170
"Correct checksum information for table.",
171
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
173
"Prints some information about table.",
174
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
175
{"data-file-length", 'D',
176
"Max length of data file (when recreating data-file when it's full).",
177
(char**) &check_param.max_data_file_length,
178
(char**) &check_param.max_data_file_length,
179
0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
180
{"extend-check", 'e',
181
"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.",
182
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
184
"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).",
185
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
187
"Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
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
"Display this help and exit.",
194
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
196
"Print statistics information about table that is checked.",
197
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
199
"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.",
200
(char**) &check_param.keys_in_use,
201
(char**) &check_param.keys_in_use,
202
0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
203
{"max-record-length", OPT_MAX_RECORD_LENGTH,
204
"Skip rows bigger than this if myisamchk can't allocate memory to hold it",
205
(char**) &check_param.max_record_length,
206
(char**) &check_param.max_record_length,
207
0, GET_ULL, REQUIRED_ARG, INT64_MAX, 0, INT64_MAX, 0, 0, 0},
208
{"medium-check", 'm',
209
"Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
210
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
211
{"quick", 'q', "Faster repair by not modifying the data file.",
212
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
214
"Don't mark table as checked.",
215
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
217
"Can fix almost anything except unique keys that aren't unique.",
218
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
219
{"parallel-recover", 'p',
220
"Same as '-r' but creates all the keys in parallel.",
221
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
222
{"safe-recover", 'o',
223
"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.",
224
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
225
{"sort-recover", 'n',
226
"Force recovering with sorting even if the temporary file was very big.",
227
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
229
{"start-check-pos", OPT_START_CHECK_POS,
230
"No help available.",
231
0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
233
{"set-auto-increment", 'A',
234
"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.",
235
(char**) &check_param.auto_increment_value,
236
(char**) &check_param.auto_increment_value,
237
0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
238
{"set-collation", OPT_SET_COLLATION,
239
"Change the collation used by the index",
240
(char**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
241
{"set-variable", 'O',
242
"Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
243
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
245
"Only print errors. One can use two -s to make myisamchk very silent.",
246
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
248
"Sort index blocks. This speeds up 'read-next' in applications.",
249
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
250
{"sort-records", 'R',
251
"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!)",
252
(char**) &check_param.opt_sort_key,
253
(char**) &check_param.opt_sort_key,
254
0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
256
"Path for temporary files.",
257
(char**) &opt_tmpdir,
258
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
259
{"update-state", 'U',
260
"Mark tables as crashed if any errors were found.",
261
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
263
"Unpack file packed with myisampack.",
264
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
266
"Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
267
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
269
"Print version and exit.",
270
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
272
"Wait if table is locked.",
273
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
274
{ "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
275
(char**) &check_param.use_buffers, (char**) &check_param.use_buffers, 0,
276
GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
277
INT32_MAX, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
278
{ "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "",
279
(char**) &opt_key_cache_block_size,
280
(char**) &opt_key_cache_block_size, 0,
281
GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
282
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
283
{ "myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "",
284
(char**) &opt_myisam_block_size, (char**) &opt_myisam_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
{ "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
288
(char**) &check_param.read_buffer_length,
289
(char**) &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
290
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
291
SIZE_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
292
{ "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
293
(char**) &check_param.write_buffer_length,
294
(char**) &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
295
(long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
296
SIZE_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
297
{ "sort_buffer_size", OPT_SORT_BUFFER_SIZE, "",
298
(char**) &check_param.sort_buffer_length,
299
(char**) &check_param.sort_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
300
(long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
301
SIZE_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
302
{ "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
303
(char**) &check_param.sort_key_blocks,
304
(char**) &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
305
BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
306
{ "decode_bits", OPT_DECODE_BITS, "", (char**) &decode_bits,
307
(char**) &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
308
{"stats_method", OPT_STATS_METHOD,
309
"Specifies how index statistics collection code should treat NULLs. "
310
"Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
311
"\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
312
(char**) &myisam_stats_method_str, (char**) &myisam_stats_method_str, 0,
313
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
314
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
318
static void print_version(void)
320
printf("%s Ver 2.7 for %s at %s\n", my_progname, SYSTEM_TYPE,
325
static void usage(void)
328
puts("By Monty, for your professional use");
329
puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
330
puts("Description, check and repair of MyISAM tables.");
331
puts("Used without options all tables on the command will be checked for errors");
332
printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname_short);
333
printf("\nGlobal options:\n");
335
-?, --help Display this help and exit.\n\
336
-O, --set-variable var=option.\n\
337
Change the value of a variable. Please note that\n\
338
this option is deprecated; you can set variables\n\
339
directly with '--variable-name=value'.\n\
340
-t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
341
specified, separated by ");
342
#if defined( __WIN__)
343
printf("semicolon (;)");
347
printf(", they will be used\n\
348
in a round-robin fashion.\n\
349
-s, --silent Only print errors. One can use two -s to make\n\
350
myisamchk very silent.\n\
351
-v, --verbose Print more information. This can be used with\n\
352
--description and --check. Use many -v for more verbosity.\n\
353
-V, --version Print version and exit.\n\
354
-w, --wait Wait if table is locked.\n\n");
356
puts(" --start-check-pos=# Start reading file at given offset.\n");
359
puts("Check options (check is the default action for myisamchk):\n\
360
-c, --check Check table for errors.\n\
361
-e, --extend-check Check the table VERY throughly. Only use this in\n\
362
extreme cases as myisamchk should normally be able to\n\
363
find out if the table is ok even without this switch.\n\
364
-F, --fast Check only tables that haven't been closed properly.\n\
365
-C, --check-only-changed\n\
366
Check only tables that have changed since last check.\n\
367
-f, --force Restart with '-r' if there are any errors in the table.\n\
368
States will be updated as with '--update-state'.\n\
369
-i, --information Print statistics information about table that is checked.\n\
370
-m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
371
all errors. Should be good enough for most cases.\n\
372
-U --update-state Mark tables as crashed if you find any errors.\n\
373
-T, --read-only Don't mark table as checked.\n");
375
puts("Repair options (When using '-r' or '-o'):\n\
376
-B, --backup Make a backup of the .MYD file as 'filename-time.BAK'.\n\
377
--correct-checksum Correct checksum information for table.\n\
378
-D, --data-file-length=# Max length of data file (when recreating data\n\
379
file when it's full).\n\
380
-e, --extend-check Try to recover every possible row from the data file\n\
381
Normally this will also find a lot of garbage rows;\n\
382
Don't use this option if you are not totally desperate.\n\
383
-f, --force Overwrite old temporary files.\n\
384
-k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\
385
bit mask of which keys to use. This can be used to\n\
386
get faster inserts.\n\
387
--max-record-length=#\n\
388
Skip rows bigger than this if myisamchk can't allocate\n\
389
memory to hold it.\n\
390
-r, --recover Can fix almost anything except unique keys that aren't\n\
392
-n, --sort-recover Forces recovering with sorting even if the temporary\n\
393
file would be very big.\n\
394
-p, --parallel-recover\n\
395
Uses the same technique as '-r' and '-n', but creates\n\
396
all the keys in parallel, in different threads.\n\
397
-o, --safe-recover Uses old recovery method; Slower than '-r' but can\n\
398
handle a couple of cases where '-r' reports that it\n\
399
can't fix the data file.\n\
400
--character-sets-dir=...\n\
401
Directory where character sets are.\n\
402
--set-collation=name\n\
403
Change the collation used by the index.\n\
404
-q, --quick Faster repair by not modifying the data file.\n\
405
One can give a second '-q' to force myisamchk to\n\
406
modify the original datafile in case of duplicate keys.\n\
407
NOTE: Tables where the data file is currupted can't be\n\
408
fixed with this option.\n\
409
-u, --unpack Unpack file packed with myisampack.\n\
412
puts("Other actions:\n\
413
-a, --analyze Analyze distribution of keys. Will make some joins in\n\
414
MySQL faster. You can check the calculated distribution\n\
415
by using '--description --verbose table_name'.\n\
416
--stats_method=name Specifies how index statistics collection code should\n\
417
treat NULLs. Possible values of name are \"nulls_unequal\"\n\
418
(default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
419
\"nulls_ignored\".\n\
420
-d, --description Prints some information about table.\n\
421
-A, --set-auto-increment[=value]\n\
422
Force auto_increment to start at this or higher value\n\
423
If no value is given, then sets the next auto_increment\n\
424
value to the highest used value for the auto key + 1.\n\
425
-S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
427
-R, --sort-records=#\n\
428
Sort records according to an index. This makes your\n\
429
data much more localized and may speed up things\n\
430
(It may be VERY slow to do a sort the first time!).\n\
431
-b, --block-search=#\n\
432
Find a record, a block at given offset belongs to.");
434
print_defaults("drizzle", load_default_groups);
435
my_print_variables(my_long_options);
438
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
439
"nulls_ignored", NULL};
440
TYPELIB myisam_stats_method_typelib= {
441
array_elements(myisam_stats_method_names) - 1, "",
442
myisam_stats_method_names, NULL};
446
bool get_one_option(int optid, const struct my_option *, char *argument)
450
if (argument == disabled_my_option)
451
check_param.testflag&= ~T_STATISTICS;
453
check_param.testflag|= T_STATISTICS;
457
check_param.auto_increment_value= strtoull(argument, NULL, 0);
459
check_param.auto_increment_value= 0; /* Set to max used value */
460
check_param.testflag|= T_AUTO_INC;
463
check_param.search_after_block= strtoul(argument, NULL, 10);
466
if (argument == disabled_my_option)
467
check_param.testflag&= ~T_BACKUP_DATA;
469
check_param.testflag|= T_BACKUP_DATA;
472
if (argument == disabled_my_option)
473
check_param.testflag&= ~T_CHECK;
475
check_param.testflag|= T_CHECK;
478
if (argument == disabled_my_option)
479
check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
481
check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
484
check_param.max_data_file_length=strtoll(argument, NULL, 10);
486
case 's': /* silent */
487
if (argument == disabled_my_option)
488
check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
491
if (check_param.testflag & T_SILENT)
492
check_param.testflag|= T_VERY_SILENT;
493
check_param.testflag|= T_SILENT;
494
check_param.testflag&= ~T_WRITE_LOOP;
498
if (argument == disabled_my_option)
499
check_param.testflag&= ~T_WAIT_FOREVER;
501
check_param.testflag|= T_WAIT_FOREVER;
503
case 'd': /* description if isam-file */
504
if (argument == disabled_my_option)
505
check_param.testflag&= ~T_DESCRIPT;
507
check_param.testflag|= T_DESCRIPT;
509
case 'e': /* extend check */
510
if (argument == disabled_my_option)
511
check_param.testflag&= ~T_EXTEND;
513
check_param.testflag|= T_EXTEND;
516
if (argument == disabled_my_option)
517
check_param.testflag&= ~T_INFO;
519
check_param.testflag|= T_INFO;
522
if (argument == disabled_my_option)
524
check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
525
check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
529
check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
530
check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
534
if (argument == disabled_my_option)
535
check_param.testflag&= ~T_FAST;
537
check_param.testflag|= T_FAST;
540
check_param.keys_in_use= (uint64_t) strtoll(argument, NULL, 10);
543
if (argument == disabled_my_option)
544
check_param.testflag&= ~T_MEDIUM;
546
check_param.testflag|= T_MEDIUM; /* Medium check */
548
case 'r': /* Repair table */
549
check_param.testflag&= ~T_REP_ANY;
550
if (argument != disabled_my_option)
551
check_param.testflag|= T_REP_BY_SORT;
554
check_param.testflag&= ~T_REP_ANY;
555
if (argument != disabled_my_option)
556
check_param.testflag|= T_REP_PARALLEL;
559
check_param.testflag&= ~T_REP_ANY;
560
check_param.force_sort= 0;
561
if (argument != disabled_my_option)
563
check_param.testflag|= T_REP;
564
my_disable_async_io= 1; /* More safety */
568
check_param.testflag&= ~T_REP_ANY;
569
if (argument == disabled_my_option)
570
check_param.force_sort= 0;
573
check_param.testflag|= T_REP_BY_SORT;
574
check_param.force_sort= 1;
578
if (argument == disabled_my_option)
579
check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
581
check_param.testflag|=
582
(check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
585
if (argument == disabled_my_option)
586
check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
588
check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
590
case 'v': /* Verbose */
591
if (argument == disabled_my_option)
593
check_param.testflag&= ~T_VERBOSE;
594
check_param.verbose=0;
598
check_param.testflag|= T_VERBOSE;
599
check_param.verbose++;
602
case 'R': /* Sort records */
603
if (argument == disabled_my_option)
604
check_param.testflag&= ~T_SORT_RECORDS;
607
check_param.testflag|= T_SORT_RECORDS;
608
check_param.opt_sort_key= (uint) atoi(argument) - 1;
609
if (check_param.opt_sort_key >= MI_MAX_KEY)
612
"The value of the sort key is bigger than max key: %d.\n",
618
case 'S': /* Sort index */
619
if (argument == disabled_my_option)
620
check_param.testflag&= ~T_SORT_INDEX;
622
check_param.testflag|= T_SORT_INDEX;
625
if (argument == disabled_my_option)
626
check_param.testflag&= ~T_READONLY;
628
check_param.testflag|= T_READONLY;
631
if (argument == disabled_my_option)
632
check_param.testflag&= ~T_UPDATE_STATE;
634
check_param.testflag|= T_UPDATE_STATE;
639
case OPT_CORRECT_CHECKSUM:
640
if (argument == disabled_my_option)
641
check_param.testflag&= ~T_CALC_CHECKSUM;
643
check_param.testflag|= T_CALC_CHECKSUM;
645
case OPT_STATS_METHOD:
648
enum_mi_stats_method method_conv;
649
myisam_stats_method_str= argument;
650
if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
652
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
657
method_conv= MI_STATS_METHOD_NULLS_EQUAL;
660
method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
663
method_conv= MI_STATS_METHOD_IGNORE_NULLS;
665
default: assert(0); /* Impossible */
666
fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
669
check_param.stats_method= method_conv;
672
#ifdef DEBUG /* Only useful if debugging */
673
case OPT_START_CHECK_POS:
674
check_param.start_check_pos= strtoull(argument, NULL, 0);
678
my_print_help(my_long_options);
688
static void get_options(register int *argc,register char ***argv)
692
load_defaults("drizzle", load_default_groups, argc, argv);
694
if (isatty(fileno(stdout)))
695
check_param.testflag|=T_WRITE_LOOP;
697
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
700
/* If using repair, then update checksum if one uses --update-state */
701
if ((check_param.testflag & T_UPDATE_STATE) &&
702
(check_param.testflag & T_REP_ANY))
703
check_param.testflag|= T_CALC_CHECKSUM;
711
if ((check_param.testflag & T_UNPACK) &&
712
(check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
715
"%s: --unpack can't be used with --quick or --sort-records\n",
719
if ((check_param.testflag & T_READONLY) &&
720
(check_param.testflag &
721
(T_REP_ANY | T_STATISTICS | T_AUTO_INC |
722
T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
725
"%s: Can't use --readonly when repairing or sorting\n",
730
check_param.key_cache_block_size= opt_key_cache_block_size;
732
if (set_collation_name)
733
if (!(set_collation= get_charset_by_name(set_collation_name)))
736
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
743
static int myisamchk(MI_CHECK *param, char * filename)
745
int error,lock_type,recreate;
746
int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
747
uint32_t raid_chunks;
750
char llbuff[22],llbuff2[22];
751
bool state_updated=0;
754
param->out_flag=error=param->warning_printed=param->error_printed=
757
param->isam_file_name=filename; /* For error messages */
758
if (!(info=mi_open(filename,
759
(param->testflag & (T_DESCRIPT | T_READONLY)) ?
762
((param->testflag & T_WAIT_FOREVER) ?
763
HA_OPEN_WAIT_IF_LOCKED :
764
(param->testflag & T_DESCRIPT) ?
765
HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
767
/* Avoid twice printing of isam file name */
768
param->error_printed=1;
771
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);
773
case HA_ERR_NOT_A_TABLE:
774
mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
776
case HA_ERR_CRASHED_ON_USAGE:
777
mi_check_print_error(param,"'%s' is marked as crashed",filename);
779
case HA_ERR_CRASHED_ON_REPAIR:
780
mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
782
case HA_ERR_OLD_FILE:
783
mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
785
case HA_ERR_END_OF_FILE:
786
mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
789
mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
792
mi_check_print_error(param,"File '%s' doesn't exist",filename);
795
mi_check_print_error(param,"You don't have permission to use '%s'",filename);
798
mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
805
share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
806
share->tot_locks-= share->r_locks;
808
raid_chunks=share->base.raid_chunks;
811
Skip the checking of the file if:
812
We are using --fast and the table is closed properly
813
We are using --check-only-changed-tables and the table hasn't changed
815
if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
817
bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
819
if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
820
((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
821
STATE_CRASHED_ON_REPAIR) ||
822
!(param->testflag & T_CHECK_ONLY_CHANGED))))
825
if (info->s->base.keys && info->state->records)
827
if ((param->testflag & T_STATISTICS) &&
828
(share->state.changed & STATE_NOT_ANALYZED))
830
if ((param->testflag & T_SORT_INDEX) &&
831
(share->state.changed & STATE_NOT_SORTED_PAGES))
833
if ((param->testflag & T_REP_BY_SORT) &&
834
(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
837
if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
838
(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
839
STATE_CRASHED_ON_REPAIR)))
843
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
844
printf("MyISAM file: %s is already checked\n",filename);
847
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
854
if ((param->testflag & (T_REP_ANY | T_STATISTICS |
855
T_SORT_RECORDS | T_SORT_INDEX)) &&
856
(((param->testflag & T_UNPACK) &&
857
share->data_file_type == COMPRESSED_RECORD) ||
858
mi_uint2korr(share->state.header.state_info_length) !=
859
MI_STATE_INFO_SIZE ||
860
mi_uint2korr(share->state.header.base_info_length) !=
862
mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
863
~share->state.key_map) ||
864
test_if_almost_full(info) ||
865
info->s->state.header.file_version[3] != myisam_file_magic[3] ||
867
set_collation->number != share->state.header.language) ||
868
myisam_block_size != MI_KEY_BLOCK_LENGTH))
871
param->language= set_collation->number;
872
if (recreate_table(param, &info,filename))
875
"MyISAM-table '%s' is not fixed because of errors\n",
880
if (!(param->testflag & T_REP_ANY))
882
param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
883
if (!(param->testflag & T_SILENT))
884
printf("- '%s' has old table-format. Recreating index\n",filename);
888
share->tot_locks-= share->r_locks;
892
if (param->testflag & T_DESCRIPT)
894
param->total_files++;
895
param->total_records+=info->state->records;
896
param->total_deleted+=info->state->del;
897
descript(param, info, filename);
902
if (!(param->testflag & T_READONLY))
903
lock_type = F_WRLCK; /* table is changed */
906
if (info->lock_type == F_RDLCK)
907
info->lock_type=F_UNLCK; /* Read only table */
908
if (_mi_readinfo(info,lock_type,0))
910
mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
912
param->error_printed=0;
916
_mi_readinfo() has locked the table.
917
We mark the table as locked (without doing file locks) to be able to
918
use functions that only works on locked tables (like row caching).
920
mi_lock_database(info, F_EXTRA_LCK);
921
datafile=info->dfile;
923
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
925
if (param->testflag & T_REP_ANY)
927
uint64_t tmp=share->state.key_map;
928
mi_copy_keys_active(share->state.key_map, share->base.keys,
930
if (tmp != share->state.key_map)
931
info->update|=HA_STATE_CHANGED;
933
if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
935
if (param->testflag & T_FORCE_CREATE)
938
mi_check_print_info(param,"Creating new data file\n");
943
mi_check_print_error(param,
944
"Quick-recover aborted; Run recovery without switch 'q'");
949
if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
950
(mi_is_any_key_active(share->state.key_map) ||
951
(rep_quick && !param->keys_in_use && !recreate)) &&
952
mi_test_if_sort_rep(info, info->state->records,
953
info->s->state.key_map,
956
if (param->testflag & T_REP_BY_SORT)
957
error=mi_repair_by_sort(param,info,filename,rep_quick);
959
error=mi_repair_parallel(param,info,filename,rep_quick);
962
else if (param->testflag & T_REP_ANY)
963
error=mi_repair(param, info,filename,rep_quick);
965
if (!error && param->testflag & T_SORT_RECORDS)
969
We can't update the index in mi_sort_records if we have a
970
prefix compressed or fulltext index
973
for (key=0 ; key < share->base.keys; key++)
974
if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY))
977
error=mi_sort_records(param,info,filename,param->opt_sort_key,
978
/* what is the following parameter for ? */
979
(bool) !(param->testflag & T_REP),
981
datafile=info->dfile; /* This is now locked */
982
if (!error && !update_index)
985
puts("Table had a compressed index; We must now recreate the index");
986
error=mi_repair_by_sort(param,info,filename,1);
989
if (!error && param->testflag & T_SORT_INDEX)
990
error=mi_sort_index(param,info,filename);
992
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
993
STATE_CRASHED_ON_REPAIR);
995
mi_mark_crashed(info);
997
else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
999
if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1000
printf("Checking MyISAM file: %s\n",filename);
1001
if (!(param->testflag & T_SILENT))
1002
printf("Data records: %7s Deleted blocks: %7s\n",
1003
llstr(info->state->records,llbuff),
1004
llstr(info->state->del,llbuff2));
1005
error =chk_status(param,info);
1006
mi_intersect_keys_active(share->state.key_map, param->keys_in_use);
1007
error =chk_size(param,info);
1008
if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1009
error|=chk_del(param, info,param->testflag);
1010
if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1011
!param->start_check_pos)))
1013
error|=chk_key(param, info);
1014
if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1015
error=update_state_info(param, info,
1016
((param->testflag & T_STATISTICS) ?
1018
((param->testflag & T_AUTO_INC) ?
1019
UPDATE_AUTO_INC : 0));
1021
if ((!rep_quick && !error) ||
1022
!(param->testflag & (T_FAST | T_FORCE_CREATE)))
1024
if (param->testflag & (T_EXTEND | T_MEDIUM))
1025
init_key_cache(dflt_key_cache,opt_key_cache_block_size,
1026
param->use_buffers, 0, 0);
1027
init_io_cache(¶m->read_cache,datafile,
1028
(uint) param->read_buffer_length,
1030
(param->start_check_pos ?
1031
param->start_check_pos :
1032
share->pack.header_length),
1036
if ((info->s->options & (HA_OPTION_PACK_RECORD |
1037
HA_OPTION_COMPRESS_RECORD)) ||
1038
(param->testflag & (T_EXTEND | T_MEDIUM)))
1039
error|=chk_data_link(param, info, param->testflag & T_EXTEND);
1040
error|=flush_blocks(param, share->key_cache, share->kfile);
1041
end_io_cache(¶m->read_cache);
1045
if ((share->state.changed & STATE_CHANGED) &&
1046
(param->testflag & T_UPDATE_STATE))
1047
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1048
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1049
STATE_CRASHED_ON_REPAIR);
1051
else if (!mi_is_crashed(info) &&
1052
(param->testflag & T_UPDATE_STATE))
1053
{ /* Mark crashed */
1054
mi_mark_crashed(info);
1055
info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1059
if ((param->testflag & T_AUTO_INC) ||
1060
((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1061
update_auto_increment_key(param, info,
1062
(bool) !test(param->testflag & T_AUTO_INC));
1064
if (!(param->testflag & T_DESCRIPT))
1066
if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1067
error|=update_state_info(param, info,
1069
(((param->testflag & T_REP_ANY) ?
1071
(state_updated ? UPDATE_STAT : 0) |
1072
((param->testflag & T_SORT_RECORDS) ?
1074
info->update&= ~HA_STATE_CHANGED;
1076
mi_lock_database(info, F_UNLCK);
1080
mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
1085
if (param->out_flag & O_NEW_DATA)
1086
error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1088
((param->testflag & T_BACKUP_DATA) ?
1089
MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1090
if (param->out_flag & O_NEW_INDEX)
1091
error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1094
fflush(stdout); fflush(stderr);
1095
if (param->error_printed)
1097
if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1100
"MyISAM-table '%s' is not fixed because of errors\n",
1102
if (param->testflag & T_REP_ANY)
1104
"Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n");
1106
else if (!(param->error_printed & 2) &&
1107
!(param->testflag & T_FORCE_CREATE))
1109
"MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
1112
else if (param->warning_printed &&
1113
! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1115
fprintf(stderr, "MyISAM-table '%s' is usable but should be fixed\n",
1122
/* Write info about table */
1124
static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
1126
uint32_t key,keyseg_nr,field,start;
1127
register MI_KEYDEF *keyinfo;
1128
register HA_KEYSEG *keyseg;
1129
register const char *text;
1130
char buff[160],length[10],*pos,*end;
1131
enum en_fieldtype type;
1132
MYISAM_SHARE *share=info->s;
1133
char llbuff[22],llbuff2[22];
1135
printf("\nMyISAM file: %s\n",name);
1136
fputs("Record format: ",stdout);
1137
if (share->options & HA_OPTION_COMPRESS_RECORD)
1139
else if (share->options & HA_OPTION_PACK_RECORD)
1142
puts("Fixed length");
1143
printf("Character set: %s (%d)\n",
1144
get_charset_name(share->state.header.language),
1145
share->state.header.language);
1147
if (param->testflag & T_VERBOSE)
1149
printf("File-version: %d\n",
1150
(int) share->state.header.file_version[3]);
1151
if (share->state.create_time)
1153
get_date(buff,1,share->state.create_time);
1154
printf("Creation time: %s\n",buff);
1156
if (share->state.check_time)
1158
get_date(buff,1,share->state.check_time);
1159
printf("Recover time: %s\n",buff);
1162
if (share->state.changed & STATE_CRASHED)
1163
strcpy(buff,"crashed");
1166
if (share->state.open_count)
1167
pos= strcpy(pos,"open,")+5;
1168
if (share->state.changed & STATE_CHANGED)
1169
pos= strcpy(pos,"changed,")+8;
1171
pos= strcpy(pos,"checked,")+8;
1172
if (!(share->state.changed & STATE_NOT_ANALYZED))
1173
pos= strcpy(pos,"analyzed,")+9;
1174
if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1175
pos= strcpy(pos,"optimized keys,")+15;
1176
if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1177
pos= strcpy(pos,"sorted index pages,")+19;
1178
pos[-1]=0; /* Remove extra ',' */
1180
printf("Status: %s\n",buff);
1181
if (share->base.auto_key)
1183
printf("Auto increment key: %13d Last value: %13s\n",
1184
share->base.auto_key,
1185
llstr(share->state.auto_increment,llbuff));
1187
if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1188
printf("Checksum: %23s\n",llstr(info->state->checksum,llbuff));
1190
if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1191
printf("Keys are only flushed at close\n");
1194
printf("Data records: %13s Deleted blocks: %13s\n",
1195
llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1196
if (param->testflag & T_SILENT)
1197
return; /* This is enough */
1199
if (param->testflag & T_VERBOSE)
1202
printf("Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
1204
printf("Datafile parts: %13s Deleted data: %13s\n",
1205
llstr(share->state.split,llbuff),
1206
llstr(info->state->empty,llbuff2));
1207
printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
1208
share->rec_reflength,share->base.key_reflength);
1209
printf("Datafile length: %13s Keyfile length: %13s\n",
1210
llstr(info->state->data_file_length,llbuff),
1211
llstr(info->state->key_file_length,llbuff2));
1213
if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1214
puts("This is a one-record table");
1217
if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1218
share->base.max_key_file_length != HA_OFFSET_ERROR)
1219
printf("Max datafile length: %13s Max keyfile length: %13s\n",
1220
llstr(share->base.max_data_file_length-1,llbuff),
1221
llstr(share->base.max_key_file_length-1,llbuff2));
1225
printf("Recordlength: %13d\n",(int) share->base.pack_reclength);
1226
if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1228
int64_t2str(share->state.key_map,buff,2);
1229
printf("Using only keys '%s' of %d possibly keys\n",
1230
buff, share->base.keys);
1232
puts("\ntable description:");
1233
printf("Key Start Len Index Type");
1234
if (param->testflag & T_VERBOSE)
1235
printf(" Rec/key Root Blocksize");
1238
for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1239
key < share->base.keys;
1242
keyseg=keyinfo->seg;
1243
if (keyinfo->flag & HA_NOSAME) text="unique ";
1244
else text="multip.";
1247
if (keyseg->flag & HA_REVERSE_SORT)
1249
pos= strcpy(pos,type_names[keyseg->type]);
1250
pos+= strlen(type_names[keyseg->type]);
1253
if (keyinfo->flag & HA_PACK_KEY)
1254
pos= strcpy(pos,prefix_packed_txt) + strlen(prefix_packed_txt);
1255
if (keyinfo->flag & HA_BINARY_PACK_KEY)
1256
pos= strcpy(pos,bin_packed_txt) + strlen(bin_packed_txt);
1257
if (keyseg->flag & HA_SPACE_PACK)
1258
pos= strcpy(pos,diff_txt) + strlen(diff_txt);
1259
if (keyseg->flag & HA_BLOB_PART)
1260
pos= strcpy(pos,blob_txt) + strlen(blob_txt);
1261
if (keyseg->flag & HA_NULL_PART)
1262
pos= strcpy(pos,null_txt) + strlen(null_txt);
1265
printf("%-4d%-6ld%-3d %-8s%-21s",
1266
key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1267
if (share->state.key_root[key] != HA_OFFSET_ERROR)
1268
llstr(share->state.key_root[key],buff);
1271
if (param->testflag & T_VERBOSE)
1272
printf("%11lu %12s %10d",
1273
share->state.rec_per_key_part[keyseg_nr++],
1274
buff,keyinfo->block_length);
1276
while ((++keyseg)->type != HA_KEYTYPE_END)
1279
if (keyseg->flag & HA_REVERSE_SORT)
1281
pos= strcpy(pos,type_names[keyseg->type]);
1282
pos+= strlen(type_names[keyseg->type]);
1284
if (keyseg->flag & HA_SPACE_PACK)
1285
pos= strcpy(pos,diff_txt) + strlen(diff_txt);
1286
if (keyseg->flag & HA_BLOB_PART)
1287
pos= strcpy(pos,blob_txt) + strlen(blob_txt);
1288
if (keyseg->flag & HA_NULL_PART)
1289
pos= strcpy(pos,null_txt) + strlen(null_txt);
1291
printf(" %-6ld%-3d %-21s",
1292
(long) keyseg->start+1,keyseg->length,buff);
1293
if (param->testflag & T_VERBOSE)
1294
printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1299
if (share->state.header.uniques)
1301
MI_UNIQUEDEF *uniqueinfo;
1302
puts("\nUnique Key Start Len Nullpos Nullbit Type");
1303
for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1304
key < share->state.header.uniques; key++, uniqueinfo++)
1307
char null_bit[8],null_pos[8];
1308
printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1309
for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1313
null_bit[0]=null_pos[0]=0;
1314
if (keyseg->null_bit)
1316
sprintf(null_bit,"%d",keyseg->null_bit);
1317
sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1319
printf("%-7ld%-5d%-9s%-10s%-30s\n",
1320
(long) keyseg->start+1,keyseg->length,
1322
type_names[keyseg->type]);
1327
if (param->verbose > 1)
1329
char null_bit[8],null_pos[8];
1330
printf("\nField Start Length Nullpos Nullbit Type");
1331
if (share->options & HA_OPTION_COMPRESS_RECORD)
1332
printf(" Huff tree Bits");
1335
for (field=0 ; field < share->base.fields ; field++)
1337
if (share->options & HA_OPTION_COMPRESS_RECORD)
1338
type=share->rec[field].base_type;
1340
type=(enum en_fieldtype) share->rec[field].type;
1341
end= strcpy(buff, field_pack[type]);
1342
end+= strlen(field_pack[type]);
1343
if (share->options & HA_OPTION_COMPRESS_RECORD)
1345
if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1346
end= strcpy(end,", not_always")+12;
1347
if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1348
end= strcpy(end,", no empty")+10;
1349
if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1351
sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
1352
end= strchr(end, '\0');
1356
strcpy(buff,buff+2);
1357
int10_to_str((long) share->rec[field].length,length,10);
1358
null_bit[0]=null_pos[0]=0;
1359
if (share->rec[field].null_bit)
1361
sprintf(null_bit,"%d",share->rec[field].null_bit);
1362
sprintf(null_pos,"%d",share->rec[field].null_pos+1);
1364
printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1365
null_pos, null_bit, buff);
1366
if (share->options & HA_OPTION_COMPRESS_RECORD)
1368
if (share->rec[field].huff_tree)
1370
(uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1371
share->rec[field].huff_tree->quick_table_bits);
1374
start+=share->rec[field].length;
1381
/* Sort records according to one key */
1383
static int mi_sort_records(MI_CHECK *param,
1384
register MI_INFO *info, char * name,
1393
unsigned char *temp_buff;
1394
ha_rows old_record_count;
1395
MYISAM_SHARE *share=info->s;
1396
char llbuff[22],llbuff2[22];
1397
SORT_INFO sort_info;
1398
MI_SORT_PARAM sort_param;
1400
memset(&sort_info, 0, sizeof(sort_info));
1401
memset(&sort_param, 0, sizeof(sort_param));
1402
sort_param.sort_info=&sort_info;
1403
sort_info.param=param;
1404
keyinfo= &share->keyinfo[sort_key];
1409
if (! mi_is_key_active(share->state.key_map, sort_key))
1411
mi_check_print_warning(param,
1412
"Can't sort table '%s' on key %d; No such key",
1414
param->error_printed=0;
1415
return(0); /* Nothing to do */
1417
if (share->data_file_type == COMPRESSED_RECORD)
1419
mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
1420
param->error_printed=0;
1421
return(0); /* Nothing to do */
1423
if (!(param->testflag & T_SILENT))
1425
printf("- Sorting records for MyISAM-table '%s'\n",name);
1427
printf("Data records: %9s Deleted: %9s\n",
1428
llstr(info->state->records,llbuff),
1429
llstr(info->state->del,llbuff2));
1431
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1432
return(0); /* Nothing to do */
1434
init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers,
1436
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1437
WRITE_CACHE,share->pack.header_length,1,
1438
MYF(MY_WME | MY_WAIT_IF_FULL)))
1440
info->opt_flag|=WRITE_CACHE_USED;
1442
if (!(temp_buff=(unsigned char*) malloc(keyinfo->block_length)))
1444
mi_check_print_error(param,"Not enough memory for key block");
1448
if (!mi_alloc_rec_buff(info, (ulong)-1, &sort_param.record))
1450
mi_check_print_error(param,"Not enough memory for record");
1453
fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
1454
new_file=my_create(fn_format(param->temp_filename,
1455
param->temp_filename,"",
1457
0,param->tmpfile_createflag,
1461
mi_check_print_error(param,"Can't create new tempfile: '%s'",
1462
param->temp_filename);
1465
if (share->pack.header_length)
1466
if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1469
info->rec_cache.file=new_file; /* Use this file for cacheing*/
1472
for (key=0 ; key < share->base.keys ; key++)
1473
share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1475
if (my_pread(share->kfile,(unsigned char*) temp_buff,
1476
(uint) keyinfo->block_length,
1477
share->state.key_root[sort_key],
1478
MYF(MY_NABP+MY_WME)))
1480
mi_check_print_error(param,"Can't read indexpage from filepos: %s",
1481
(ulong) share->state.key_root[sort_key]);
1485
/* Setup param for sort_write_record */
1486
sort_info.info=info;
1487
sort_info.new_data_file_type=share->data_file_type;
1488
sort_param.fix_datafile=1;
1489
sort_param.master=1;
1490
sort_param.filepos=share->pack.header_length;
1491
old_record_count=info->state->records;
1492
info->state->records=0;
1493
if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1494
info->state->checksum=0;
1496
if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1497
temp_buff, sort_key,new_file,update_index) ||
1498
write_data_suffix(&sort_info,1) ||
1499
flush_io_cache(&info->rec_cache))
1502
if (info->state->records != old_record_count)
1504
mi_check_print_error(param,"found %s of %s records",
1505
llstr(info->state->records,llbuff),
1506
llstr(old_record_count,llbuff2));
1510
my_close(info->dfile,MYF(MY_WME));
1511
param->out_flag|=O_NEW_DATA; /* Data in new file */
1512
info->dfile=new_file; /* Use new datafile */
1514
info->state->empty=0;
1515
share->state.dellink= HA_OFFSET_ERROR;
1516
info->state->data_file_length=sort_param.filepos;
1517
share->state.split=info->state->records; /* Only hole records */
1518
share->state.version=(ulong) time((time_t*) 0);
1520
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1522
if (param->testflag & T_WRITE_LOOP)
1524
fputs(" \r",stdout); fflush(stdout);
1529
if (got_error && new_file >= 0)
1531
end_io_cache(&info->rec_cache);
1532
(void) my_close(new_file,MYF(MY_WME));
1533
(void) my_delete(param->temp_filename, MYF(MY_WME));
1537
free((unsigned char*) temp_buff);
1539
void * rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
1540
if (rec_buff_ptr != NULL)
1543
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1544
end_io_cache(&info->rec_cache);
1545
free(sort_info.buff);
1547
share->state.sortkey=sort_key;
1548
return(flush_blocks(param, share->key_cache, share->kfile) |
1550
} /* sort_records */
1553
/* Sort records recursive using one index */
1555
static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
1557
my_off_t page, unsigned char *buff, uint32_t sort_key,
1558
File new_file,bool update_index)
1560
uint nod_flag,used_length,key_length;
1561
unsigned char *temp_buff,*keypos,*endpos;
1562
my_off_t next_page,rec_pos;
1563
unsigned char lastkey[MI_MAX_KEY_BUFF];
1565
SORT_INFO *sort_info= sort_param->sort_info;
1566
MI_CHECK *param=sort_info->param;
1568
nod_flag=mi_test_if_nod(buff);
1573
if (!(temp_buff=(unsigned char*) malloc(keyinfo->block_length)))
1575
mi_check_print_error(param,"Not Enough memory");
1579
used_length=mi_getint(buff);
1580
keypos=buff+2+nod_flag;
1581
endpos=buff+used_length;
1586
next_page=_mi_kpos(nod_flag,keypos);
1587
if (my_pread(info->s->kfile,(unsigned char*) temp_buff,
1588
(uint) keyinfo->block_length, next_page,
1589
MYF(MY_NABP+MY_WME)))
1591
mi_check_print_error(param,"Can't read keys from filepos: %s",
1592
llstr(next_page,llbuff));
1595
if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1596
new_file, update_index))
1599
if (keypos >= endpos ||
1600
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1603
rec_pos= _mi_dpos(info,0,lastkey+key_length);
1605
if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1607
mi_check_print_error(param,"%d when reading datafile",my_errno);
1610
if (rec_pos != sort_param->filepos && update_index)
1612
_mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1613
sort_param->filepos);
1614
if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1617
mi_check_print_error(param,"%d when updating key-pointers",my_errno);
1621
if (sort_write_record(sort_param))
1624
/* Clear end of block to get better compression if the table is backuped */
1625
memset(buff+used_length, 0, keyinfo->block_length-used_length);
1626
if (my_pwrite(info->s->kfile,(unsigned char*) buff,(uint) keyinfo->block_length,
1627
page,param->myf_rw))
1629
mi_check_print_error(param,"%d when updating keyblock",my_errno);
1633
free((unsigned char*) temp_buff);
1637
free((unsigned char*) temp_buff);
1639
} /* sort_record_index */
1644
Check if myisamchk was killed by a signal
1645
This is overloaded by other programs that want to be able to abort
1649
static int not_killed= 0;
1651
volatile int *killed_ptr(MI_CHECK *)
1653
return ¬_killed; /* always NULL */
1656
/* print warnings and errors */
1659
void mi_check_print_info(MI_CHECK *,
1660
const char *fmt,...)
1665
vfprintf(stdout, fmt, args);
1672
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
1677
if (!param->warning_printed && !param->error_printed)
1679
if (param->testflag & T_SILENT)
1680
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,
1681
param->isam_file_name);
1682
param->out_flag|= O_DATA_LOST;
1684
param->warning_printed=1;
1686
fprintf(stderr,"%s: warning: ",my_progname_short);
1687
vfprintf(stderr, fmt, args);
1696
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
1701
if (!param->warning_printed && !param->error_printed)
1703
if (param->testflag & T_SILENT)
1704
fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1705
param->out_flag|= O_DATA_LOST;
1707
param->error_printed|=1;
1709
fprintf(stderr,"%s: error: ",my_progname_short);
1710
vfprintf(stderr, fmt, args);