~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/myisamchk.c

  • Committer: Brian Aker
  • Date: 2009-08-21 18:46:31 UTC
  • mto: This revision was merged to the branch mainline in revision 1123.
  • Revision ID: brian@gaz-20090821184631-e11gja79070fvhk4
Cleanup around page checksum removal

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2003 MySQL AB
2
 
 
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.
6
 
 
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.
11
 
 
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 */
15
 
 
16
 
/* Describe, check and repair of MyISAM tables */
17
 
 
18
 
#include <drizzled/global.h>
19
 
 
20
 
#include <mystrings/m_ctype.h>
21
 
#include <stdarg.h>
22
 
#include <mysys/my_getopt.h>
23
 
#include <mysys/my_bit.h>
24
 
#include <myisam.h>
25
 
#include <mystrings/m_string.h>
26
 
#ifdef HAVE_SYS_VADVICE_H
27
 
#include <sys/vadvise.h>
28
 
#endif
29
 
#ifdef HAVE_SYS_MMAN_H
30
 
#include <sys/mman.h>
31
 
#endif
32
 
 
33
 
#define my_raid_create(A,B,C,D,E,F,G) my_create(A,B,C,G)
34
 
#define my_raid_delete(A,B,C) my_delete(A,B)
35
 
 
36
 
#include "myisamdef.h"
37
 
 
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;
46
 
static MY_TMPDIR myisamchk_tmpdir;
47
 
 
48
 
static const char *type_names[]=
49
 
{ "impossible","char","binary", "short", "long", "float",
50
 
  "double","number","unsigned short",
51
 
  "unsigned long","int64_t","uint64_t","int24",
52
 
  "uint24","int8","varchar", "varbin","?",
53
 
  "?"};
54
 
 
55
 
static const char *prefix_packed_txt="packed ",
56
 
                  *bin_packed_txt="prefix ",
57
 
                  *diff_txt="stripped ",
58
 
                  *null_txt="NULL",
59
 
                  *blob_txt="BLOB ";
60
 
 
61
 
static const char *field_pack[]=
62
 
{"","no endspace", "no prespace",
63
 
 "no zeros", "blob", "constant", "table-lockup",
64
 
 "always zero","varchar","unique-hash","?","?"};
65
 
 
66
 
static const char *myisam_stats_method_str="nulls_unequal";
67
 
 
68
 
static void get_options(int *argc,char * * *argv);
69
 
static void print_version(void);
70
 
static void usage(void);
71
 
static int myisamchk(MI_CHECK *param, char *filename);
72
 
static void descript(MI_CHECK *param, register MI_INFO *info, char * name);
73
 
static int mi_sort_records(MI_CHECK *param, register MI_INFO *info,
74
 
                           char * name, uint32_t sort_key,
75
 
                           bool write_info, bool update_index);
76
 
static int sort_record_index(MI_SORT_PARAM *sort_param, MI_INFO *info,
77
 
                             MI_KEYDEF *keyinfo,
78
 
                             my_off_t page,unsigned char *buff,uint32_t sortkey,
79
 
                             File new_file, bool update_index);
80
 
 
81
 
MI_CHECK check_param;
82
 
 
83
 
        /* Main program */
84
 
 
85
 
int main(int argc, char **argv)
86
 
{
87
 
  int error;
88
 
  MY_INIT(argv[0]);
89
 
  my_progname_short= my_progname+dirname_length(my_progname);
90
 
 
91
 
  myisamchk_init(&check_param);
92
 
  check_param.opt_lock_memory=1;                /* Lock memory if possible */
93
 
  check_param.using_global_keycache = 0;
94
 
  get_options(&argc,(char***) &argv);
95
 
  myisam_quick_table_bits=decode_bits;
96
 
  error=0;
97
 
  while (--argc >= 0)
98
 
  {
99
 
    int new_error=myisamchk(&check_param, *(argv++));
100
 
    if ((check_param.testflag & T_REP_ANY) != T_REP)
101
 
      check_param.testflag&= ~T_REP;
102
 
    fflush(stdout);
103
 
    fflush(stderr);
104
 
    if ((check_param.error_printed | check_param.warning_printed) &&
105
 
        (check_param.testflag & T_FORCE_CREATE) &&
106
 
        (!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
107
 
                                   T_SORT_INDEX))))
108
 
    {
109
 
      uint32_t old_testflag=check_param.testflag;
110
 
      if (!(check_param.testflag & T_REP))
111
 
        check_param.testflag|= T_REP_BY_SORT;
112
 
      check_param.testflag&= ~T_EXTEND;                 /* Don't needed  */
113
 
      error|=myisamchk(&check_param, argv[-1]);
114
 
      check_param.testflag= old_testflag;
115
 
      fflush(stdout);
116
 
      fflush(stderr);
117
 
    }
118
 
    else
119
 
      error|=new_error;
120
 
    if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
121
 
    {
122
 
      puts("\n---------\n");
123
 
      fflush(stdout);
124
 
    }
125
 
  }
126
 
  if (check_param.total_files > 1)
127
 
  {                                     /* Only if descript */
128
 
    char buff[22],buff2[22];
129
 
    if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
130
 
      puts("\n---------\n");
131
 
    printf("\nTotal of all %d MyISAM-files:\nData records: %9s   Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
132
 
           llstr(check_param.total_deleted,buff2));
133
 
  }
134
 
  free_defaults(default_argv);
135
 
  free_tmpdir(&myisamchk_tmpdir);
136
 
  my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
137
 
  exit(error);
138
 
#ifndef _lint
139
 
  return 0;                             /* No compiler warning */
140
 
#endif
141
 
} /* main */
142
 
 
143
 
enum options_mc {
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
150
 
};
151
 
 
152
 
static struct my_option my_long_options[] =
153
 
{
154
 
  {"analyze", 'a',
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},
160
 
  {"backup", 'B',
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},
163
 
  {"character-sets-dir", OPT_CHARSETS_DIR,
164
 
   "Directory where character sets are.",
165
 
   (char**) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
166
 
  {"check", 'c',
167
 
   "Check table for errors.",
168
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
169
 
  {"check-only-changed", 'C',
170
 
   "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).",
171
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
172
 
  {"correct-checksum", OPT_CORRECT_CHECKSUM,
173
 
   "Correct checksum information for table.",
174
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
175
 
  {"description", 'd',
176
 
   "Prints some information about table.",
177
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
178
 
  {"data-file-length", 'D',
179
 
   "Max length of data file (when recreating data-file when it's full).",
180
 
   (char**) &check_param.max_data_file_length,
181
 
   (char**) &check_param.max_data_file_length,
182
 
   0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
183
 
  {"extend-check", 'e',
184
 
   "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.",
185
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
186
 
  {"fast", 'F',
187
 
   "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).",
188
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
189
 
  {"force", 'f',
190
 
   "Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
191
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
192
 
  {"HELP", 'H',
193
 
   "Display this help and exit.",
194
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
195
 
  {"help", '?',
196
 
   "Display this help and exit.",
197
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
198
 
  {"information", 'i',
199
 
   "Print statistics information about table that is checked.",
200
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
201
 
  {"keys-used", 'k',
202
 
   "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.",
203
 
   (char**) &check_param.keys_in_use,
204
 
   (char**) &check_param.keys_in_use,
205
 
   0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
206
 
  {"max-record-length", OPT_MAX_RECORD_LENGTH,
207
 
   "Skip rows bigger than this if myisamchk can't allocate memory to hold it",
208
 
   (char**) &check_param.max_record_length,
209
 
   (char**) &check_param.max_record_length,
210
 
   0, GET_ULL, REQUIRED_ARG, INT64_MAX, 0, INT64_MAX, 0, 0, 0},
211
 
  {"medium-check", 'm',
212
 
   "Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
213
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
214
 
  {"quick", 'q', "Faster repair by not modifying the data file.",
215
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
216
 
  {"read-only", 'T',
217
 
   "Don't mark table as checked.",
218
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
219
 
  {"recover", 'r',
220
 
   "Can fix almost anything except unique keys that aren't unique.",
221
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
222
 
  {"parallel-recover", 'p',
223
 
   "Same as '-r' but creates all the keys in parallel.",
224
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
225
 
  {"safe-recover", 'o',
226
 
   "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.",
227
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
228
 
  {"sort-recover", 'n',
229
 
   "Force recovering with sorting even if the temporary file was very big.",
230
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
231
 
#ifdef DEBUG
232
 
  {"start-check-pos", OPT_START_CHECK_POS,
233
 
   "No help available.",
234
 
   0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
235
 
#endif
236
 
  {"set-auto-increment", 'A',
237
 
   "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.",
238
 
   (char**) &check_param.auto_increment_value,
239
 
   (char**) &check_param.auto_increment_value,
240
 
   0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
241
 
  {"set-collation", OPT_SET_COLLATION,
242
 
   "Change the collation used by the index",
243
 
   (char**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
244
 
  {"set-variable", 'O',
245
 
   "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
246
 
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
247
 
  {"silent", 's',
248
 
   "Only print errors. One can use two -s to make myisamchk very silent.",
249
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
250
 
  {"sort-index", 'S',
251
 
   "Sort index blocks. This speeds up 'read-next' in applications.",
252
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
253
 
  {"sort-records", 'R',
254
 
   "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!)",
255
 
   (char**) &check_param.opt_sort_key,
256
 
   (char**) &check_param.opt_sort_key,
257
 
   0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
258
 
  {"tmpdir", 't',
259
 
   "Path for temporary files.",
260
 
   (char**) &opt_tmpdir,
261
 
   0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
262
 
  {"update-state", 'U',
263
 
   "Mark tables as crashed if any errors were found.",
264
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
265
 
  {"unpack", 'u',
266
 
   "Unpack file packed with myisampack.",
267
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
268
 
  {"verbose", 'v',
269
 
   "Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
270
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
271
 
  {"version", 'V',
272
 
   "Print version and exit.",
273
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
274
 
  {"wait", 'w',
275
 
   "Wait if table is locked.",
276
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
277
 
  { "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
278
 
    (char**) &check_param.use_buffers, (char**) &check_param.use_buffers, 0,
279
 
    GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
280
 
    INT32_MAX, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
281
 
  { "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE,  "",
282
 
    (char**) &opt_key_cache_block_size,
283
 
    (char**) &opt_key_cache_block_size, 0,
284
 
    GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
285
 
    MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
286
 
  { "myisam_block_size", OPT_MYISAM_BLOCK_SIZE,  "",
287
 
    (char**) &opt_myisam_block_size, (char**) &opt_myisam_block_size, 0,
288
 
    GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
289
 
    MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
290
 
  { "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
291
 
    (char**) &check_param.read_buffer_length,
292
 
    (char**) &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
293
 
    (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
294
 
    INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
295
 
  { "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
296
 
    (char**) &check_param.write_buffer_length,
297
 
    (char**) &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
298
 
    (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
299
 
    INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
300
 
  { "sort_buffer_size", OPT_SORT_BUFFER_SIZE, "",
301
 
    (char**) &check_param.sort_buffer_length,
302
 
    (char**) &check_param.sort_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
303
 
    (long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
304
 
    INT32_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0},
305
 
  { "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
306
 
    (char**) &check_param.sort_key_blocks,
307
 
    (char**) &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
308
 
    BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
309
 
  { "decode_bits", OPT_DECODE_BITS, "", (char**) &decode_bits,
310
 
    (char**) &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
311
 
  {"stats_method", OPT_STATS_METHOD,
312
 
   "Specifies how index statistics collection code should treat NULLs. "
313
 
   "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
314
 
   "\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
315
 
   (char**) &myisam_stats_method_str, (char**) &myisam_stats_method_str, 0,
316
 
    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
317
 
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
318
 
};
319
 
 
320
 
 
321
 
static void print_version(void)
322
 
{
323
 
  printf("%s  Ver 2.7 for %s at %s\n", my_progname, SYSTEM_TYPE,
324
 
         MACHINE_TYPE);
325
 
}
326
 
 
327
 
 
328
 
static void usage(void)
329
 
{
330
 
  print_version();
331
 
  puts("By Monty, for your professional use");
332
 
  puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
333
 
  puts("Description, check and repair of MyISAM tables.");
334
 
  puts("Used without options all tables on the command will be checked for errors");
335
 
  printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname_short);
336
 
  printf("\nGlobal options:\n");
337
 
  printf("\
338
 
  -?, --help          Display this help and exit.\n\
339
 
  -O, --set-variable var=option.\n\
340
 
                      Change the value of a variable. Please note that\n\
341
 
                      this option is deprecated; you can set variables\n\
342
 
                      directly with '--variable-name=value'.\n\
343
 
  -t, --tmpdir=path   Path for temporary files. Multiple paths can be\n\
344
 
                      specified, separated by ");
345
 
#if defined( __WIN__)
346
 
   printf("semicolon (;)");
347
 
#else
348
 
   printf("colon (:)");
349
 
#endif
350
 
                      printf(", they will be used\n\
351
 
                      in a round-robin fashion.\n\
352
 
  -s, --silent        Only print errors.  One can use two -s to make\n\
353
 
                      myisamchk very silent.\n\
354
 
  -v, --verbose       Print more information. This can be used with\n\
355
 
                      --description and --check. Use many -v for more verbosity.\n\
356
 
  -V, --version       Print version and exit.\n\
357
 
  -w, --wait          Wait if table is locked.\n\n");
358
 
#ifdef DEBUG
359
 
  puts("  --start-check-pos=# Start reading file at given offset.\n");
360
 
#endif
361
 
 
362
 
  puts("Check options (check is the default action for myisamchk):\n\
363
 
  -c, --check         Check table for errors.\n\
364
 
  -e, --extend-check  Check the table VERY throughly.  Only use this in\n\
365
 
                      extreme cases as myisamchk should normally be able to\n\
366
 
                      find out if the table is ok even without this switch.\n\
367
 
  -F, --fast          Check only tables that haven't been closed properly.\n\
368
 
  -C, --check-only-changed\n\
369
 
                      Check only tables that have changed since last check.\n\
370
 
  -f, --force         Restart with '-r' if there are any errors in the table.\n\
371
 
                      States will be updated as with '--update-state'.\n\
372
 
  -i, --information   Print statistics information about table that is checked.\n\
373
 
  -m, --medium-check  Faster than extend-check, but only finds 99.99% of\n\
374
 
                      all errors.  Should be good enough for most cases.\n\
375
 
  -U  --update-state  Mark tables as crashed if you find any errors.\n\
376
 
  -T, --read-only     Don't mark table as checked.\n");
377
 
 
378
 
  puts("Repair options (When using '-r' or '-o'):\n\
379
 
  -B, --backup        Make a backup of the .MYD file as 'filename-time.BAK'.\n\
380
 
  --correct-checksum  Correct checksum information for table.\n\
381
 
  -D, --data-file-length=#  Max length of data file (when recreating data\n\
382
 
                      file when it's full).\n\
383
 
  -e, --extend-check  Try to recover every possible row from the data file\n\
384
 
                      Normally this will also find a lot of garbage rows;\n\
385
 
                      Don't use this option if you are not totally desperate.\n\
386
 
  -f, --force         Overwrite old temporary files.\n\
387
 
  -k, --keys-used=#   Tell MyISAM to update only some specific keys. # is a\n\
388
 
                      bit mask of which keys to use. This can be used to\n\
389
 
                      get faster inserts.\n\
390
 
  --max-record-length=#\n\
391
 
                      Skip rows bigger than this if myisamchk can't allocate\n\
392
 
                      memory to hold it.\n\
393
 
  -r, --recover       Can fix almost anything except unique keys that aren't\n\
394
 
                      unique.\n\
395
 
  -n, --sort-recover  Forces recovering with sorting even if the temporary\n\
396
 
                      file would be very big.\n\
397
 
  -p, --parallel-recover\n\
398
 
                      Uses the same technique as '-r' and '-n', but creates\n\
399
 
                      all the keys in parallel, in different threads.\n\
400
 
  -o, --safe-recover  Uses old recovery method; Slower than '-r' but can\n\
401
 
                      handle a couple of cases where '-r' reports that it\n\
402
 
                      can't fix the data file.\n\
403
 
  --character-sets-dir=...\n\
404
 
                      Directory where character sets are.\n\
405
 
  --set-collation=name\n\
406
 
                      Change the collation used by the index.\n\
407
 
  -q, --quick         Faster repair by not modifying the data file.\n\
408
 
                      One can give a second '-q' to force myisamchk to\n\
409
 
                      modify the original datafile in case of duplicate keys.\n\
410
 
                      NOTE: Tables where the data file is currupted can't be\n\
411
 
                      fixed with this option.\n\
412
 
  -u, --unpack        Unpack file packed with myisampack.\n\
413
 
");
414
 
 
415
 
  puts("Other actions:\n\
416
 
  -a, --analyze       Analyze distribution of keys. Will make some joins in\n\
417
 
                      MySQL faster.  You can check the calculated distribution\n\
418
 
                      by using '--description --verbose table_name'.\n\
419
 
  --stats_method=name Specifies how index statistics collection code should\n\
420
 
                      treat NULLs. Possible values of name are \"nulls_unequal\"\n\
421
 
                      (default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
422
 
                      \"nulls_ignored\".\n\
423
 
  -d, --description   Prints some information about table.\n\
424
 
  -A, --set-auto-increment[=value]\n\
425
 
                      Force auto_increment to start at this or higher value\n\
426
 
                      If no value is given, then sets the next auto_increment\n\
427
 
                      value to the highest used value for the auto key + 1.\n\
428
 
  -S, --sort-index    Sort index blocks.  This speeds up 'read-next' in\n\
429
 
                      applications.\n\
430
 
  -R, --sort-records=#\n\
431
 
                      Sort records according to an index.  This makes your\n\
432
 
                      data much more localized and may speed up things\n\
433
 
                      (It may be VERY slow to do a sort the first time!).\n\
434
 
  -b,  --block-search=#\n\
435
 
                       Find a record, a block at given offset belongs to.");
436
 
 
437
 
  print_defaults("my", load_default_groups);
438
 
  my_print_variables(my_long_options);
439
 
}
440
 
 
441
 
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
442
 
                                           "nulls_ignored", NULL};
443
 
TYPELIB myisam_stats_method_typelib= {
444
 
  array_elements(myisam_stats_method_names) - 1, "",
445
 
  myisam_stats_method_names, NULL};
446
 
 
447
 
         /* Read options */
448
 
 
449
 
static bool
450
 
get_one_option(int optid,
451
 
               const struct my_option *opt __attribute__((unused)),
452
 
               char *argument)
453
 
{
454
 
  switch (optid) {
455
 
  case 'a':
456
 
    if (argument == disabled_my_option)
457
 
      check_param.testflag&= ~T_STATISTICS;
458
 
    else
459
 
      check_param.testflag|= T_STATISTICS;
460
 
    break;
461
 
  case 'A':
462
 
    if (argument)
463
 
      check_param.auto_increment_value= strtoull(argument, NULL, 0);
464
 
    else
465
 
      check_param.auto_increment_value= 0;      /* Set to max used value */
466
 
    check_param.testflag|= T_AUTO_INC;
467
 
    break;
468
 
  case 'b':
469
 
    check_param.search_after_block= strtoul(argument, NULL, 10);
470
 
    break;
471
 
  case 'B':
472
 
    if (argument == disabled_my_option)
473
 
      check_param.testflag&= ~T_BACKUP_DATA;
474
 
    else
475
 
      check_param.testflag|= T_BACKUP_DATA;
476
 
    break;
477
 
  case 'c':
478
 
    if (argument == disabled_my_option)
479
 
      check_param.testflag&= ~T_CHECK;
480
 
    else
481
 
      check_param.testflag|= T_CHECK;
482
 
    break;
483
 
  case 'C':
484
 
    if (argument == disabled_my_option)
485
 
      check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
486
 
    else
487
 
      check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
488
 
    break;
489
 
  case 'D':
490
 
    check_param.max_data_file_length=strtoll(argument, NULL, 10);
491
 
    break;
492
 
  case 's':                             /* silent */
493
 
    if (argument == disabled_my_option)
494
 
      check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
495
 
    else
496
 
    {
497
 
      if (check_param.testflag & T_SILENT)
498
 
        check_param.testflag|= T_VERY_SILENT;
499
 
      check_param.testflag|= T_SILENT;
500
 
      check_param.testflag&= ~T_WRITE_LOOP;
501
 
    }
502
 
    break;
503
 
  case 'w':
504
 
    if (argument == disabled_my_option)
505
 
      check_param.testflag&= ~T_WAIT_FOREVER;
506
 
    else
507
 
      check_param.testflag|= T_WAIT_FOREVER;
508
 
    break;
509
 
  case 'd':                             /* description if isam-file */
510
 
    if (argument == disabled_my_option)
511
 
      check_param.testflag&= ~T_DESCRIPT;
512
 
    else
513
 
      check_param.testflag|= T_DESCRIPT;
514
 
    break;
515
 
  case 'e':                             /* extend check */
516
 
    if (argument == disabled_my_option)
517
 
      check_param.testflag&= ~T_EXTEND;
518
 
    else
519
 
      check_param.testflag|= T_EXTEND;
520
 
    break;
521
 
  case 'i':
522
 
    if (argument == disabled_my_option)
523
 
      check_param.testflag&= ~T_INFO;
524
 
    else
525
 
      check_param.testflag|= T_INFO;
526
 
    break;
527
 
  case 'f':
528
 
    if (argument == disabled_my_option)
529
 
    {
530
 
      check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
531
 
      check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
532
 
    }
533
 
    else
534
 
    {
535
 
      check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
536
 
      check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
537
 
    }
538
 
    break;
539
 
  case 'F':
540
 
    if (argument == disabled_my_option)
541
 
      check_param.testflag&= ~T_FAST;
542
 
    else
543
 
      check_param.testflag|= T_FAST;
544
 
    break;
545
 
  case 'k':
546
 
    check_param.keys_in_use= (uint64_t) strtoll(argument, NULL, 10);
547
 
    break;
548
 
  case 'm':
549
 
    if (argument == disabled_my_option)
550
 
      check_param.testflag&= ~T_MEDIUM;
551
 
    else
552
 
      check_param.testflag|= T_MEDIUM;          /* Medium check */
553
 
    break;
554
 
  case 'r':                             /* Repair table */
555
 
    check_param.testflag&= ~T_REP_ANY;
556
 
    if (argument != disabled_my_option)
557
 
      check_param.testflag|= T_REP_BY_SORT;
558
 
    break;
559
 
  case 'p':
560
 
    check_param.testflag&= ~T_REP_ANY;
561
 
    if (argument != disabled_my_option)
562
 
      check_param.testflag|= T_REP_PARALLEL;
563
 
    break;
564
 
  case 'o':
565
 
    check_param.testflag&= ~T_REP_ANY;
566
 
    check_param.force_sort= 0;
567
 
    if (argument != disabled_my_option)
568
 
    {
569
 
      check_param.testflag|= T_REP;
570
 
      my_disable_async_io= 1;           /* More safety */
571
 
    }
572
 
    break;
573
 
  case 'n':
574
 
    check_param.testflag&= ~T_REP_ANY;
575
 
    if (argument == disabled_my_option)
576
 
      check_param.force_sort= 0;
577
 
    else
578
 
    {
579
 
      check_param.testflag|= T_REP_BY_SORT;
580
 
      check_param.force_sort= 1;
581
 
    }
582
 
    break;
583
 
  case 'q':
584
 
    if (argument == disabled_my_option)
585
 
      check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
586
 
    else
587
 
      check_param.testflag|=
588
 
        (check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
589
 
    break;
590
 
  case 'u':
591
 
    if (argument == disabled_my_option)
592
 
      check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
593
 
    else
594
 
      check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
595
 
    break;
596
 
  case 'v':                             /* Verbose */
597
 
    if (argument == disabled_my_option)
598
 
    {
599
 
      check_param.testflag&= ~T_VERBOSE;
600
 
      check_param.verbose=0;
601
 
    }
602
 
    else
603
 
    {
604
 
      check_param.testflag|= T_VERBOSE;
605
 
      check_param.verbose++;
606
 
    }
607
 
    break;
608
 
  case 'R':                             /* Sort records */
609
 
    if (argument == disabled_my_option)
610
 
      check_param.testflag&= ~T_SORT_RECORDS;
611
 
    else
612
 
    {
613
 
      check_param.testflag|= T_SORT_RECORDS;
614
 
      check_param.opt_sort_key= (uint) atoi(argument) - 1;
615
 
      if (check_param.opt_sort_key >= MI_MAX_KEY)
616
 
      {
617
 
        fprintf(stderr,
618
 
                "The value of the sort key is bigger than max key: %d.\n",
619
 
                MI_MAX_KEY);
620
 
        exit(1);
621
 
      }
622
 
    }
623
 
    break;
624
 
  case 'S':                           /* Sort index */
625
 
    if (argument == disabled_my_option)
626
 
      check_param.testflag&= ~T_SORT_INDEX;
627
 
    else
628
 
      check_param.testflag|= T_SORT_INDEX;
629
 
    break;
630
 
  case 'T':
631
 
    if (argument == disabled_my_option)
632
 
      check_param.testflag&= ~T_READONLY;
633
 
    else
634
 
      check_param.testflag|= T_READONLY;
635
 
    break;
636
 
  case 'U':
637
 
    if (argument == disabled_my_option)
638
 
      check_param.testflag&= ~T_UPDATE_STATE;
639
 
    else
640
 
      check_param.testflag|= T_UPDATE_STATE;
641
 
    break;
642
 
  case 'V':
643
 
    print_version();
644
 
    exit(0);
645
 
  case OPT_CORRECT_CHECKSUM:
646
 
    if (argument == disabled_my_option)
647
 
      check_param.testflag&= ~T_CALC_CHECKSUM;
648
 
    else
649
 
      check_param.testflag|= T_CALC_CHECKSUM;
650
 
    break;
651
 
  case OPT_STATS_METHOD:
652
 
  {
653
 
    int method;
654
 
    enum_mi_stats_method method_conv;
655
 
    myisam_stats_method_str= argument;
656
 
    if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
657
 
    {
658
 
      fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
659
 
      exit(1);
660
 
    }
661
 
    switch (method-1) {
662
 
    case 0: 
663
 
      method_conv= MI_STATS_METHOD_NULLS_EQUAL;
664
 
      break;
665
 
    case 1:
666
 
      method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
667
 
      break;
668
 
    case 2:
669
 
      method_conv= MI_STATS_METHOD_IGNORE_NULLS;
670
 
      break;
671
 
    default: assert(0);                         /* Impossible */
672
 
    }
673
 
    check_param.stats_method= method_conv;
674
 
    break;
675
 
  }
676
 
#ifdef DEBUG                                    /* Only useful if debugging */
677
 
  case OPT_START_CHECK_POS:
678
 
    check_param.start_check_pos= strtoull(argument, NULL, 0);
679
 
    break;
680
 
#endif
681
 
  case 'H':
682
 
    my_print_help(my_long_options);
683
 
    exit(0);
684
 
  case '?':
685
 
    usage();
686
 
    exit(0);
687
 
  }
688
 
  return 0;
689
 
}
690
 
 
691
 
 
692
 
static void get_options(register int *argc,register char ***argv)
693
 
{
694
 
  int ho_error;
695
 
 
696
 
  load_defaults("my", load_default_groups, argc, argv);
697
 
  default_argv= *argv;
698
 
  if (isatty(fileno(stdout)))
699
 
    check_param.testflag|=T_WRITE_LOOP;
700
 
 
701
 
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
702
 
    exit(ho_error);
703
 
 
704
 
  /* If using repair, then update checksum if one uses --update-state */
705
 
  if ((check_param.testflag & T_UPDATE_STATE) &&
706
 
      (check_param.testflag & T_REP_ANY))
707
 
    check_param.testflag|= T_CALC_CHECKSUM;
708
 
 
709
 
  if (*argc == 0)
710
 
  {
711
 
    usage();
712
 
    exit(-1);
713
 
  }
714
 
 
715
 
  if ((check_param.testflag & T_UNPACK) &&
716
 
      (check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
717
 
  {
718
 
    fprintf(stderr,
719
 
            "%s: --unpack can't be used with --quick or --sort-records\n",
720
 
            my_progname_short);
721
 
    exit(1);
722
 
  }
723
 
  if ((check_param.testflag & T_READONLY) &&
724
 
      (check_param.testflag &
725
 
       (T_REP_ANY | T_STATISTICS | T_AUTO_INC |
726
 
        T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
727
 
  {
728
 
    fprintf(stderr,
729
 
            "%s: Can't use --readonly when repairing or sorting\n",
730
 
            my_progname_short);
731
 
    exit(1);
732
 
  }
733
 
 
734
 
  if (init_tmpdir(&myisamchk_tmpdir, opt_tmpdir))
735
 
    exit(1);
736
 
 
737
 
  check_param.tmpdir=&myisamchk_tmpdir;
738
 
  check_param.key_cache_block_size= opt_key_cache_block_size;
739
 
 
740
 
  if (set_collation_name)
741
 
    if (!(set_collation= get_charset_by_name(set_collation_name,
742
 
                                             MYF(MY_WME))))
743
 
      exit(1);
744
 
 
745
 
  myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
746
 
  return;
747
 
} /* get options */
748
 
 
749
 
 
750
 
        /* Check table */
751
 
 
752
 
static int myisamchk(MI_CHECK *param, char * filename)
753
 
{
754
 
  int error,lock_type,recreate;
755
 
  int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
756
 
  uint32_t raid_chunks;
757
 
  MI_INFO *info;
758
 
  File datafile;
759
 
  char llbuff[22],llbuff2[22];
760
 
  bool state_updated=0;
761
 
  MYISAM_SHARE *share;
762
 
 
763
 
  param->out_flag=error=param->warning_printed=param->error_printed=
764
 
    recreate=0;
765
 
  datafile=0;
766
 
  param->isam_file_name=filename;               /* For error messages */
767
 
  if (!(info=mi_open(filename,
768
 
                     (param->testflag & (T_DESCRIPT | T_READONLY)) ?
769
 
                     O_RDONLY : O_RDWR,
770
 
                     HA_OPEN_FOR_REPAIR |
771
 
                     ((param->testflag & T_WAIT_FOREVER) ?
772
 
                      HA_OPEN_WAIT_IF_LOCKED :
773
 
                      (param->testflag & T_DESCRIPT) ?
774
 
                      HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
775
 
  {
776
 
    /* Avoid twice printing of isam file name */
777
 
    param->error_printed=1;
778
 
    switch (my_errno) {
779
 
    case HA_ERR_CRASHED:
780
 
      mi_check_print_error(param,"'%s' doesn't have a correct index definition. You need to recreate it before you can do a repair",filename);
781
 
      break;
782
 
    case HA_ERR_NOT_A_TABLE:
783
 
      mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
784
 
      break;
785
 
    case HA_ERR_CRASHED_ON_USAGE:
786
 
      mi_check_print_error(param,"'%s' is marked as crashed",filename);
787
 
      break;
788
 
    case HA_ERR_CRASHED_ON_REPAIR:
789
 
      mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
790
 
      break;
791
 
    case HA_ERR_OLD_FILE:
792
 
      mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
793
 
      break;
794
 
    case HA_ERR_END_OF_FILE:
795
 
      mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
796
 
      break;
797
 
    case EAGAIN:
798
 
      mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
799
 
      break;
800
 
    case ENOENT:
801
 
      mi_check_print_error(param,"File '%s' doesn't exist",filename);
802
 
      break;
803
 
    case EACCES:
804
 
      mi_check_print_error(param,"You don't have permission to use '%s'",filename);
805
 
      break;
806
 
    default:
807
 
      mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
808
 
                  my_errno,filename);
809
 
      break;
810
 
    }
811
 
    return(1);
812
 
  }
813
 
  share=info->s;
814
 
  share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
815
 
  share->tot_locks-= share->r_locks;
816
 
  share->r_locks=0;
817
 
  raid_chunks=share->base.raid_chunks;
818
 
 
819
 
  /*
820
 
    Skip the checking of the file if:
821
 
    We are using --fast and the table is closed properly
822
 
    We are using --check-only-changed-tables and the table hasn't changed
823
 
  */
824
 
  if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
825
 
  {
826
 
    bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
827
 
 
828
 
    if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
829
 
        ((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
830
 
                                  STATE_CRASHED_ON_REPAIR) ||
831
 
          !(param->testflag & T_CHECK_ONLY_CHANGED))))
832
 
      need_to_check=1;
833
 
 
834
 
    if (info->s->base.keys && info->state->records)
835
 
    {
836
 
      if ((param->testflag & T_STATISTICS) &&
837
 
          (share->state.changed & STATE_NOT_ANALYZED))
838
 
        need_to_check=1;
839
 
      if ((param->testflag & T_SORT_INDEX) &&
840
 
          (share->state.changed & STATE_NOT_SORTED_PAGES))
841
 
        need_to_check=1;
842
 
      if ((param->testflag & T_REP_BY_SORT) &&
843
 
          (share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
844
 
        need_to_check=1;
845
 
    }
846
 
    if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
847
 
        (share->state.changed & (STATE_CHANGED | STATE_CRASHED |
848
 
                                 STATE_CRASHED_ON_REPAIR)))
849
 
      need_to_check=1;
850
 
    if (!need_to_check)
851
 
    {
852
 
      if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
853
 
        printf("MyISAM file: %s is already checked\n",filename);
854
 
      if (mi_close(info))
855
 
      {
856
 
        mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
857
 
                             my_errno,filename);
858
 
        return(1);
859
 
      }
860
 
      return(0);
861
 
    }
862
 
  }
863
 
  if ((param->testflag & (T_REP_ANY | T_STATISTICS |
864
 
                          T_SORT_RECORDS | T_SORT_INDEX)) &&
865
 
      (((param->testflag & T_UNPACK) &&
866
 
        share->data_file_type == COMPRESSED_RECORD) ||
867
 
       mi_uint2korr(share->state.header.state_info_length) !=
868
 
       MI_STATE_INFO_SIZE ||
869
 
       mi_uint2korr(share->state.header.base_info_length) !=
870
 
       MI_BASE_INFO_SIZE ||
871
 
       mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
872
 
                                       ~share->state.key_map) ||
873
 
       test_if_almost_full(info) ||
874
 
       info->s->state.header.file_version[3] != myisam_file_magic[3] ||
875
 
       (set_collation &&
876
 
        set_collation->number != share->state.header.language) ||
877
 
       myisam_block_size != MI_KEY_BLOCK_LENGTH))
878
 
  {
879
 
    if (set_collation)
880
 
      param->language= set_collation->number;
881
 
    if (recreate_table(param, &info,filename))
882
 
    {
883
 
      fprintf(stderr,
884
 
              "MyISAM-table '%s' is not fixed because of errors\n",
885
 
              filename);
886
 
      return(-1);
887
 
    }
888
 
    recreate=1;
889
 
    if (!(param->testflag & T_REP_ANY))
890
 
    {
891
 
      param->testflag|=T_REP_BY_SORT;           /* if only STATISTICS */
892
 
      if (!(param->testflag & T_SILENT))
893
 
        printf("- '%s' has old table-format. Recreating index\n",filename);
894
 
      rep_quick|=T_QUICK;
895
 
    }
896
 
    share=info->s;
897
 
    share->tot_locks-= share->r_locks;
898
 
    share->r_locks=0;
899
 
  }
900
 
 
901
 
  if (param->testflag & T_DESCRIPT)
902
 
  {
903
 
    param->total_files++;
904
 
    param->total_records+=info->state->records;
905
 
    param->total_deleted+=info->state->del;
906
 
    descript(param, info, filename);
907
 
  }
908
 
  else
909
 
  {
910
 
 
911
 
    if (!(param->testflag & T_READONLY))
912
 
      lock_type = F_WRLCK;                      /* table is changed */
913
 
    else
914
 
      lock_type= F_RDLCK;
915
 
    if (info->lock_type == F_RDLCK)
916
 
      info->lock_type=F_UNLCK;                  /* Read only table */
917
 
    if (_mi_readinfo(info,lock_type,0))
918
 
    {
919
 
      mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
920
 
                  filename,my_errno);
921
 
      param->error_printed=0;
922
 
      goto end2;
923
 
    }
924
 
    /*
925
 
      _mi_readinfo() has locked the table.
926
 
      We mark the table as locked (without doing file locks) to be able to
927
 
      use functions that only works on locked tables (like row caching).
928
 
    */
929
 
    mi_lock_database(info, F_EXTRA_LCK);
930
 
    datafile=info->dfile;
931
 
 
932
 
    if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
933
 
    {
934
 
      if (param->testflag & T_REP_ANY)
935
 
      {
936
 
        uint64_t tmp=share->state.key_map;
937
 
        mi_copy_keys_active(share->state.key_map, share->base.keys,
938
 
                            param->keys_in_use);
939
 
        if (tmp != share->state.key_map)
940
 
          info->update|=HA_STATE_CHANGED;
941
 
      }
942
 
      if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
943
 
      {
944
 
        if (param->testflag & T_FORCE_CREATE)
945
 
        {
946
 
          rep_quick=0;
947
 
          mi_check_print_info(param,"Creating new data file\n");
948
 
        }
949
 
        else
950
 
        {
951
 
          error=1;
952
 
          mi_check_print_error(param,
953
 
                               "Quick-recover aborted; Run recovery without switch 'q'");
954
 
        }
955
 
      }
956
 
      if (!error)
957
 
      {
958
 
        if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
959
 
            (mi_is_any_key_active(share->state.key_map) ||
960
 
             (rep_quick && !param->keys_in_use && !recreate)) &&
961
 
            mi_test_if_sort_rep(info, info->state->records,
962
 
                                info->s->state.key_map,
963
 
                                param->force_sort))
964
 
        {
965
 
          if (param->testflag & T_REP_BY_SORT)
966
 
            error=mi_repair_by_sort(param,info,filename,rep_quick);
967
 
          else
968
 
            error=mi_repair_parallel(param,info,filename,rep_quick);
969
 
          state_updated=1;
970
 
        }
971
 
        else if (param->testflag & T_REP_ANY)
972
 
          error=mi_repair(param, info,filename,rep_quick);
973
 
      }
974
 
      if (!error && param->testflag & T_SORT_RECORDS)
975
 
      {
976
 
        uint32_t key;
977
 
        /*
978
 
          We can't update the index in mi_sort_records if we have a
979
 
          prefix compressed or fulltext index
980
 
        */
981
 
        bool update_index=1;
982
 
        for (key=0 ; key < share->base.keys; key++)
983
 
          if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY))
984
 
            update_index=0;
985
 
 
986
 
        error=mi_sort_records(param,info,filename,param->opt_sort_key,
987
 
                           /* what is the following parameter for ? */
988
 
                              (bool) !(param->testflag & T_REP),
989
 
                              update_index);
990
 
        datafile=info->dfile;   /* This is now locked */
991
 
        if (!error && !update_index)
992
 
        {
993
 
          if (param->verbose)
994
 
            puts("Table had a compressed index;  We must now recreate the index");
995
 
          error=mi_repair_by_sort(param,info,filename,1);
996
 
        }
997
 
      }
998
 
      if (!error && param->testflag & T_SORT_INDEX)
999
 
        error=mi_sort_index(param,info,filename);
1000
 
      if (!error)
1001
 
        share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1002
 
                                 STATE_CRASHED_ON_REPAIR);
1003
 
      else
1004
 
        mi_mark_crashed(info);
1005
 
    }
1006
 
    else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
1007
 
    {
1008
 
      if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1009
 
        printf("Checking MyISAM file: %s\n",filename);
1010
 
      if (!(param->testflag & T_SILENT))
1011
 
        printf("Data records: %7s   Deleted blocks: %7s\n",
1012
 
               llstr(info->state->records,llbuff),
1013
 
               llstr(info->state->del,llbuff2));
1014
 
      error =chk_status(param,info);
1015
 
      mi_intersect_keys_active(share->state.key_map, param->keys_in_use);
1016
 
      error =chk_size(param,info);
1017
 
      if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1018
 
        error|=chk_del(param, info,param->testflag);
1019
 
      if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1020
 
                      !param->start_check_pos)))
1021
 
      {
1022
 
        error|=chk_key(param, info);
1023
 
        if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1024
 
          error=update_state_info(param, info,
1025
 
                                  ((param->testflag & T_STATISTICS) ?
1026
 
                                   UPDATE_STAT : 0) |
1027
 
                                  ((param->testflag & T_AUTO_INC) ?
1028
 
                                   UPDATE_AUTO_INC : 0));
1029
 
      }
1030
 
      if ((!rep_quick && !error) ||
1031
 
          !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1032
 
      {
1033
 
        if (param->testflag & (T_EXTEND | T_MEDIUM))
1034
 
          init_key_cache(dflt_key_cache,opt_key_cache_block_size,
1035
 
                         param->use_buffers, 0, 0);
1036
 
        init_io_cache(&param->read_cache,datafile,
1037
 
                      (uint) param->read_buffer_length,
1038
 
                      READ_CACHE,
1039
 
                      (param->start_check_pos ?
1040
 
                       param->start_check_pos :
1041
 
                       share->pack.header_length),
1042
 
                      1,
1043
 
                      MYF(MY_WME));
1044
 
        lock_memory(param);
1045
 
        if ((info->s->options & (HA_OPTION_PACK_RECORD |
1046
 
                                 HA_OPTION_COMPRESS_RECORD)) ||
1047
 
            (param->testflag & (T_EXTEND | T_MEDIUM)))
1048
 
          error|=chk_data_link(param, info, param->testflag & T_EXTEND);
1049
 
        error|=flush_blocks(param, share->key_cache, share->kfile);
1050
 
        end_io_cache(&param->read_cache);
1051
 
      }
1052
 
      if (!error)
1053
 
      {
1054
 
        if ((share->state.changed & STATE_CHANGED) &&
1055
 
            (param->testflag & T_UPDATE_STATE))
1056
 
          info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1057
 
        share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1058
 
                                 STATE_CRASHED_ON_REPAIR);
1059
 
      }
1060
 
      else if (!mi_is_crashed(info) &&
1061
 
               (param->testflag & T_UPDATE_STATE))
1062
 
      {                                         /* Mark crashed */
1063
 
        mi_mark_crashed(info);
1064
 
        info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1065
 
      }
1066
 
    }
1067
 
  }
1068
 
  if ((param->testflag & T_AUTO_INC) ||
1069
 
      ((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1070
 
    update_auto_increment_key(param, info,
1071
 
                              (bool) !test(param->testflag & T_AUTO_INC));
1072
 
 
1073
 
  if (!(param->testflag & T_DESCRIPT))
1074
 
  {
1075
 
    if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1076
 
      error|=update_state_info(param, info,
1077
 
                               UPDATE_OPEN_COUNT |
1078
 
                               (((param->testflag & T_REP_ANY) ?
1079
 
                                 UPDATE_TIME : 0) |
1080
 
                                (state_updated ? UPDATE_STAT : 0) |
1081
 
                                ((param->testflag & T_SORT_RECORDS) ?
1082
 
                                 UPDATE_SORT : 0)));
1083
 
    info->update&= ~HA_STATE_CHANGED;
1084
 
  }
1085
 
  mi_lock_database(info, F_UNLCK);
1086
 
end2:
1087
 
  if (mi_close(info))
1088
 
  {
1089
 
    mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
1090
 
    return(1);
1091
 
  }
1092
 
  if (error == 0)
1093
 
  {
1094
 
    if (param->out_flag & O_NEW_DATA)
1095
 
      error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
1096
 
                               raid_chunks,
1097
 
                               ((param->testflag & T_BACKUP_DATA) ?
1098
 
                                MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1099
 
    if (param->out_flag & O_NEW_INDEX)
1100
 
      error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
1101
 
                               MYF(0));
1102
 
  }
1103
 
  fflush(stdout); fflush(stderr);
1104
 
  if (param->error_printed)
1105
 
  {
1106
 
    if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1107
 
    {
1108
 
      fprintf(stderr,
1109
 
              "MyISAM-table '%s' is not fixed because of errors\n",
1110
 
              filename);
1111
 
      if (param->testflag & T_REP_ANY)
1112
 
        fprintf(stderr,
1113
 
                "Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n");
1114
 
    }
1115
 
    else if (!(param->error_printed & 2) &&
1116
 
             !(param->testflag & T_FORCE_CREATE))
1117
 
      fprintf(stderr,
1118
 
              "MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
1119
 
              filename);
1120
 
  }
1121
 
  else if (param->warning_printed &&
1122
 
           ! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1123
 
                          T_FORCE_CREATE)))
1124
 
    fprintf(stderr, "MyISAM-table '%s' is usable but should be fixed\n",
1125
 
            filename);
1126
 
  fflush(stderr);
1127
 
  return(error);
1128
 
} /* myisamchk */
1129
 
 
1130
 
 
1131
 
         /* Write info about table */
1132
 
 
1133
 
static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
1134
 
{
1135
 
  uint32_t key,keyseg_nr,field,start;
1136
 
  register MI_KEYDEF *keyinfo;
1137
 
  register HA_KEYSEG *keyseg;
1138
 
  register const char *text;
1139
 
  char buff[160],length[10],*pos,*end;
1140
 
  enum en_fieldtype type;
1141
 
  MYISAM_SHARE *share=info->s;
1142
 
  char llbuff[22],llbuff2[22];
1143
 
 
1144
 
  printf("\nMyISAM file:         %s\n",name);
1145
 
  fputs("Record format:       ",stdout);
1146
 
  if (share->options & HA_OPTION_COMPRESS_RECORD)
1147
 
    puts("Compressed");
1148
 
  else if (share->options & HA_OPTION_PACK_RECORD)
1149
 
    puts("Packed");
1150
 
  else
1151
 
    puts("Fixed length");
1152
 
  printf("Character set:       %s (%d)\n",
1153
 
         get_charset_name(share->state.header.language),
1154
 
         share->state.header.language);
1155
 
 
1156
 
  if (param->testflag & T_VERBOSE)
1157
 
  {
1158
 
    printf("File-version:        %d\n",
1159
 
           (int) share->state.header.file_version[3]);
1160
 
    if (share->state.create_time)
1161
 
    {
1162
 
      get_date(buff,1,share->state.create_time);
1163
 
      printf("Creation time:       %s\n",buff);
1164
 
    }
1165
 
    if (share->state.check_time)
1166
 
    {
1167
 
      get_date(buff,1,share->state.check_time);
1168
 
      printf("Recover time:        %s\n",buff);
1169
 
    }
1170
 
    pos=buff;
1171
 
    if (share->state.changed & STATE_CRASHED)
1172
 
      my_stpcpy(buff,"crashed");
1173
 
    else
1174
 
    {
1175
 
      if (share->state.open_count)
1176
 
        pos=my_stpcpy(pos,"open,");
1177
 
      if (share->state.changed & STATE_CHANGED)
1178
 
        pos=my_stpcpy(pos,"changed,");
1179
 
      else
1180
 
        pos=my_stpcpy(pos,"checked,");
1181
 
      if (!(share->state.changed & STATE_NOT_ANALYZED))
1182
 
        pos=my_stpcpy(pos,"analyzed,");
1183
 
      if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1184
 
        pos=my_stpcpy(pos,"optimized keys,");
1185
 
      if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1186
 
        pos=my_stpcpy(pos,"sorted index pages,");
1187
 
      pos[-1]=0;                                /* Remove extra ',' */
1188
 
    }      
1189
 
    printf("Status:              %s\n",buff);
1190
 
    if (share->base.auto_key)
1191
 
    {
1192
 
      printf("Auto increment key:  %13d  Last value:         %13s\n",
1193
 
             share->base.auto_key,
1194
 
             llstr(share->state.auto_increment,llbuff));
1195
 
    }
1196
 
    if (share->base.raid_type)
1197
 
    {
1198
 
      printf("RAID:                Type:  %u   Chunks: %u  Chunksize: %lu\n",
1199
 
             share->base.raid_type,
1200
 
             share->base.raid_chunks,
1201
 
             share->base.raid_chunksize);
1202
 
    }
1203
 
    if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1204
 
      printf("Checksum:  %23s\n",llstr(info->state->checksum,llbuff));
1205
 
;
1206
 
    if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1207
 
      printf("Keys are only flushed at close\n");
1208
 
 
1209
 
  }
1210
 
  printf("Data records:        %13s  Deleted blocks:     %13s\n",
1211
 
         llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1212
 
  if (param->testflag & T_SILENT)
1213
 
    return;                             /* This is enough */
1214
 
 
1215
 
  if (param->testflag & T_VERBOSE)
1216
 
  {
1217
 
#ifdef USE_RELOC
1218
 
    printf("Init-relocation:     %13s\n",llstr(share->base.reloc,llbuff));
1219
 
#endif
1220
 
    printf("Datafile parts:      %13s  Deleted data:       %13s\n",
1221
 
           llstr(share->state.split,llbuff),
1222
 
           llstr(info->state->empty,llbuff2));
1223
 
    printf("Datafile pointer (bytes):%9d  Keyfile pointer (bytes):%9d\n",
1224
 
           share->rec_reflength,share->base.key_reflength);
1225
 
    printf("Datafile length:     %13s  Keyfile length:     %13s\n",
1226
 
           llstr(info->state->data_file_length,llbuff),
1227
 
           llstr(info->state->key_file_length,llbuff2));
1228
 
 
1229
 
    if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1230
 
      puts("This is a one-record table");
1231
 
    else
1232
 
    {
1233
 
      if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1234
 
          share->base.max_key_file_length != HA_OFFSET_ERROR)
1235
 
        printf("Max datafile length: %13s  Max keyfile length: %13s\n",
1236
 
               llstr(share->base.max_data_file_length-1,llbuff),
1237
 
               llstr(share->base.max_key_file_length-1,llbuff2));
1238
 
    }
1239
 
  }
1240
 
 
1241
 
  printf("Recordlength:        %13d\n",(int) share->base.pack_reclength);
1242
 
  if (! mi_is_all_keys_active(share->state.key_map, share->base.keys))
1243
 
  {
1244
 
    int64_t2str(share->state.key_map,buff,2);
1245
 
    printf("Using only keys '%s' of %d possibly keys\n",
1246
 
           buff, share->base.keys);
1247
 
  }
1248
 
  puts("\ntable description:");
1249
 
  printf("Key Start Len Index   Type");
1250
 
  if (param->testflag & T_VERBOSE)
1251
 
    printf("                     Rec/key         Root  Blocksize");
1252
 
  putchar('\n');
1253
 
 
1254
 
  for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1255
 
       key < share->base.keys;
1256
 
       key++,keyinfo++)
1257
 
  {
1258
 
    keyseg=keyinfo->seg;
1259
 
    if (keyinfo->flag & HA_NOSAME) text="unique ";
1260
 
    else text="multip.";
1261
 
 
1262
 
    pos=buff;
1263
 
    if (keyseg->flag & HA_REVERSE_SORT)
1264
 
      *pos++ = '-';
1265
 
    pos=my_stpcpy(pos,type_names[keyseg->type]);
1266
 
    *pos++ = ' ';
1267
 
    *pos=0;
1268
 
    if (keyinfo->flag & HA_PACK_KEY)
1269
 
      pos=my_stpcpy(pos,prefix_packed_txt);
1270
 
    if (keyinfo->flag & HA_BINARY_PACK_KEY)
1271
 
      pos=my_stpcpy(pos,bin_packed_txt);
1272
 
    if (keyseg->flag & HA_SPACE_PACK)
1273
 
      pos=my_stpcpy(pos,diff_txt);
1274
 
    if (keyseg->flag & HA_BLOB_PART)
1275
 
      pos=my_stpcpy(pos,blob_txt);
1276
 
    if (keyseg->flag & HA_NULL_PART)
1277
 
      pos=my_stpcpy(pos,null_txt);
1278
 
    *pos=0;
1279
 
 
1280
 
    printf("%-4d%-6ld%-3d %-8s%-21s",
1281
 
           key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1282
 
    if (share->state.key_root[key] != HA_OFFSET_ERROR)
1283
 
      llstr(share->state.key_root[key],buff);
1284
 
    else
1285
 
      buff[0]=0;
1286
 
    if (param->testflag & T_VERBOSE)
1287
 
      printf("%11lu %12s %10d",
1288
 
             share->state.rec_per_key_part[keyseg_nr++],
1289
 
             buff,keyinfo->block_length);
1290
 
    putchar('\n');
1291
 
    while ((++keyseg)->type != HA_KEYTYPE_END)
1292
 
    {
1293
 
      pos=buff;
1294
 
      if (keyseg->flag & HA_REVERSE_SORT)
1295
 
        *pos++ = '-';
1296
 
      pos=my_stpcpy(pos,type_names[keyseg->type]);
1297
 
      *pos++= ' ';
1298
 
      if (keyseg->flag & HA_SPACE_PACK)
1299
 
        pos=my_stpcpy(pos,diff_txt);
1300
 
      if (keyseg->flag & HA_BLOB_PART)
1301
 
        pos=my_stpcpy(pos,blob_txt);
1302
 
      if (keyseg->flag & HA_NULL_PART)
1303
 
        pos=my_stpcpy(pos,null_txt);
1304
 
      *pos=0;
1305
 
      printf("    %-6ld%-3d         %-21s",
1306
 
             (long) keyseg->start+1,keyseg->length,buff);
1307
 
      if (param->testflag & T_VERBOSE)
1308
 
        printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
1309
 
      putchar('\n');
1310
 
    }
1311
 
    keyseg++;
1312
 
  }
1313
 
  if (share->state.header.uniques)
1314
 
  {
1315
 
    MI_UNIQUEDEF *uniqueinfo;
1316
 
    puts("\nUnique  Key  Start  Len  Nullpos  Nullbit  Type");
1317
 
    for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1318
 
         key < share->state.header.uniques; key++, uniqueinfo++)
1319
 
    {
1320
 
      bool new_row=0;
1321
 
      char null_bit[8],null_pos[8];
1322
 
      printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1323
 
      for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1324
 
      {
1325
 
        if (new_row)
1326
 
          fputs("             ",stdout);
1327
 
        null_bit[0]=null_pos[0]=0;
1328
 
        if (keyseg->null_bit)
1329
 
        {
1330
 
          sprintf(null_bit,"%d",keyseg->null_bit);
1331
 
          sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1332
 
        }
1333
 
        printf("%-7ld%-5d%-9s%-10s%-30s\n",
1334
 
               (long) keyseg->start+1,keyseg->length,
1335
 
               null_pos,null_bit,
1336
 
               type_names[keyseg->type]);
1337
 
        new_row=1;
1338
 
      }
1339
 
    }
1340
 
  }
1341
 
  if (param->verbose > 1)
1342
 
  {
1343
 
    char null_bit[8],null_pos[8];
1344
 
    printf("\nField Start Length Nullpos Nullbit Type");
1345
 
    if (share->options & HA_OPTION_COMPRESS_RECORD)
1346
 
      printf("                         Huff tree  Bits");
1347
 
    putchar('\n');
1348
 
    start=1;
1349
 
    for (field=0 ; field < share->base.fields ; field++)
1350
 
    {
1351
 
      if (share->options & HA_OPTION_COMPRESS_RECORD)
1352
 
        type=share->rec[field].base_type;
1353
 
      else
1354
 
        type=(enum en_fieldtype) share->rec[field].type;
1355
 
      end=my_stpcpy(buff,field_pack[type]);
1356
 
      if (share->options & HA_OPTION_COMPRESS_RECORD)
1357
 
      {
1358
 
        if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
1359
 
          end=my_stpcpy(end,", not_always");
1360
 
        if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1361
 
          end=my_stpcpy(end,", no empty");
1362
 
        if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
1363
 
        {
1364
 
          sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
1365
 
          end= strchr(end, '\0');
1366
 
        }
1367
 
      }
1368
 
      if (buff[0] == ',')
1369
 
        my_stpcpy(buff,buff+2);
1370
 
      int10_to_str((long) share->rec[field].length,length,10);
1371
 
      null_bit[0]=null_pos[0]=0;
1372
 
      if (share->rec[field].null_bit)
1373
 
      {
1374
 
        sprintf(null_bit,"%d",share->rec[field].null_bit);
1375
 
        sprintf(null_pos,"%d",share->rec[field].null_pos+1);
1376
 
      }
1377
 
      printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
1378
 
             null_pos, null_bit, buff);
1379
 
      if (share->options & HA_OPTION_COMPRESS_RECORD)
1380
 
      {
1381
 
        if (share->rec[field].huff_tree)
1382
 
          printf("%3d    %2d",
1383
 
                 (uint) (share->rec[field].huff_tree-share->decode_trees)+1,
1384
 
                 share->rec[field].huff_tree->quick_table_bits);
1385
 
      }
1386
 
      putchar('\n');
1387
 
      start+=share->rec[field].length;
1388
 
    }
1389
 
  }
1390
 
  return;
1391
 
} /* describe */
1392
 
 
1393
 
 
1394
 
        /* Sort records according to one key */
1395
 
 
1396
 
static int mi_sort_records(MI_CHECK *param,
1397
 
                           register MI_INFO *info, char * name,
1398
 
                           uint32_t sort_key,
1399
 
                           bool write_info,
1400
 
                           bool update_index)
1401
 
{
1402
 
  int got_error;
1403
 
  uint32_t key;
1404
 
  MI_KEYDEF *keyinfo;
1405
 
  File new_file;
1406
 
  unsigned char *temp_buff;
1407
 
  ha_rows old_record_count;
1408
 
  MYISAM_SHARE *share=info->s;
1409
 
  char llbuff[22],llbuff2[22];
1410
 
  SORT_INFO sort_info;
1411
 
  MI_SORT_PARAM sort_param;
1412
 
 
1413
 
  memset(&sort_info, 0, sizeof(sort_info));
1414
 
  memset(&sort_param, 0, sizeof(sort_param));
1415
 
  sort_param.sort_info=&sort_info;
1416
 
  sort_info.param=param;
1417
 
  keyinfo= &share->keyinfo[sort_key];
1418
 
  got_error=1;
1419
 
  temp_buff=0;
1420
 
  new_file= -1;
1421
 
 
1422
 
  if (! mi_is_key_active(share->state.key_map, sort_key))
1423
 
  {
1424
 
    mi_check_print_warning(param,
1425
 
                           "Can't sort table '%s' on key %d;  No such key",
1426
 
                name,sort_key+1);
1427
 
    param->error_printed=0;
1428
 
    return(0);                          /* Nothing to do */
1429
 
  }
1430
 
  if (share->data_file_type == COMPRESSED_RECORD)
1431
 
  {
1432
 
    mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
1433
 
    param->error_printed=0;
1434
 
    return(0);                          /* Nothing to do */
1435
 
  }
1436
 
  if (!(param->testflag & T_SILENT))
1437
 
  {
1438
 
    printf("- Sorting records for MyISAM-table '%s'\n",name);
1439
 
    if (write_info)
1440
 
      printf("Data records: %9s   Deleted: %9s\n",
1441
 
             llstr(info->state->records,llbuff),
1442
 
             llstr(info->state->del,llbuff2));
1443
 
  }
1444
 
  if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1445
 
    return(0);                          /* Nothing to do */
1446
 
 
1447
 
  init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers,
1448
 
                 0, 0);
1449
 
  if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1450
 
                   WRITE_CACHE,share->pack.header_length,1,
1451
 
                   MYF(MY_WME | MY_WAIT_IF_FULL)))
1452
 
    goto err;
1453
 
  info->opt_flag|=WRITE_CACHE_USED;
1454
 
 
1455
 
  if (!(temp_buff=(unsigned char*) my_alloca((uint) keyinfo->block_length)))
1456
 
  {
1457
 
    mi_check_print_error(param,"Not enough memory for key block");
1458
 
    goto err;
1459
 
  }
1460
 
 
1461
 
  if (!mi_alloc_rec_buff(info, -1, &sort_param.record))
1462
 
  {
1463
 
    mi_check_print_error(param,"Not enough memory for record");
1464
 
    goto err;
1465
 
  }
1466
 
  fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
1467
 
  new_file=my_raid_create(fn_format(param->temp_filename,
1468
 
                                    param->temp_filename,"",
1469
 
                                    DATA_TMP_EXT,2+4),
1470
 
                          0,param->tmpfile_createflag,
1471
 
                          share->base.raid_type,
1472
 
                          share->base.raid_chunks,
1473
 
                          share->base.raid_chunksize,
1474
 
                          MYF(0));
1475
 
  if (new_file < 0)
1476
 
  {
1477
 
    mi_check_print_error(param,"Can't create new tempfile: '%s'",
1478
 
                         param->temp_filename);
1479
 
    goto err;
1480
 
  }
1481
 
  if (share->pack.header_length)
1482
 
    if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
1483
 
                 "datafile-header"))
1484
 
      goto err;
1485
 
  info->rec_cache.file=new_file;                /* Use this file for cacheing*/
1486
 
 
1487
 
  lock_memory(param);
1488
 
  for (key=0 ; key < share->base.keys ; key++)
1489
 
    share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1490
 
 
1491
 
  if (my_pread(share->kfile,(unsigned char*) temp_buff,
1492
 
               (uint) keyinfo->block_length,
1493
 
               share->state.key_root[sort_key],
1494
 
               MYF(MY_NABP+MY_WME)))
1495
 
  {
1496
 
    mi_check_print_error(param,"Can't read indexpage from filepos: %s",
1497
 
                (ulong) share->state.key_root[sort_key]);
1498
 
    goto err;
1499
 
  }
1500
 
 
1501
 
  /* Setup param for sort_write_record */
1502
 
  sort_info.info=info;
1503
 
  sort_info.new_data_file_type=share->data_file_type;
1504
 
  sort_param.fix_datafile=1;
1505
 
  sort_param.master=1;
1506
 
  sort_param.filepos=share->pack.header_length;
1507
 
  old_record_count=info->state->records;
1508
 
  info->state->records=0;
1509
 
  if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1510
 
    info->state->checksum=0;
1511
 
 
1512
 
  if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
1513
 
                        temp_buff, sort_key,new_file,update_index) ||
1514
 
      write_data_suffix(&sort_info,1) ||
1515
 
      flush_io_cache(&info->rec_cache))
1516
 
    goto err;
1517
 
 
1518
 
  if (info->state->records != old_record_count)
1519
 
  {
1520
 
    mi_check_print_error(param,"found %s of %s records",
1521
 
                llstr(info->state->records,llbuff),
1522
 
                llstr(old_record_count,llbuff2));
1523
 
    goto err;
1524
 
  }
1525
 
 
1526
 
  my_close(info->dfile,MYF(MY_WME));
1527
 
  param->out_flag|=O_NEW_DATA;                  /* Data in new file */
1528
 
  info->dfile=new_file;                         /* Use new datafile */
1529
 
  info->state->del=0;
1530
 
  info->state->empty=0;
1531
 
  share->state.dellink= HA_OFFSET_ERROR;
1532
 
  info->state->data_file_length=sort_param.filepos;
1533
 
  share->state.split=info->state->records;      /* Only hole records */
1534
 
  share->state.version=(ulong) time((time_t*) 0);
1535
 
 
1536
 
  info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1537
 
 
1538
 
  if (param->testflag & T_WRITE_LOOP)
1539
 
  {
1540
 
    fputs("          \r",stdout); fflush(stdout);
1541
 
  }
1542
 
  got_error=0;
1543
 
 
1544
 
err:
1545
 
  if (got_error && new_file >= 0)
1546
 
  {
1547
 
    end_io_cache(&info->rec_cache);
1548
 
    (void) my_close(new_file,MYF(MY_WME));
1549
 
    (void) my_raid_delete(param->temp_filename, share->base.raid_chunks,
1550
 
                          MYF(MY_WME));
1551
 
  }
1552
 
  if (temp_buff)
1553
 
  {
1554
 
    my_afree((unsigned char*) temp_buff);
1555
 
  }
1556
 
  void * rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record);
1557
 
  if (rec_buff_ptr != NULL)
1558
 
    free(rec_buff_ptr);
1559
 
 
1560
 
  info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1561
 
  end_io_cache(&info->rec_cache);
1562
 
  free(sort_info.buff);
1563
 
  sort_info.buff=0;
1564
 
  share->state.sortkey=sort_key;
1565
 
  return(flush_blocks(param, share->key_cache, share->kfile) |
1566
 
              got_error);
1567
 
} /* sort_records */
1568
 
 
1569
 
 
1570
 
         /* Sort records recursive using one index */
1571
 
 
1572
 
static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
1573
 
                             MI_KEYDEF *keyinfo,
1574
 
                             my_off_t page, unsigned char *buff, uint32_t sort_key,
1575
 
                             File new_file,bool update_index)
1576
 
{
1577
 
  uint  nod_flag,used_length,key_length;
1578
 
  unsigned char *temp_buff,*keypos,*endpos;
1579
 
  my_off_t next_page,rec_pos;
1580
 
  unsigned char lastkey[MI_MAX_KEY_BUFF];
1581
 
  char llbuff[22];
1582
 
  SORT_INFO *sort_info= sort_param->sort_info;
1583
 
  MI_CHECK *param=sort_info->param;
1584
 
 
1585
 
  nod_flag=mi_test_if_nod(buff);
1586
 
  temp_buff=0;
1587
 
 
1588
 
  if (nod_flag)
1589
 
  {
1590
 
    if (!(temp_buff=(unsigned char*) my_alloca((uint) keyinfo->block_length)))
1591
 
    {
1592
 
      mi_check_print_error(param,"Not Enough memory");
1593
 
      return(-1);
1594
 
    }
1595
 
  }
1596
 
  used_length=mi_getint(buff);
1597
 
  keypos=buff+2+nod_flag;
1598
 
  endpos=buff+used_length;
1599
 
  for ( ;; )
1600
 
  {
1601
 
    if (nod_flag)
1602
 
    {
1603
 
      next_page=_mi_kpos(nod_flag,keypos);
1604
 
      if (my_pread(info->s->kfile,(unsigned char*) temp_buff,
1605
 
                  (uint) keyinfo->block_length, next_page,
1606
 
                   MYF(MY_NABP+MY_WME)))
1607
 
      {
1608
 
        mi_check_print_error(param,"Can't read keys from filepos: %s",
1609
 
                    llstr(next_page,llbuff));
1610
 
        goto err;
1611
 
      }
1612
 
      if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
1613
 
                            new_file, update_index))
1614
 
        goto err;
1615
 
    }
1616
 
    if (keypos >= endpos ||
1617
 
        (key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
1618
 
        == 0)
1619
 
      break;
1620
 
    rec_pos= _mi_dpos(info,0,lastkey+key_length);
1621
 
 
1622
 
    if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
1623
 
    {
1624
 
      mi_check_print_error(param,"%d when reading datafile",my_errno);
1625
 
      goto err;
1626
 
    }
1627
 
    if (rec_pos != sort_param->filepos && update_index)
1628
 
    {
1629
 
      _mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
1630
 
                   sort_param->filepos);
1631
 
      if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
1632
 
                    sort_key))
1633
 
      {
1634
 
        mi_check_print_error(param,"%d when updating key-pointers",my_errno);
1635
 
        goto err;
1636
 
      }
1637
 
    }
1638
 
    if (sort_write_record(sort_param))
1639
 
      goto err;
1640
 
  }
1641
 
  /* Clear end of block to get better compression if the table is backuped */
1642
 
  memset(buff+used_length, 0, keyinfo->block_length-used_length);
1643
 
  if (my_pwrite(info->s->kfile,(unsigned char*) buff,(uint) keyinfo->block_length,
1644
 
                page,param->myf_rw))
1645
 
  {
1646
 
    mi_check_print_error(param,"%d when updating keyblock",my_errno);
1647
 
    goto err;
1648
 
  }
1649
 
  if (temp_buff)
1650
 
    my_afree((unsigned char*) temp_buff);
1651
 
  return(0);
1652
 
err:
1653
 
  if (temp_buff)
1654
 
    my_afree((unsigned char*) temp_buff);
1655
 
  return(1);
1656
 
} /* sort_record_index */
1657
 
 
1658
 
 
1659
 
 
1660
 
/*
1661
 
  Check if myisamchk was killed by a signal
1662
 
  This is overloaded by other programs that want to be able to abort
1663
 
  sorting
1664
 
*/
1665
 
 
1666
 
static int not_killed= 0;
1667
 
 
1668
 
volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
1669
 
{
1670
 
  return &not_killed;                   /* always NULL */
1671
 
}
1672
 
 
1673
 
        /* print warnings and errors */
1674
 
        /* VARARGS */
1675
 
 
1676
 
void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
1677
 
                         const char *fmt,...)
1678
 
{
1679
 
  va_list args;
1680
 
 
1681
 
  va_start(args,fmt);
1682
 
  vfprintf(stdout, fmt, args);
1683
 
  fputc('\n',stdout);
1684
 
  va_end(args);
1685
 
}
1686
 
 
1687
 
/* VARARGS */
1688
 
 
1689
 
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
1690
 
{
1691
 
  va_list args;
1692
 
 
1693
 
  fflush(stdout);
1694
 
  if (!param->warning_printed && !param->error_printed)
1695
 
  {
1696
 
    if (param->testflag & T_SILENT)
1697
 
      fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,
1698
 
              param->isam_file_name);
1699
 
    param->out_flag|= O_DATA_LOST;
1700
 
  }
1701
 
  param->warning_printed=1;
1702
 
  va_start(args,fmt);
1703
 
  fprintf(stderr,"%s: warning: ",my_progname_short);
1704
 
  vfprintf(stderr, fmt, args);
1705
 
  fputc('\n',stderr);
1706
 
  fflush(stderr);
1707
 
  va_end(args);
1708
 
  return;
1709
 
}
1710
 
 
1711
 
/* VARARGS */
1712
 
 
1713
 
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
1714
 
{
1715
 
  va_list args;
1716
 
 
1717
 
  fflush(stdout);
1718
 
  if (!param->warning_printed && !param->error_printed)
1719
 
  {
1720
 
    if (param->testflag & T_SILENT)
1721
 
      fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name);
1722
 
    param->out_flag|= O_DATA_LOST;
1723
 
  }
1724
 
  param->error_printed|=1;
1725
 
  va_start(args,fmt);
1726
 
  fprintf(stderr,"%s: error: ",my_progname_short);
1727
 
  vfprintf(stderr, fmt, args);
1728
 
  fputc('\n',stderr);
1729
 
  fflush(stderr);
1730
 
  va_end(args);
1731
 
  return;
1732
 
}
1733