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