~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/myisam/myisamchk.cc

  • Committer: Padraig O'Sullivan
  • Date: 2009-07-30 02:39:13 UTC
  • mto: (1115.3.11 captain)
  • mto: This revision was merged to the branch mainline in revision 1121.
  • Revision ID: osullivan.padraig@gmail.com-20090730023913-o2zuocp32l6btnc2
Removing references to MY_BITMAP throughout the code base and updating calls
to MyBitmap in various places to use the new interface.

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