~drizzle-trunk/drizzle/development

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