~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/myisamchk.c

  • Committer: Brian Aker
  • Date: 2010-05-27 01:25:56 UTC
  • mfrom: (1567.1.4 new-staging)
  • Revision ID: brian@gaz-20100527012556-5zgkirkl7swbigd6
Merge of Brian, Paul. PBXT compile issue, and test framework cleanup. 

Show diffs side-by-side

added added

removed removed

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