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