~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/myisam/myisamchk.cc

  • Committer: Brian Aker
  • Date: 2009-08-15 00:59:30 UTC
  • mfrom: (1115.1.7 merge)
  • Revision ID: brian@gaz-20090815005930-q47yenjrq1esiwsz
Merge of Trond + Brian

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