1/* Copyright (C) 2006-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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
15
16/* Describe, check and repair of MARIA tables */
17
18#include "ma_fulltext.h"
19#include <myisamchk.h>
20#include <my_bit.h>
21#include <m_ctype.h>
22#include <stdarg.h>
23#include <my_getopt.h>
24#include <my_check_opt.h>
25#ifdef HAVE_SYS_MMAN_H
26#include <sys/mman.h>
27#endif
28
29static uint decode_bits;
30static char **default_argv;
31static const char *load_default_groups[]= { "aria_chk", 0 };
32static const char *set_collation_name, *opt_tmpdir, *opt_log_dir;
33static const char *default_log_dir;
34static CHARSET_INFO *set_collation;
35static int stopwords_inited= 0;
36static MY_TMPDIR maria_chk_tmpdir;
37static my_bool opt_transaction_logging, opt_debug;
38static my_bool opt_ignore_control_file, opt_require_control_file;
39static my_bool opt_warning_for_wrong_transid, opt_update_state;
40
41static const char *type_names[]=
42{
43 "impossible","char","binary", "short", "long", "float",
44 "double","number","unsigned short",
45 "unsigned long","longlong","ulonglong","int24",
46 "uint24","int8","varchar", "varbin", "varchar2", "varbin2", "bit",
47 "?","?"
48};
49
50static const char *prefix_packed_txt="packed ",
51 *bin_packed_txt="prefix ",
52 *diff_txt="stripped ",
53 *null_txt="NULL",
54 *blob_txt="BLOB ";
55
56static const char *field_pack[]=
57{
58 "","no endspace", "no prespace",
59 "no zeros", "blob", "constant", "table-lockup",
60 "always zero","varchar","unique-hash","?","?"
61};
62
63static const char *record_formats[]=
64{
65 "Fixed length", "Packed", "Compressed", "Block", "No data", "?", "?"
66};
67
68static const char *bitmap_description[]=
69{
70 "Empty page", "Part filled head page","Part filled head page",
71 "Part filled head page", "Full head page",
72 "Part filled tail page","Part filled tail page",
73 "Full tail or blob page"
74};
75
76static const char *maria_stats_method_str="nulls_unequal";
77static char default_open_errmsg[]= "%d when opening Aria table '%s'";
78static char default_close_errmsg[]= "%d when closing Aria table '%s'";
79
80static void get_options(int *argc,char * * *argv);
81static void print_version(void);
82static void usage(void);
83static int maria_chk(HA_CHECK *param, char *filename);
84static void descript(HA_CHECK *param, register MARIA_HA *info, char *name);
85static int maria_sort_records(HA_CHECK *param, register MARIA_HA *info,
86 char *name, uint sort_key,
87 my_bool write_info, my_bool update_index);
88static int sort_record_index(MARIA_SORT_PARAM *sort_param, MARIA_PAGE *page,
89 uint sortkey, File new_file,
90 my_bool update_index);
91static my_bool write_log_record(HA_CHECK *param);
92ATTRIBUTE_NORETURN static void my_exit(int exit_code);
93
94HA_CHECK check_param;
95
96/* Free memory and exit */
97
98static void my_exit(int exit_code)
99{
100 free_tmpdir(&maria_chk_tmpdir);
101 free_defaults(default_argv);
102 my_end(check_param.testflag & T_INFO ?
103 MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
104 exit(exit_code);
105}
106
107
108 /* Main program */
109
110int main(int argc, char **argv)
111{
112 int error;
113 MY_INIT(argv[0]);
114
115 default_log_dir= opt_log_dir= maria_data_root= (char *)".";
116 maria_chk_init(&check_param);
117 check_param.opt_lock_memory= 1; /* Lock memory if possible */
118 check_param.using_global_keycache = 0;
119 get_options(&argc,(char***) &argv);
120 maria_quick_table_bits=decode_bits;
121 error=0;
122 maria_init();
123
124 maria_block_size= 0; /* Use block size from control file */
125 if (!opt_ignore_control_file &&
126 (ma_control_file_open(FALSE, opt_require_control_file ||
127 !(check_param.testflag & T_SILENT)) &&
128 (opt_require_control_file ||
129 (opt_transaction_logging && (check_param.testflag & T_REP_ANY)))))
130 {
131 error= 1;
132 goto end;
133 }
134
135 /*
136 If we are doing a repair, user may want to store this repair into the log
137 so that the log has a complete history and can be used to replay.
138 */
139 if (opt_transaction_logging && (check_param.testflag & T_REP_ANY))
140 {
141 if (init_pagecache(maria_log_pagecache,
142 TRANSLOG_PAGECACHE_SIZE, 0, 0,
143 TRANSLOG_PAGE_SIZE, 0, MY_WME) == 0 ||
144 translog_init(opt_log_dir, TRANSLOG_FILE_SIZE,
145 0, 0, maria_log_pagecache,
146 TRANSLOG_DEFAULT_FLAGS, 0))
147 {
148 _ma_check_print_error(&check_param,
149 "Can't initialize transaction logging. Run "
150 "recovery with switch --skip-transaction-log");
151 error= 1;
152 goto end;
153 }
154 }
155
156 while (--argc >= 0)
157 {
158 int new_error=maria_chk(&check_param, *(argv++));
159 if ((check_param.testflag & T_REP_ANY) != T_REP)
160 check_param.testflag&= ~T_REP;
161 fflush(stdout);
162 fflush(stderr);
163 if ((check_param.error_printed | check_param.warning_printed) &&
164 (check_param.testflag & T_FORCE_CREATE) &&
165 (!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
166 T_SORT_INDEX))))
167 {
168 ulonglong old_testflag=check_param.testflag;
169 if (!(check_param.testflag & T_REP))
170 check_param.testflag|= T_REP_BY_SORT;
171 check_param.testflag&= ~T_EXTEND; /* Not needed */
172 error|=maria_chk(&check_param, argv[-1]);
173 check_param.testflag= old_testflag;
174 fflush(stdout);
175 fflush(stderr);
176 }
177 else
178 error|=new_error;
179 if (argc && (!(check_param.testflag & T_SILENT) ||
180 check_param.testflag & T_INFO))
181 {
182 puts("\n---------\n");
183 fflush(stdout);
184 }
185 }
186end:
187 if (check_param.total_files > 1)
188 { /* Only if descript */
189 char buff[22],buff2[22];
190 if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
191 puts("\n---------");
192 printf("\nTotal of all %d Aria-files:\nData records: %9s Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
193 llstr(check_param.total_deleted,buff2));
194 }
195 maria_end();
196 my_exit(error);
197#ifndef _lint
198 return 0; /* No compiler warning */
199#endif
200} /* main */
201
202enum options_mc {
203 OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
204 OPT_CORRECT_CHECKSUM, OPT_CREATE_MISSING_KEYS, OPT_PAGE_BUFFER_SIZE,
205 OPT_KEY_CACHE_BLOCK_SIZE, OPT_MARIA_BLOCK_SIZE,
206 OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
207 OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN,
208 OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE,
209 OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD, OPT_TRANSACTION_LOG,
210 OPT_ZEROFILL_KEEP_LSN,
211 OPT_REQUIRE_CONTROL_FILE, OPT_IGNORE_CONTROL_FILE,
212 OPT_LOG_DIR, OPT_WARNING_FOR_WRONG_TRANSID
213};
214
215static struct my_option my_long_options[] =
216{
217 {"analyze", 'a',
218 "Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
219 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
220#ifdef __NETWARE__
221 {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
222 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
223#endif
224 {"block-search", 'b',
225 "No help available.",
226 0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
227 {"backup", 'B',
228 "Make a backup of the .MAD file as 'filename-time.BAK'.",
229 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
230 {"character-sets-dir", OPT_CHARSETS_DIR,
231 "Directory where character sets are.",
232 (char**) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
233 {"check", 'c',
234 "Check table for errors.",
235 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
236 {"check-only-changed", 'C',
237 "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).",
238 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
239 {"correct-checksum", OPT_CORRECT_CHECKSUM,
240 "Correct checksum information for table.",
241 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
242 {"create-missing-keys", OPT_CREATE_MISSING_KEYS,
243 "Create missing keys. This assumes that the data file is correct and that "
244 "the the number of rows stored in the index file is correct. Enables "
245 "--quick",
246 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
247#ifndef DBUG_OFF
248 {"debug", '#',
249 "Output debug log. Often this is 'd:t:o,filename'.",
250 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
251#endif
252 {"description", 'd',
253 "Prints some information about table.",
254 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
255 {"data-file-length", 'D',
256 "Max length of data file (when recreating data-file when it's full).",
257 &check_param.max_data_file_length,
258 &check_param.max_data_file_length,
259 0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
260 {"extend-check", 'e',
261 "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.",
262 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
263 {"fast", 'F',
264 "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).",
265 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
266 {"force", 'f',
267 "Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
268 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
269 {"HELP", 'H',
270 "Print all argument options sorted alphabetically and exit.",
271 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
272 {"help", '?',
273 "Print all options by groups and exit. See also --HELP",
274 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
275 {"information", 'i',
276 "Print statistics information about table that is checked.",
277 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
278 { "ignore-control-file", OPT_IGNORE_CONTROL_FILE,
279 "Ignore the control file",
280 (uchar**)&opt_ignore_control_file, 0, 0, GET_BOOL, NO_ARG,
281 0, 0, 0, 0, 0, 0},
282 {"keys-used", 'k',
283 "Tell Aria to update only some specific keys. # is a bit mask of which keys to use. This can be used to get faster inserts.",
284 &check_param.keys_in_use,
285 &check_param.keys_in_use,
286 0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
287 {"datadir", 'h',
288 "Path for control file (and logs if --logdir not used).",
289 &maria_data_root, 0, 0, GET_STR, REQUIRED_ARG,
290 0, 0, 0, 0, 0, 0},
291 {"logdir", OPT_LOG_DIR,
292 "Path for log files.",
293 (char**) &opt_log_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
294 {"max-record-length", OPT_MAX_RECORD_LENGTH,
295 "Skip rows bigger than this if aria_chk can't allocate memory to hold it",
296 &check_param.max_record_length,
297 &check_param.max_record_length,
298 0, GET_ULL, REQUIRED_ARG, LONGLONG_MAX, 0, LONGLONG_MAX, 0, 0, 0},
299 {"medium-check", 'm',
300 "Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
301 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
302 {"quick", 'q', "Faster repair by not modifying the data file.",
303 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
304 {"read-only", 'T',
305 "Don't mark table as checked.",
306 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
307 {"recover", 'r',
308 "Can fix almost anything except unique keys that aren't unique.",
309 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
310 {"parallel-recover", 'p',
311 "Same as '-r' but creates all the keys in parallel.",
312 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
313 {"safe-recover", 'o',
314 "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.",
315 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
316 {"sort-recover", 'n',
317 "Force recovering with sorting even if the temporary file was very big.",
318 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
319 { "require-control-file", OPT_REQUIRE_CONTROL_FILE,
320 "Abort if cannot find control file",
321 (uchar**)&opt_require_control_file, 0, 0, GET_BOOL, NO_ARG,
322 0, 0, 0, 0, 0, 0},
323#ifdef DEBUG
324 {"start-check-pos", OPT_START_CHECK_POS,
325 "No help available.",
326 0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
327#endif
328 {"set-auto-increment", 'A',
329 "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.",
330 &check_param.auto_increment_value,
331 &check_param.auto_increment_value,
332 0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
333 {"set-collation", OPT_SET_COLLATION,
334 "Change the collation used by the index",
335 (char**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG,
336 0, 0, 0, 0, 0, 0},
337 {"silent", 's',
338 "Only print errors. One can use two -s to make aria_chk very silent.",
339 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
340 {"sort-index", 'S',
341 "Sort index blocks. This speeds up 'read-next' in applications.",
342 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
343 {"sort-records", 'R',
344 "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!)",
345 &check_param.opt_sort_key,
346 &check_param.opt_sort_key,
347 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
348 {"tmpdir", 't', "Path for temporary files.", (char**) &opt_tmpdir,
349 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
350 {"transaction-log", OPT_TRANSACTION_LOG,
351 "Log repair command to transaction log",
352 &opt_transaction_logging, &opt_transaction_logging,
353 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
354 {"update-state", 'U',
355 "Mark tables as crashed if any errors were found and clean if check "
356 "didn't find any errors but table was marked as 'not clean' before. This "
357 "allows one to get rid of warnings like 'table not properly closed'. "
358 "If table was updated, update also the timestamp for when check was made. "
359 "This option is on by default!",
360 &opt_update_state, &opt_update_state, 0, GET_BOOL, NO_ARG,
361 1, 0, 0, 0, 0, 0},
362 {"unpack", 'u',
363 "Unpack file packed with aria_pack.",
364 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
365 {"verbose", 'v',
366 "Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
367 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
368 {"version", 'V', "Print version and exit.",
369 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
370 {"wait", 'w', "Wait if table is locked.",
371 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
372 {"warning-for-wrong-transaction-id", OPT_WARNING_FOR_WRONG_TRANSID,
373 "Give a warning if we find a transaction id in the table that is bigger"
374 "than what exists in the control file. Use --skip-... to disable warning",
375 &opt_warning_for_wrong_transid, &opt_warning_for_wrong_transid,
376 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
377 { "page_buffer_size", OPT_PAGE_BUFFER_SIZE,
378 "Size of page buffer. Used by --safe-repair",
379 &check_param.use_buffers, &check_param.use_buffers, 0,
380 GET_ULONG, REQUIRED_ARG, PAGE_BUFFER_INIT, 1024L*1024L,
381 SIZE_T_MAX, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
382 { "read_buffer_size", OPT_READ_BUFFER_SIZE,
383 "Read buffer size for sequential reads during scanning",
384 &check_param.read_buffer_length,
385 &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
386 (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
387 ~0ULL, (long) MALLOC_OVERHEAD, (long) 1L, 0},
388 { "write_buffer_size", OPT_WRITE_BUFFER_SIZE,
389 "Write buffer size for sequential writes during repair of fixed size or dynamic size rows",
390 &check_param.write_buffer_length,
391 &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
392 (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
393 ~0UL, (long) MALLOC_OVERHEAD, (long) 1L, 0},
394 { "sort_buffer_size", OPT_SORT_BUFFER_SIZE,
395 "Size of sort buffer. Used by --recover",
396 &check_param.sort_buffer_length,
397 &check_param.sort_buffer_length, 0, GET_ULL, REQUIRED_ARG,
398 SORT_BUFFER_INIT, MIN_SORT_BUFFER, SIZE_T_MAX, MALLOC_OVERHEAD, 1L, 0},
399 { "sort_key_blocks", OPT_SORT_KEY_BLOCKS,
400 "Internal buffer for sorting keys; Don't touch :)",
401 &check_param.sort_key_blocks,
402 &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
403 BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
404 { "decode_bits", OPT_DECODE_BITS, "", &decode_bits,
405 &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
406 { "ft_min_word_len", OPT_FT_MIN_WORD_LEN, "", &ft_min_word_len,
407 &ft_min_word_len, 0, GET_ULONG, REQUIRED_ARG, 4, 1, HA_FT_MAXCHARLEN,
408 0, 1, 0},
409 { "ft_max_word_len", OPT_FT_MAX_WORD_LEN, "", &ft_max_word_len,
410 &ft_max_word_len, 0, GET_ULONG, REQUIRED_ARG, HA_FT_MAXCHARLEN, 10,
411 HA_FT_MAXCHARLEN, 0, 1, 0},
412 { "aria_ft_stopword_file", OPT_FT_STOPWORD_FILE,
413 "Use stopwords from this file instead of built-in list.",
414 (char**) &ft_stopword_file, (char**) &ft_stopword_file, 0, GET_STR,
415 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
416 { "stats_method", OPT_STATS_METHOD,
417 "Specifies how index statistics collection code should treat NULLs. "
418 "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
419 "\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
420 (char**) &maria_stats_method_str, (char**) &maria_stats_method_str, 0,
421 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
422 { "zerofill", 'z',
423 "Fill empty space in data and index files with zeroes. This makes the data file movable between different servers.",
424 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
425 { "zerofill-keep-lsn", OPT_ZEROFILL_KEEP_LSN,
426 "Like --zerofill but does not zero out LSN of data/index pages;"
427 " used only for testing and debugging",
428 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
429 { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
430};
431
432
433static void print_version(void)
434{
435 printf("%s Ver 1.2 for %s on %s\n", my_progname, SYSTEM_TYPE,
436 MACHINE_TYPE);
437}
438
439
440static void usage(void)
441{
442 print_version();
443 puts("By Monty, for your professional use");
444 puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
445 puts("Description, check and repair of Aria tables.");
446 puts("Used without options all tables on the command will be checked for errors");
447 printf("Usage: %s [OPTIONS] tables[.MAI]\n", my_progname_short);
448 printf("\nGlobal options:\n");
449#ifndef DBUG_OFF
450 printf("\
451 -#, --debug=... Output debug log. Often this is 'd:t:o,filename'.\n");
452#endif
453 printf("\
454 -H, --HELP Print all argument options sorted alphabetically.\n\
455 -?, --help Print all options by groups\n\
456 --datadir=path Path for control file (and logs if --logdir not used)\n\
457 --logdir=path Path for log files\n\
458 --ignore-control-file Don't open the control file. Only use this if you\n\
459 are sure the tables are not in use by another\n\
460 program!\n\
461 --require-control-file Abort if we can't find/read the maria_log_control\n\
462 file\n\
463 -s, --silent Only print errors. One can use two -s to make\n\
464 maria_chk very silent.\n\
465 -t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
466 specified, separated by ");
467#if defined( __WIN__) || defined(__NETWARE__)
468 printf("semicolon (;)");
469#else
470 printf("colon (:)");
471#endif
472 printf(", they will be used\n\
473 in a round-robin fashion.\n\
474 -v, --verbose Print more information. This can be used with\n\
475 --description and --check. Use many -v for more verbosity.\n\
476 -V, --version Print version and exit.\n\
477 -w, --wait Wait if table is locked.\n\n");
478#ifdef DEBUG
479 puts(" --start-check-pos=# Start reading file at given offset.\n");
480#endif
481
482 puts("Check options (check is the default action for aria_chk):\n\
483 -c, --check Check table for errors.\n\
484 -e, --extend-check Check the table VERY throughly. Only use this in\n\
485 extreme cases as aria_chk should normally be able to\n\
486 find out if the table is ok even without this switch.\n\
487 -F, --fast Check only tables that haven't been closed properly.\n\
488 -C, --check-only-changed\n\
489 Check only tables that have changed since last check.\n\
490 -f, --force Restart with '-r' if there are any errors in the table.\n\
491 States will be updated as with '--update-state'.\n\
492 -i, --information Print statistics information about table that is checked.\n\
493 -m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
494 all errors. Should be good enough for most cases.\n\
495 -T, --read-only Don't mark table as checked.\n\
496 -U, --update-state Mark tables as crashed if any errors were found and\n\
497 clean if check didn't find any errors but table was\n\
498 marked as 'not clean' before. This allows one to get\n\
499 rid of warnings like 'table not properly closed'. If\n\
500 table was updated, update also the timestamp for when\n\
501 the check was made. This option is on by default!\n\
502 Use --skip-update-state to disable.\n\
503 --warning-for-wrong-transaction-id\n\
504 Give a warning if we find a transaction id in the table that is bigger\n\
505 than what exists in the control file. Use --skip-... to disable warning\n\
506 ");
507
508 puts("\
509Recover (repair)/ options (When using '--recover' or '--safe-recover'):\n\
510 -B, --backup Make a backup of the .MAD file as 'filename-time.BAK'.\n\
511 --correct-checksum Correct checksum information for table.\n\
512 -D, --data-file-length=# Max length of data file (when recreating data\n\
513 file when it's full).\n\
514 --create-missing-keys\n\
515 Create missing keys. This assumes that the data\n\
516 file is correct and that the the number of rows stored\n\
517 in the index file is correct. Enables --quick.\n\
518 -e, --extend-check Try to recover every possible row from the data file\n\
519 Normally this will also find a lot of garbage rows;\n\
520 Don't use this option if you are not totally desperate.\n\
521 -f, --force Overwrite old temporary files. Add another --force to\n\
522 avoid 'sort_buffer_size is too small' errors.\n\
523 In this case we will attempt to do the repair with the\n\
524 given sort_buffer_size and dynamically allocate\n\
525 as many management buffers as needed.\n\
526 -k, --keys-used=# Tell Aria to update only some specific keys. # is a\n\
527 bit mask of which keys to use. This can be used to\n\
528 get faster inserts.\n\
529 --max-record-length=#\n\
530 Skip rows bigger than this if aria_chk can't allocate\n\
531 memory to hold it.\n\
532 -r, --recover Can fix almost anything except unique keys that aren't\n\
533 unique.\n\
534 -n, --sort-recover Forces recovering with sorting even if the temporary\n\
535 file would be very big.\n\
536 -p, --parallel-recover\n\
537 Uses the same technique as '-r' and '-n', but creates\n\
538 all the keys in parallel, in different threads.");
539 puts("\
540 -o, --safe-recover Uses old recovery method; Slower than '-r' but can\n \
541 handle a couple of cases where '-r' reports that it\n\
542 can't fix the data file.\n\
543 --transaction-log Log repair command to transaction log. This is needed\n\
544 if one wants to use the aria_read_log to repeat the \n\
545 repair\n\
546 --character-sets-dir=...\n\
547 Directory where character sets are.\n\
548 --set-collation=name\n\
549 Change the collation used by the index.\n\
550 -q, --quick Faster repair by not modifying the data file.\n\
551 One can give a second '-q' to force aria_chk to\n\
552 modify the original datafile in case of duplicate keys.\n\
553 NOTE: Tables where the data file is currupted can't be\n\
554 fixed with this option.\n\
555 -u, --unpack Unpack file packed with ariapack.\n\
556");
557
558 puts("Other actions:\n\
559 -a, --analyze Analyze distribution of keys. Will make some joins in\n\
560 MariaDB faster. You can check the calculated distribution\n\
561 by using '--description --verbose table_name'.\n\
562 --stats_method=name Specifies how index statistics collection code should\n\
563 treat NULLs. Possible values of name are \"nulls_unequal\"\n\
564 (default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
565 \"nulls_ignored\".\n\
566 -d, --description Prints some information about table.\n\
567 -A, --set-auto-increment[=value]\n\
568 Force auto_increment to start at this or higher value\n\
569 If no value is given, then sets the next auto_increment\n\
570 value to the highest used value for the auto key + 1.\n\
571 -S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
572 applications.\n\
573 -R, --sort-records=#\n\
574 Sort records according to an index. This makes your\n\
575 data much more localized and may speed up things\n\
576 (It may be VERY slow to do a sort the first time!).\n\
577 -b, --block-search=#\n\
578 Find a record, a block at given offset belongs to.\n\
579 -z, --zerofill Fill empty space in data and index files with zeroes.\n\
580 This makes the data file movable between different \n\
581 servers.\n\
582 --zerofill-keep-lsn Like --zerofill but does not zero out LSN of\n\
583 data/index pages.");
584
585 puts("Variables:\n\
586--page_buffer_size=# Size of page buffer. Used by --safe-repair\n\
587--read_buffer_size=# Read buffer size for sequential reads during scanning\n\
588--sort_buffer_size=# Size of sort buffer. Used by --recover\n\
589--sort_key_blocks=# Internal buffer for sorting keys; Don't touch :)\n\
590--write_buffer_size=# Write buffer size for sequential writes during repair");
591
592 print_defaults("my", load_default_groups);
593 my_print_variables(my_long_options);
594}
595
596const char *maria_stats_method_names[] = {"nulls_unequal", "nulls_equal",
597 "nulls_ignored", NullS};
598TYPELIB maria_stats_method_typelib= {
599 array_elements(maria_stats_method_names) - 1, "",
600 maria_stats_method_names, NULL};
601
602 /* Read options */
603
604static my_bool
605get_one_option(int optid,
606 const struct my_option *opt __attribute__((unused)),
607 char *argument)
608{
609 switch (optid) {
610#ifdef __NETWARE__
611 case OPT_AUTO_CLOSE:
612 setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
613 break;
614#endif
615 case 'a':
616 if (argument == disabled_my_option)
617 check_param.testflag&= ~T_STATISTICS;
618 else
619 check_param.testflag|= T_STATISTICS;
620 break;
621 case 'A':
622 if (argument)
623 check_param.auto_increment_value= strtoull(argument, NULL, 0);
624 else
625 check_param.auto_increment_value= 0; /* Set to max used value */
626 check_param.testflag|= T_AUTO_INC;
627 break;
628 case 'b':
629 check_param.search_after_block= strtoul(argument, NULL, 10);
630 break;
631 case 'B':
632 if (argument == disabled_my_option)
633 check_param.testflag&= ~T_BACKUP_DATA;
634 else
635 check_param.testflag|= T_BACKUP_DATA;
636 break;
637 case 'c':
638 if (argument == disabled_my_option)
639 check_param.testflag&= ~T_CHECK;
640 else
641 check_param.testflag|= T_CHECK;
642 break;
643 case 'C':
644 if (argument == disabled_my_option)
645 check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
646 else
647 check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
648 break;
649 case 'D':
650 check_param.max_data_file_length=strtoll(argument, NULL, 10);
651 break;
652 case 's': /* silent */
653 if (argument == disabled_my_option)
654 check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
655 else
656 {
657 if (check_param.testflag & T_SILENT)
658 check_param.testflag|= T_VERY_SILENT;
659 check_param.testflag|= T_SILENT;
660 check_param.testflag&= ~T_WRITE_LOOP;
661 }
662 break;
663 case 'w':
664 if (argument == disabled_my_option)
665 check_param.testflag&= ~T_WAIT_FOREVER;
666 else
667 check_param.testflag|= T_WAIT_FOREVER;
668 break;
669 case 'd': /* description if isam-file */
670 if (argument == disabled_my_option)
671 check_param.testflag&= ~T_DESCRIPT;
672 else
673 check_param.testflag|= T_DESCRIPT;
674 break;
675 case 'e': /* extend check */
676 if (argument == disabled_my_option)
677 check_param.testflag&= ~T_EXTEND;
678 else
679 check_param.testflag|= T_EXTEND;
680 break;
681 case 'i':
682 if (argument == disabled_my_option)
683 check_param.testflag&= ~T_INFO;
684 else
685 check_param.testflag|= T_INFO;
686 break;
687 case 'f':
688 if (argument == disabled_my_option)
689 {
690 check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
691 check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE |
692 T_FORCE_SORT_MEMORY);
693 }
694 else
695 {
696 if (check_param.testflag & T_FORCE_CREATE)
697 check_param.testflag= T_FORCE_SORT_MEMORY;
698 check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
699 check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
700 }
701 break;
702 case 'F':
703 if (argument == disabled_my_option)
704 check_param.testflag&= ~T_FAST;
705 else
706 check_param.testflag|= T_FAST;
707 break;
708 case 'k':
709 check_param.keys_in_use= (ulonglong) strtoll(argument, NULL, 10);
710 break;
711 case 'm':
712 if (argument == disabled_my_option)
713 check_param.testflag&= ~T_MEDIUM;
714 else
715 check_param.testflag|= T_MEDIUM; /* Medium check */
716 break;
717 case 'r': /* Repair table */
718 check_param.testflag&= ~T_REP_ANY;
719 if (argument != disabled_my_option)
720 check_param.testflag|= T_REP_BY_SORT;
721 break;
722 case 'p':
723 check_param.testflag&= ~T_REP_ANY;
724 if (argument != disabled_my_option)
725 check_param.testflag|= T_REP_PARALLEL;
726 break;
727 case 'o':
728 check_param.testflag&= ~T_REP_ANY;
729 check_param.force_sort= 0;
730 if (argument != disabled_my_option)
731 {
732 check_param.testflag|= T_REP;
733 my_disable_async_io= 1; /* More safety */
734 }
735 break;
736 case 'n':
737 check_param.testflag&= ~T_REP_ANY;
738 if (argument == disabled_my_option)
739 check_param.force_sort= 0;
740 else
741 {
742 check_param.testflag|= T_REP_BY_SORT;
743 check_param.force_sort= 1;
744 }
745 break;
746 case 'q':
747 if (argument == disabled_my_option)
748 check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
749 else
750 {
751 /*
752 If T_QUICK was specified before, but not OPT_CREATE_MISSING_KEYS,
753 then add T_FORCE_UNIQUENESS.
754 */
755 check_param.testflag|=
756 ((check_param.testflag & (T_QUICK | T_CREATE_MISSING_KEYS)) ==
757 T_QUICK ? T_FORCE_UNIQUENESS : T_QUICK);
758 }
759 break;
760 case OPT_CREATE_MISSING_KEYS:
761 if (argument == disabled_my_option)
762 check_param.testflag&= ~(T_QUICK | T_CREATE_MISSING_KEYS);
763 else
764 {
765 check_param.testflag|= T_QUICK | T_CREATE_MISSING_KEYS;
766 /* Use repair by sort by default */
767 if (!(check_param.testflag & T_REP_ANY))
768 check_param.testflag|= T_REP_BY_SORT;
769 }
770 break;
771 case 'u':
772 if (argument == disabled_my_option)
773 check_param.testflag&= ~T_UNPACK;
774 else
775 {
776 check_param.testflag|= T_UNPACK;
777 if (!(check_param.testflag & T_REP_ANY))
778 check_param.testflag|= T_REP_BY_SORT;
779 }
780 break;
781 case 'v': /* Verbose */
782 if (argument == disabled_my_option)
783 {
784 check_param.testflag&= ~T_VERBOSE;
785 check_param.verbose=0;
786 }
787 else
788 {
789 check_param.testflag|= T_VERBOSE;
790 check_param.verbose++;
791 }
792 break;
793 case 'R': /* Sort records */
794 if (argument == disabled_my_option)
795 check_param.testflag&= ~T_SORT_RECORDS;
796 else
797 {
798 check_param.testflag|= T_SORT_RECORDS;
799 check_param.opt_sort_key= (uint) atoi(argument) - 1;
800 if (check_param.opt_sort_key >= MARIA_MAX_KEY)
801 {
802 fprintf(stderr,
803 "The value of the sort key is bigger than max key: %d.\n",
804 MARIA_MAX_KEY);
805 my_exit(1);
806 }
807 }
808 break;
809 case 'S': /* Sort index */
810 if (argument == disabled_my_option)
811 check_param.testflag&= ~T_SORT_INDEX;
812 else
813 check_param.testflag|= T_SORT_INDEX;
814 break;
815 case 'T':
816 if (argument == disabled_my_option)
817 check_param.testflag&= ~T_READONLY;
818 else
819 check_param.testflag|= T_READONLY;
820 break;
821 case 'U':
822 if (argument == disabled_my_option)
823 check_param.testflag&= ~T_UPDATE_STATE;
824 else
825 check_param.testflag|= T_UPDATE_STATE;
826 break;
827 case '#':
828 DBUG_SET_INITIAL(argument ? argument : "d:t:o,/tmp/aria_chk.trace");
829 opt_debug= 1;
830 break;
831 case 'V':
832 print_version();
833 my_exit(0);
834 case OPT_CORRECT_CHECKSUM:
835 if (argument == disabled_my_option)
836 check_param.testflag&= ~T_CALC_CHECKSUM;
837 else
838 check_param.testflag|= T_CALC_CHECKSUM;
839 break;
840 case OPT_STATS_METHOD:
841 {
842 int method;
843 enum_handler_stats_method UNINIT_VAR(method_conv);
844 maria_stats_method_str= argument;
845 if ((method=find_type(argument, &maria_stats_method_typelib, 2)) <= 0)
846 {
847 fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
848 my_exit(1);
849 }
850 switch (method-1) {
851 case 0:
852 method_conv= MI_STATS_METHOD_NULLS_EQUAL;
853 break;
854 case 1:
855 method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
856 break;
857 case 2:
858 method_conv= MI_STATS_METHOD_IGNORE_NULLS;
859 break;
860 default: abort(); /* Impossible */
861 }
862 check_param.stats_method= method_conv;
863 break;
864 }
865#ifdef DEBUG /* Only useful if debugging */
866 case OPT_START_CHECK_POS:
867 check_param.start_check_pos= strtoull(argument, NULL, 0);
868 break;
869#endif
870 case 'z':
871 if (argument == disabled_my_option)
872 check_param.testflag&= ~T_ZEROFILL;
873 else
874 check_param.testflag|= T_ZEROFILL;
875 break;
876 case OPT_ZEROFILL_KEEP_LSN:
877 if (argument == disabled_my_option)
878 check_param.testflag&= ~(T_ZEROFILL_KEEP_LSN | T_ZEROFILL);
879 else
880 check_param.testflag|= (T_ZEROFILL_KEEP_LSN | T_ZEROFILL);
881 break;
882 case 'H':
883 my_print_help(my_long_options);
884 my_print_variables(my_long_options);
885 my_exit(0);
886 case '?':
887 usage();
888 my_exit(0);
889 }
890 return 0;
891}
892
893
894static void get_options(register int *argc,register char ***argv)
895{
896 int ho_error;
897
898 load_defaults_or_exit("my", load_default_groups, argc, argv);
899 default_argv= *argv;
900 check_param.testflag= T_UPDATE_STATE;
901 if (isatty(fileno(stdout)))
902 check_param.testflag|=T_WRITE_LOOP;
903
904 if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
905 my_exit(ho_error);
906
907 /* If using repair, then update checksum if one uses --update-state */
908 if ((check_param.testflag & T_UPDATE_STATE) &&
909 (check_param.testflag & T_REP_ANY))
910 check_param.testflag|= T_CALC_CHECKSUM;
911
912 if (*argc == 0)
913 {
914 usage();
915 my_exit(-1);
916 }
917
918 if ((check_param.testflag & T_UNPACK) &&
919 (check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
920 {
921 fprintf(stderr, "%s: --unpack can't be used with --quick or --sort-records\n",
922 my_progname_short);
923 my_exit(1);
924 }
925 if ((check_param.testflag & T_READONLY) &&
926 (check_param.testflag &
927 (T_REP_ANY | T_STATISTICS | T_AUTO_INC |
928 T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
929 {
930 fprintf(stderr, "%s: Can't use --readonly when repairing or sorting\n",
931 my_progname_short);
932 my_exit(1);
933 }
934
935 if (!opt_debug)
936 {
937 DEBUGGER_OFF; /* Speed up things a bit */
938 }
939 if (init_tmpdir(&maria_chk_tmpdir, opt_tmpdir))
940 my_exit(1);
941
942 check_param.tmpdir=&maria_chk_tmpdir;
943
944 if (set_collation_name)
945 if (!(set_collation= get_charset_by_name(set_collation_name,
946 MYF(MY_WME))))
947 my_exit(1);
948
949 if (maria_data_root != default_log_dir && opt_log_dir == default_log_dir)
950 {
951 /* --datadir was used and --log-dir was not. Set log-dir to datadir */
952 opt_log_dir= maria_data_root;
953 }
954
955 /* If we are using zerofill, then we don't need to read the control file */
956 if ((check_param.testflag & (T_ZEROFILL_KEEP_LSN | T_ZEROFILL)) &&
957 !(check_param.testflag & ~(T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX | T_STATISTICS | T_CHECK | T_FAST | T_CHECK_ONLY_CHANGED)))
958 opt_ignore_control_file= 1;
959
960 return;
961} /* get options */
962
963
964/**
965 Check/repair table
966
967 @return 0 table is ok
968 @return 1 Got warning during check
969 @return 2 Got error during check/repair.
970*/
971
972static int maria_chk(HA_CHECK *param, char *filename)
973{
974 int error,lock_type,recreate;
975 uint warning_printed_by_chk_status;
976 my_bool rep_quick= MY_TEST(param->testflag & (T_QUICK | T_FORCE_UNIQUENESS));
977 MARIA_HA *info;
978 File datafile;
979 char llbuff[22],llbuff2[22];
980 my_bool state_updated=0;
981 MARIA_SHARE *share;
982 DBUG_ENTER("maria_chk");
983
984 param->out_flag=error=param->warning_printed=param->error_printed=
985 recreate=0;
986 datafile=0;
987 param->isam_file_name=filename; /* For error messages */
988 warning_printed_by_chk_status= 0;
989 if (!(info=maria_open(filename,
990 (param->testflag & (T_DESCRIPT | T_READONLY)) ?
991 O_RDONLY : O_RDWR,
992 HA_OPEN_FOR_REPAIR |
993 ((param->testflag & T_WAIT_FOREVER) ?
994 HA_OPEN_WAIT_IF_LOCKED :
995 (param->testflag & T_DESCRIPT) ?
996 HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
997 {
998 /* Avoid twice printing of isam file name */
999 param->error_printed=1;
1000 switch (my_errno) {
1001 case HA_ERR_CRASHED:
1002 _ma_check_print_error(param,"'%s' doesn't have a correct index definition. You need to recreate it before you can do a repair",filename);
1003 break;
1004 case HA_ERR_NOT_A_TABLE:
1005 _ma_check_print_error(param,"'%s' is not a Aria table",filename);
1006 break;
1007 case HA_ERR_CRASHED_ON_USAGE:
1008 _ma_check_print_error(param,"'%s' is marked as crashed",filename);
1009 break;
1010 case HA_ERR_CRASHED_ON_REPAIR:
1011 _ma_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
1012 break;
1013 case HA_ERR_OLD_FILE:
1014 _ma_check_print_error(param,"'%s' is a old type of Aria table", filename);
1015 break;
1016 case HA_ERR_NEW_FILE:
1017 _ma_check_print_error(param,"'%s' uses new features not supported by this version of the Aria library", filename);
1018 break;
1019 case HA_ERR_END_OF_FILE:
1020 _ma_check_print_error(param,"Couldn't read complete header from '%s'", filename);
1021 break;
1022 case EAGAIN:
1023 _ma_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
1024 break;
1025 case ENOENT:
1026 _ma_check_print_error(param,"File '%s' doesn't exist",filename);
1027 break;
1028 case EACCES:
1029 _ma_check_print_error(param,"You don't have permission to use '%s'",
1030 filename);
1031 break;
1032 default:
1033 _ma_check_print_error(param,"%d when opening Aria table '%s'",
1034 my_errno,filename);
1035 break;
1036 }
1037 DBUG_RETURN(1);
1038 }
1039 share= info->s;
1040 share->tot_locks-= share->r_locks;
1041 share->r_locks=0;
1042 maria_block_size= share->base.block_size;
1043
1044 if (share->data_file_type == BLOCK_RECORD ||
1045 ((param->testflag & T_UNPACK) &&
1046 share->state.header.org_data_file_type == BLOCK_RECORD))
1047 {
1048 if (param->testflag & T_SORT_RECORDS)
1049 {
1050 _ma_check_print_error(param,
1051 "Record format used by '%s' is is not yet supported with sort-records",
1052 filename);
1053 param->error_printed= 0;
1054 error= 1;
1055 goto end2;
1056 }
1057 /* We can't do parallel repair with BLOCK_RECORD yet */
1058 if (param->testflag & T_REP_PARALLEL)
1059 {
1060 param->testflag&= ~T_REP_PARALLEL;
1061 param->testflag|= T_REP_BY_SORT;
1062 }
1063 }
1064
1065 /*
1066 Skip the checking of the file if:
1067 We are using --fast and the table is closed properly
1068 We are using --check-only-changed-tables and the table hasn't changed
1069 */
1070 if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
1071 {
1072 my_bool need_to_check= (maria_is_crashed(info) ||
1073 share->state.open_count != 0);
1074
1075 if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
1076 ((share->state.changed & (STATE_CHANGED | STATE_CRASHED_FLAGS |
1077 STATE_IN_REPAIR) ||
1078 !(param->testflag & T_CHECK_ONLY_CHANGED))))
1079 need_to_check=1;
1080
1081 if (info->s->base.keys && info->state->records)
1082 {
1083 if ((param->testflag & T_STATISTICS) &&
1084 (share->state.changed & STATE_NOT_ANALYZED))
1085 need_to_check=1;
1086 if ((param->testflag & T_SORT_INDEX) &&
1087 (share->state.changed & STATE_NOT_SORTED_PAGES))
1088 need_to_check=1;
1089 if ((param->testflag & T_REP_BY_SORT) &&
1090 (share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1091 need_to_check=1;
1092 }
1093 if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
1094 (share->state.changed & (STATE_CHANGED | STATE_CRASHED_FLAGS |
1095 STATE_IN_REPAIR)))
1096 need_to_check=1;
1097 if (!need_to_check)
1098 {
1099 if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
1100 printf("Aria file: %s is already checked\n",filename);
1101 if (maria_close(info))
1102 {
1103 _ma_check_print_error(param,"%d when closing Aria table '%s'",
1104 my_errno,filename);
1105 DBUG_RETURN(1);
1106 }
1107 DBUG_RETURN(0);
1108 }
1109 }
1110 if ((param->testflag & (T_REP_ANY | T_STATISTICS |
1111 T_SORT_RECORDS | T_SORT_INDEX)) &&
1112 (((param->testflag & T_UNPACK) &&
1113 share->data_file_type == COMPRESSED_RECORD) ||
1114 mi_uint2korr(share->state.header.state_info_length) !=
1115 MARIA_STATE_INFO_SIZE ||
1116 mi_uint2korr(share->state.header.base_info_length) !=
1117 MARIA_BASE_INFO_SIZE ||
1118 maria_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
1119 ~share->state.key_map) ||
1120 maria_test_if_almost_full(info) ||
1121 info->s->state.header.file_version[3] != maria_file_magic[3] ||
1122 (set_collation &&
1123 set_collation->number != share->base.language)))
1124 {
1125 if (set_collation)
1126 param->language= set_collation->number;
1127 if (maria_recreate_table(param, &info,filename))
1128 {
1129 fprintf(stderr, "Aria table '%s' is not fixed because of errors\n",
1130 filename);
1131 return(-1);
1132 }
1133 recreate=1;
1134 if (!(param->testflag & T_REP_ANY))
1135 {
1136 param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
1137 if (!(param->testflag & T_SILENT))
1138 printf("- '%s' has old table-format. Recreating index\n",filename);
1139 rep_quick= 1;
1140 }
1141 share= info->s;
1142 share->tot_locks-= share->r_locks;
1143 share->r_locks=0;
1144 }
1145
1146 if (param->testflag & T_DESCRIPT)
1147 {
1148 param->total_files++;
1149 param->total_records+=info->state->records;
1150 param->total_deleted+=info->state->del;
1151 descript(param, info, filename);
1152 maria_close(info); /* Should always succeed */
1153 return(0);
1154 }
1155
1156 if (!stopwords_inited++)
1157 ft_init_stopwords();
1158
1159 if (!(param->testflag & T_READONLY))
1160 lock_type = F_WRLCK; /* table is changed */
1161 else
1162 lock_type= F_RDLCK;
1163 if (info->lock_type == F_RDLCK)
1164 info->lock_type=F_UNLCK; /* Read only table */
1165 if (_ma_readinfo(info,lock_type,0))
1166 {
1167 _ma_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
1168 filename,my_errno);
1169 param->error_printed=0;
1170 error= 1;
1171 goto end2;
1172 }
1173 /*
1174 _ma_readinfo() has locked the table.
1175 We mark the table as locked (without doing file locks) to be able to
1176 use functions that only works on locked tables (like row caching).
1177 */
1178 maria_lock_database(info, F_EXTRA_LCK);
1179 datafile= info->dfile.file;
1180 if (init_pagecache(maria_pagecache, (size_t) param->use_buffers, 0, 0,
1181 maria_block_size, 0, MY_WME) == 0)
1182 {
1183 _ma_check_print_error(param, "Can't initialize page cache with %lu memory",
1184 (ulong) param->use_buffers);
1185 error= 1;
1186 goto end2;
1187 }
1188
1189 if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1190 T_ZEROFILL))
1191 {
1192 /*
1193 Mark table as not transactional to avoid logging. Should not be needed,
1194 maria_repair and maria_zerofill do it already.
1195 */
1196 _ma_tmp_disable_logging_for_table(info, FALSE);
1197
1198 if (param->testflag & T_REP_ANY)
1199 {
1200 ulonglong tmp=share->state.key_map;
1201 maria_copy_keys_active(share->state.key_map, share->base.keys,
1202 param->keys_in_use);
1203 if (tmp != share->state.key_map)
1204 info->update|=HA_STATE_CHANGED;
1205
1206 if (rep_quick &&
1207 maria_chk_del(param, info, param->testflag & ~T_VERBOSE))
1208 {
1209 if (param->testflag & T_FORCE_CREATE)
1210 {
1211 rep_quick=0;
1212 _ma_check_print_info(param,"Creating new data file\n");
1213 }
1214 else
1215 {
1216 error=1;
1217 _ma_check_print_error(param,
1218 "Quick-recover aborted; Run recovery without switch 'q'");
1219 }
1220 }
1221 }
1222 if (!error)
1223 {
1224 /*
1225 Unless this was only --zerofill-keep-lsn, old REDOs are not
1226 applicable, tell the server's Recovery to ignore them; we don't
1227 know what the log's end LSN is now, so we just let the server know
1228 that it will have to find and store it.
1229 This is the only case where create_rename_lsn can be a horizon and not
1230 a LSN.
1231 If this was only --zerofill-keep-lsn, the table can be used in
1232 Recovery and especially in this scenario: do a dirty-copy-based backup
1233 (snapshot-like), --zerofill-keep-lsn on the copies to achieve better
1234 compression, compress the copies with an external tool, and after a
1235 restore, Recovery still works (because pages and state still have
1236 their correct LSNs).
1237 */
1238 if (share->base.born_transactional &&
1239 ((param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1240 T_ZEROFILL | T_ZEROFILL_KEEP_LSN)) !=
1241 (T_ZEROFILL | T_ZEROFILL_KEEP_LSN)))
1242 {
1243 share->state.create_rename_lsn= share->state.is_of_horizon=
1244 share->state.skip_redo_lsn= LSN_NEEDS_NEW_STATE_LSNS;
1245 share->state.create_trid= 0;
1246 }
1247 }
1248 if (!error && (param->testflag & T_REP_ANY))
1249 {
1250 if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
1251 (maria_is_any_key_active(share->state.key_map) ||
1252 (rep_quick && !param->keys_in_use && !recreate)) &&
1253 maria_test_if_sort_rep(info, info->state->records,
1254 info->s->state.key_map,
1255 param->force_sort))
1256 {
1257 if (param->testflag & T_REP_BY_SORT)
1258 error=maria_repair_by_sort(param,info,filename,rep_quick);
1259 else
1260 error=maria_repair_parallel(param,info,filename,rep_quick);
1261 state_updated=1;
1262 }
1263 else
1264 error=maria_repair(param, info,filename,rep_quick);
1265 }
1266 if (!error && (param->testflag & T_SORT_RECORDS))
1267 {
1268 /*
1269 The data file is nowadays reopened in the repair code so we should
1270 soon remove the following reopen-code
1271 */
1272#ifndef TO_BE_REMOVED
1273 if (param->out_flag & O_NEW_DATA)
1274 { /* Change temp file to org file */
1275 mysql_file_close(info->dfile.file, MYF(MY_WME)); /* Close new file */
1276 error|=maria_change_to_newfile(filename,MARIA_NAME_DEXT,DATA_TMP_EXT,
1277 0, MYF(0));
1278 if (_ma_open_datafile(info, info->s))
1279 error=1;
1280 param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */
1281 param->read_cache.file= info->dfile.file;
1282 }
1283#endif
1284 if (! error)
1285 {
1286 uint key;
1287 /*
1288 We can't update the index in maria_sort_records if we have a
1289 prefix compressed or fulltext index
1290 */
1291 my_bool update_index=1;
1292 for (key=0 ; key < share->base.keys; key++)
1293 if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY|HA_FULLTEXT))
1294 update_index=0;
1295
1296 error=maria_sort_records(param,info,filename,param->opt_sort_key,
1297 /* what is the following parameter for ? */
1298 (my_bool) !(param->testflag & T_REP),
1299 update_index);
1300 datafile= info->dfile.file; /* This is now locked */
1301 if (!error && !update_index)
1302 {
1303 if (param->verbose)
1304 puts("Table had a compressed index; We must now recreate the index");
1305 error=maria_repair_by_sort(param,info,filename,1);
1306 }
1307 }
1308 }
1309 if (!error && (param->testflag & T_SORT_INDEX))
1310 error= maria_sort_index(param,info,filename);
1311 if (!error && (param->testflag & T_ZEROFILL))
1312 error= maria_zerofill(param, info, filename);
1313 if (!error)
1314 {
1315 DBUG_PRINT("info", ("Reseting crashed state"));
1316 share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED_FLAGS |
1317 STATE_IN_REPAIR);
1318 }
1319 else
1320 maria_mark_crashed(info);
1321 }
1322 else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
1323 {
1324 if (!(param->testflag & T_VERY_SILENT) || param->testflag & T_INFO)
1325 printf("Checking Aria file: %s\n",filename);
1326 if (!(param->testflag & T_SILENT))
1327 printf("Data records: %7s Deleted blocks: %7s\n",
1328 llstr(info->state->records,llbuff),
1329 llstr(info->state->del,llbuff2));
1330 maria_chk_init_for_check(param, info);
1331 if (opt_warning_for_wrong_transid == 0)
1332 param->max_trid= ~ (ulonglong) 0;
1333
1334 error= maria_chk_status(param,info);
1335 /* Forget warning printed by maria_chk_status if no problems found */
1336 warning_printed_by_chk_status= param->warning_printed;
1337 param->warning_printed= 0;
1338
1339 maria_intersect_keys_active(share->state.key_map, param->keys_in_use);
1340 error|= maria_chk_size(param,info);
1341 if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1342 error|=maria_chk_del(param, info,param->testflag);
1343 if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
1344 !param->start_check_pos)))
1345 {
1346 error|=maria_chk_key(param, info);
1347 if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
1348 error=maria_update_state_info(param, info,
1349 ((param->testflag & T_STATISTICS) ?
1350 UPDATE_STAT : 0) |
1351 ((param->testflag & T_AUTO_INC) ?
1352 UPDATE_AUTO_INC : 0));
1353 }
1354 if ((!rep_quick && !error) ||
1355 !(param->testflag & (T_FAST | T_FORCE_CREATE)))
1356 {
1357 init_io_cache(&param->read_cache,datafile,
1358 (uint) param->read_buffer_length,
1359 READ_CACHE,
1360 (param->start_check_pos ?
1361 param->start_check_pos :
1362 share->pack.header_length),
1363 1,
1364 MYF(MY_WME));
1365 maria_lock_memory(param);
1366 if ((info->s->data_file_type != STATIC_RECORD) ||
1367 (param->testflag & (T_EXTEND | T_MEDIUM)))
1368 error|=maria_chk_data_link(param, info,
1369 MY_TEST(param->testflag & T_EXTEND));
1370 end_io_cache(&param->read_cache);
1371 }
1372 if (!error)
1373 {
1374 if (((share->state.changed &
1375 (STATE_CHANGED | STATE_CRASHED_FLAGS | STATE_IN_REPAIR)) ||
1376 share->state.open_count != 0)
1377 && (param->testflag & T_UPDATE_STATE))
1378 info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1379 DBUG_PRINT("info", ("Reseting crashed state"));
1380 share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED_FLAGS |
1381 STATE_IN_REPAIR);
1382 }
1383 else if (!maria_is_crashed(info) &&
1384 (param->testflag & T_UPDATE_STATE))
1385 { /* Mark crashed */
1386 maria_mark_crashed(info);
1387 info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1388 }
1389 }
1390
1391 if ((param->testflag & T_AUTO_INC) ||
1392 ((param->testflag & T_REP_ANY) && info->s->base.auto_key))
1393 _ma_update_auto_increment_key(param, info,
1394 (my_bool)
1395 !MY_TEST(param->testflag & T_AUTO_INC));
1396
1397 if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
1398 {
1399 error|=maria_update_state_info(param, info,
1400 UPDATE_OPEN_COUNT |
1401 (((param->testflag &
1402 (T_REP_ANY | T_UPDATE_STATE)) ?
1403 UPDATE_TIME : 0) |
1404 (state_updated ? UPDATE_STAT : 0) |
1405 ((param->testflag & T_SORT_RECORDS) ?
1406 UPDATE_SORT : 0)));
1407 if (warning_printed_by_chk_status)
1408 _ma_check_print_info(param, "Aria table '%s' was ok. Status updated",
1409 filename);
1410 else if (!(param->testflag & T_SILENT))
1411 printf("State updated\n");
1412 warning_printed_by_chk_status= 0;
1413 }
1414 info->update&= ~HA_STATE_CHANGED;
1415 _ma_reenable_logging_for_table(info, FALSE);
1416 maria_lock_database(info, F_UNLCK);
1417
1418end2:
1419 if (maria_close(info))
1420 {
1421 _ma_check_print_error(param, default_close_errmsg, my_errno, filename);
1422 DBUG_RETURN(1);
1423 }
1424 end_pagecache(maria_pagecache, 1);
1425 if (error == 0)
1426 {
1427 if (param->out_flag & O_NEW_DATA)
1428 error|=maria_change_to_newfile(filename,MARIA_NAME_DEXT,DATA_TMP_EXT,
1429 param->backup_time,
1430 ((param->testflag & T_BACKUP_DATA) ?
1431 MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
1432 }
1433 if (opt_transaction_logging &&
1434 share->base.born_transactional && !error &&
1435 (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1436 T_ZEROFILL)))
1437 error= write_log_record(param);
1438
1439 if (param->not_visible_rows_found && (param->testflag & T_VERBOSE))
1440 {
1441 char buff[22];
1442 printf("Max transaction id found: %s\n",
1443 llstr(param->max_found_trid, buff));
1444 }
1445
1446 fflush(stdout);
1447 fflush(stderr);
1448
1449 if (param->error_printed)
1450 {
1451 error= 2;
1452 if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
1453 {
1454 fprintf(stderr, "Aria table '%s' is not fixed because of errors\n",
1455 filename);
1456 if (param->testflag & T_REP_ANY)
1457 fprintf(stderr, "Try fixing it by using the --safe-recover (-o), "
1458 "the --force (-f) option or by not using the --quick (-q) "
1459 "flag\n");
1460 }
1461 else if (!(param->error_printed & 2) &&
1462 !(param->testflag & T_FORCE_CREATE))
1463 fprintf(stderr, "Aria table '%s' is corrupted\nFix it using switch "
1464 "\"-r\" or \"-o\"\n", filename);
1465 }
1466 else if ((param->warning_printed || warning_printed_by_chk_status) &&
1467 ! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
1468 T_FORCE_CREATE)))
1469 {
1470 if (!error)
1471 error= 1;
1472 (void) fprintf(stderr, "Aria table '%s' is usable but should be fixed\n",
1473 filename);
1474 }
1475
1476 (void) fflush(stderr);
1477 DBUG_RETURN(error);
1478} /* maria_chk */
1479
1480
1481/* Write info about table */
1482
1483static void descript(HA_CHECK *param, register MARIA_HA *info, char *name)
1484{
1485 uint key,keyseg_nr,field;
1486 reg3 MARIA_KEYDEF *keyinfo;
1487 reg2 HA_KEYSEG *keyseg;
1488 reg4 const char *text;
1489 char buff[200],length[10],*pos,*end;
1490 enum en_fieldtype type;
1491 MARIA_SHARE *share= info->s;
1492 char llbuff[22],llbuff2[22];
1493 DBUG_ENTER("descript");
1494
1495 if (param->testflag & T_VERY_SILENT)
1496 {
1497 longlong checksum= info->state->checksum;
1498 if (!(share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
1499 checksum= 0;
1500 printf("%s %s %s\n", name, llstr(info->state->records,llbuff),
1501 llstr(checksum, llbuff2));
1502 DBUG_VOID_RETURN;
1503 }
1504
1505 printf("Aria file: %s\n",name);
1506 printf("Record format: %s\n", record_formats[share->data_file_type]);
1507 printf("Crashsafe: %s\n",
1508 share->base.born_transactional ? "yes" : "no");
1509 printf("Character set: %s (%d)\n",
1510 get_charset_name(share->base.language),
1511 (int) share->base.language);
1512
1513 if (param->testflag & T_VERBOSE)
1514 {
1515 printf("File-version: %d\n",
1516 (int) share->state.header.file_version[3]);
1517 if (share->state.create_time)
1518 {
1519 get_date(buff,1,share->state.create_time);
1520 printf("Creation time: %s\n",buff);
1521 }
1522 if (share->state.check_time)
1523 {
1524 get_date(buff,1,share->state.check_time);
1525 printf("Check/recover time: %s\n",buff);
1526 }
1527 if (share->base.born_transactional)
1528 {
1529 printf("LSNs: create_rename " LSN_FMT ","
1530 " state_horizon " LSN_FMT ", skip_redo " LSN_FMT "\n",
1531 LSN_IN_PARTS(share->state.create_rename_lsn),
1532 LSN_IN_PARTS(share->state.is_of_horizon),
1533 LSN_IN_PARTS(share->state.skip_redo_lsn));
1534 printf("create_trid: %s\n",
1535 llstr(share->state.create_trid, llbuff));
1536 }
1537 compile_time_assert((MY_UUID_STRING_LENGTH + 1) <= sizeof(buff));
1538 buff[MY_UUID_STRING_LENGTH]= 0;
1539 my_uuid2str(share->base.uuid, buff);
1540 printf("UUID: %s\n", buff);
1541 pos=buff;
1542 if (share->state.changed & STATE_CRASHED)
1543 strmov(buff, share->state.changed & STATE_CRASHED_ON_REPAIR ?
1544 "crashed on repair" : "crashed");
1545 else
1546 {
1547 if (share->state.open_count)
1548 pos=strmov(pos,"open,");
1549 if (share->state.changed & STATE_CHANGED)
1550 pos=strmov(pos,"changed,");
1551 else
1552 pos=strmov(pos,"checked,");
1553 if (!(share->state.changed & STATE_NOT_ANALYZED))
1554 pos=strmov(pos,"analyzed,");
1555 if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
1556 pos=strmov(pos,"optimized keys,");
1557 if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
1558 pos=strmov(pos,"sorted index pages,");
1559 if (!(share->state.changed & STATE_NOT_ZEROFILLED))
1560 pos=strmov(pos,"zerofilled,");
1561 if (!(share->state.changed & STATE_NOT_MOVABLE))
1562 pos=strmov(pos,"movable,");
1563 pos[-1]=0; /* Remove extra ',' */
1564 }
1565 printf("Status: %s\n",buff);
1566 if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
1567 printf("Checksum: %26s\n",llstr(info->state->checksum,llbuff));
1568;
1569 if (share->options & HA_OPTION_DELAY_KEY_WRITE)
1570 printf("Keys are only flushed at close\n");
1571
1572 if (share->options & HA_OPTION_PAGE_CHECKSUM)
1573 printf("Page checksums are used\n");
1574 if (share->base.auto_key)
1575 {
1576 printf("Auto increment key: %16d Last value: %18s\n",
1577 share->base.auto_key,
1578 llstr(share->state.auto_increment,llbuff));
1579 }
1580 }
1581 printf("Data records: %16s Deleted blocks: %18s\n",
1582 llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
1583 if (param->testflag & T_SILENT)
1584 DBUG_VOID_RETURN; /* This is enough */
1585
1586 if (param->testflag & T_VERBOSE)
1587 {
1588#ifdef USE_RELOC
1589 printf("Init-relocation: %16s\n",llstr(share->base.reloc,llbuff));
1590#endif
1591 printf("Datafile parts: %16s Deleted data: %18s\n",
1592 llstr(share->state.split,llbuff),
1593 llstr(info->state->empty,llbuff2));
1594 printf("Datafile pointer (bytes): %11d Keyfile pointer (bytes): %13d\n",
1595 share->rec_reflength,share->base.key_reflength);
1596 printf("Datafile length: %16s Keyfile length: %18s\n",
1597 llstr(info->state->data_file_length,llbuff),
1598 llstr(info->state->key_file_length,llbuff2));
1599
1600 if (info->s->base.reloc == 1L && info->s->base.records == 1L)
1601 puts("This is a one-record table");
1602 else
1603 {
1604 if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
1605 share->base.max_key_file_length != HA_OFFSET_ERROR)
1606 printf("Max datafile length: %16s Max keyfile length: %18s\n",
1607 ullstr(share->base.max_data_file_length,llbuff),
1608 ullstr(share->base.max_key_file_length,llbuff2));
1609 }
1610 }
1611 printf("Block_size: %16d\n",(int) share->block_size);
1612 printf("Recordlength: %16d\n",(int) share->base.pack_reclength);
1613 if (! maria_is_all_keys_active(share->state.key_map, share->base.keys))
1614 {
1615 longlong2str(share->state.key_map,buff,2);
1616 printf("Using only keys '%s' of %d possibly keys\n",
1617 buff, share->base.keys);
1618 }
1619 puts("\nTable description:");
1620 printf("Key Start Len Index Type");
1621 if (param->testflag & T_VERBOSE)
1622 printf(" Rec/key Root Blocksize");
1623 putchar('\n');
1624
1625 for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
1626 key < share->base.keys;
1627 key++,keyinfo++)
1628 {
1629 keyseg=keyinfo->seg;
1630 if (keyinfo->flag & HA_NOSAME) text="unique ";
1631 else if (keyinfo->flag & HA_FULLTEXT) text="fulltext ";
1632 else text="multip.";
1633
1634 pos=buff;
1635 if (keyseg->flag & HA_REVERSE_SORT)
1636 *pos++ = '-';
1637 pos=strmov(pos,type_names[keyseg->type]);
1638 *pos++ = ' ';
1639 *pos=0;
1640 if (keyinfo->flag & HA_PACK_KEY)
1641 pos=strmov(pos,prefix_packed_txt);
1642 if (keyinfo->flag & HA_BINARY_PACK_KEY)
1643 pos=strmov(pos,bin_packed_txt);
1644 if (keyseg->flag & HA_SPACE_PACK)
1645 pos=strmov(pos,diff_txt);
1646 if (keyseg->flag & HA_BLOB_PART)
1647 pos=strmov(pos,blob_txt);
1648 if (keyseg->flag & HA_NULL_PART)
1649 pos=strmov(pos,null_txt);
1650 *pos=0;
1651
1652 printf("%-4d%-6ld%-3d %-8s%-23s",
1653 key+1,(long) keyseg->start+1,keyseg->length,text,buff);
1654 if (share->state.key_root[key] != HA_OFFSET_ERROR)
1655 llstr(share->state.key_root[key],buff);
1656 else
1657 buff[0]=0;
1658 if (param->testflag & T_VERBOSE)
1659 printf("%9.0f %12s %10d",
1660 share->state.rec_per_key_part[keyseg_nr++],
1661 buff,keyinfo->block_length);
1662 putchar('\n');
1663 while ((++keyseg)->type != HA_KEYTYPE_END)
1664 {
1665 pos=buff;
1666 if (keyseg->flag & HA_REVERSE_SORT)
1667 *pos++ = '-';
1668 pos=strmov(pos,type_names[keyseg->type]);
1669 *pos++= ' ';
1670 if (keyseg->flag & HA_SPACE_PACK)
1671 pos=strmov(pos,diff_txt);
1672 if (keyseg->flag & HA_BLOB_PART)
1673 pos=strmov(pos,blob_txt);
1674 if (keyseg->flag & HA_NULL_PART)
1675 pos=strmov(pos,null_txt);
1676 *pos=0;
1677 printf(" %-6ld%-3d %-21s",
1678 (long) keyseg->start+1,keyseg->length,buff);
1679 if (param->testflag & T_VERBOSE)
1680 printf("%11.0f", share->state.rec_per_key_part[keyseg_nr++]);
1681 putchar('\n');
1682 }
1683 keyseg++;
1684 }
1685 if (share->state.header.uniques)
1686 {
1687 MARIA_UNIQUEDEF *uniqueinfo;
1688 puts("\nUnique Key Start Len Nullpos Nullbit Type");
1689 for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
1690 key < share->state.header.uniques; key++, uniqueinfo++)
1691 {
1692 my_bool new_row=0;
1693 char null_bit[8],null_pos[8];
1694 printf("%-8d%-5d",key+1,uniqueinfo->key+1);
1695 for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
1696 {
1697 if (new_row)
1698 fputs(" ",stdout);
1699 null_bit[0]=null_pos[0]=0;
1700 if (keyseg->null_bit)
1701 {
1702 sprintf(null_bit,"%d",keyseg->null_bit);
1703 sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
1704 }
1705 printf("%-7ld%-5d%-9s%-10s%-30s\n",
1706 (long) keyseg->start+1,keyseg->length,
1707 null_pos,null_bit,
1708 type_names[keyseg->type]);
1709 new_row=1;
1710 }
1711 }
1712 }
1713 if (param->verbose > 1)
1714 {
1715 char null_bit[8],null_pos[8];
1716 printf("\nField Start Length Nullpos Nullbit Type");
1717 if (share->options & HA_OPTION_COMPRESS_RECORD)
1718 printf(" Huff tree Bits");
1719 putchar('\n');
1720
1721 for (field=0 ; field < share->base.fields ; field++)
1722 {
1723 if (share->options & HA_OPTION_COMPRESS_RECORD)
1724 type=share->columndef[field].base_type;
1725 else
1726 type=(enum en_fieldtype) share->columndef[field].type;
1727 end=strmov(buff,field_pack[type]);
1728 if (share->options & HA_OPTION_COMPRESS_RECORD)
1729 {
1730 if (share->columndef[field].pack_type & PACK_TYPE_SELECTED)
1731 end=strmov(end,", not_always");
1732 if (share->columndef[field].pack_type & PACK_TYPE_SPACE_FIELDS)
1733 end=strmov(end,", no empty");
1734 if (share->columndef[field].pack_type & PACK_TYPE_ZERO_FILL)
1735 {
1736 sprintf(end,", zerofill(%d)",share->columndef[field].space_length_bits);
1737 end=strend(end);
1738 }
1739 }
1740 if (buff[0] == ',')
1741 strmov(buff,buff+2);
1742 int10_to_str((long) share->columndef[field].length,length,10);
1743 null_bit[0]=null_pos[0]=0;
1744 if (share->columndef[field].null_bit)
1745 {
1746 sprintf(null_bit,"%d",share->columndef[field].null_bit);
1747 sprintf(null_pos,"%d",share->columndef[field].null_pos+1);
1748 }
1749 printf("%-6d%-6u%-7s%-8s%-8s%-35s",field+1,
1750 (uint) share->columndef[field].offset+1,
1751 length, null_pos, null_bit, buff);
1752 if (share->options & HA_OPTION_COMPRESS_RECORD)
1753 {
1754 if (share->columndef[field].huff_tree)
1755 printf("%3d %2d",
1756 (uint) (share->columndef[field].huff_tree-share->decode_trees)+1,
1757 share->columndef[field].huff_tree->quick_table_bits);
1758 }
1759 putchar('\n');
1760 }
1761 if (share->data_file_type == BLOCK_RECORD)
1762 {
1763 uint i;
1764 puts("\nBitmap Data size Description");
1765 for (i=0 ; i <= 7 ; i++)
1766 printf("%u %5u %s\n", i, share->bitmap.sizes[i],
1767 bitmap_description[i]);
1768 }
1769 }
1770 DBUG_VOID_RETURN;
1771} /* describe */
1772
1773
1774 /* Sort records according to one key */
1775
1776static int maria_sort_records(HA_CHECK *param,
1777 register MARIA_HA *info, char *name,
1778 uint sort_key,
1779 my_bool write_info,
1780 my_bool update_index)
1781{
1782 int got_error;
1783 uint key;
1784 MARIA_KEYDEF *keyinfo;
1785 File new_file;
1786 uchar *temp_buff;
1787 ha_rows old_record_count;
1788 MARIA_SHARE *share= info->s;
1789 char llbuff[22],llbuff2[22];
1790 MARIA_SORT_INFO sort_info;
1791 MARIA_SORT_PARAM sort_param;
1792 MARIA_PAGE page;
1793 DBUG_ENTER("sort_records");
1794
1795 bzero((char*)&sort_info,sizeof(sort_info));
1796 bzero((char*)&sort_param,sizeof(sort_param));
1797 sort_param.sort_info=&sort_info;
1798 sort_info.param=param;
1799 keyinfo= &share->keyinfo[sort_key];
1800 got_error=1;
1801 temp_buff=0;
1802 new_file= -1;
1803
1804 if (! maria_is_key_active(share->state.key_map, sort_key))
1805 {
1806 _ma_check_print_warning(param,
1807 "Can't sort table '%s' on key %d; No such key",
1808 name,sort_key+1);
1809 param->error_printed=0;
1810 DBUG_RETURN(0); /* Nothing to do */
1811 }
1812 if (keyinfo->flag & HA_FULLTEXT)
1813 {
1814 _ma_check_print_warning(param,"Can't sort table '%s' on FULLTEXT key %d",
1815 name,sort_key+1);
1816 param->error_printed=0;
1817 DBUG_RETURN(0); /* Nothing to do */
1818 }
1819 if (keyinfo->flag & HA_BINARY_PACK_KEY)
1820 {
1821 _ma_check_print_warning(param,
1822 "Can't sort table '%s' on a key with prefix "
1823 "packing %d",
1824 name,sort_key+1);
1825 param->error_printed=0;
1826 DBUG_RETURN(0);
1827 }
1828
1829
1830 if (share->data_file_type == COMPRESSED_RECORD)
1831 {
1832 _ma_check_print_warning(param,"Can't sort read-only table '%s'", name);
1833 param->error_printed=0;
1834 DBUG_RETURN(0); /* Nothing to do */
1835 }
1836 if (!(param->testflag & T_SILENT))
1837 {
1838 printf("- Sorting records for Aria table '%s'\n",name);
1839 if (write_info)
1840 printf("Data records: %9s Deleted: %9s\n",
1841 llstr(info->state->records,llbuff),
1842 llstr(info->state->del,llbuff2));
1843 }
1844 if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
1845 DBUG_RETURN(0); /* Nothing to do */
1846
1847 if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
1848 WRITE_CACHE,share->pack.header_length,1,
1849 MYF(MY_WME | MY_WAIT_IF_FULL)))
1850 goto err;
1851 info->opt_flag|=WRITE_CACHE_USED;
1852
1853 if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
1854 {
1855 _ma_check_print_error(param,"Not enough memory for key block");
1856 goto err;
1857 }
1858
1859 if (!(sort_param.record=
1860 (uchar*) my_malloc((uint) share->base.default_rec_buff_size, MYF(0))))
1861 {
1862 _ma_check_print_error(param,"Not enough memory for record");
1863 goto err;
1864 }
1865
1866 fn_format(param->temp_filename,name,"", MARIA_NAME_DEXT,2+4+32);
1867 new_file= mysql_file_create(key_file_tmp,
1868 fn_format(param->temp_filename,
1869 param->temp_filename, "",
1870 DATA_TMP_EXT,
1871 MY_REPLACE_EXT | MY_UNPACK_FILENAME),
1872 0, param->tmpfile_createflag, MYF(0));
1873 if (new_file < 0)
1874 {
1875 _ma_check_print_error(param,"Can't create new tempfile: '%s'",
1876 param->temp_filename);
1877 goto err;
1878 }
1879 if (share->pack.header_length)
1880 if (maria_filecopy(param, new_file, info->dfile.file, 0L,
1881 share->pack.header_length,
1882 "datafile-header"))
1883 goto err;
1884 info->rec_cache.file=new_file; /* Use this file for cacheing*/
1885
1886 maria_lock_memory(param);
1887 for (key=0 ; key < share->base.keys ; key++)
1888 share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
1889
1890 if (mysql_file_pread(share->kfile.file, temp_buff,
1891 (uint) keyinfo->block_length,
1892 share->state.key_root[sort_key],
1893 MYF(MY_NABP+MY_WME)))
1894 {
1895 _ma_check_print_error(param, "Can't read indexpage from filepos: %s",
1896 llstr(share->state.key_root[sort_key], llbuff));
1897 goto err;
1898 }
1899
1900 /* Setup param for _ma_sort_write_record */
1901 sort_info.info=info;
1902 sort_info.new_data_file_type=share->data_file_type;
1903 sort_param.fix_datafile=1;
1904 sort_param.master=1;
1905 sort_param.filepos=share->pack.header_length;
1906 old_record_count=info->state->records;
1907 info->state->records=0;
1908 if (sort_info.new_data_file_type != COMPRESSED_RECORD)
1909 info->state->checksum=0;
1910
1911 _ma_page_setup(&page, info, keyinfo, share->state.key_root[sort_key],
1912 temp_buff);
1913 if (sort_record_index(&sort_param, &page, sort_key,new_file,update_index) ||
1914 maria_write_data_suffix(&sort_info,1) ||
1915 flush_io_cache(&info->rec_cache))
1916 goto err;
1917
1918 if (info->state->records != old_record_count)
1919 {
1920 _ma_check_print_error(param,"found %s of %s records",
1921 llstr(info->state->records,llbuff),
1922 llstr(old_record_count,llbuff2));
1923 goto err;
1924 }
1925
1926 mysql_file_close(info->dfile.file, MYF(MY_WME));
1927 param->out_flag|=O_NEW_DATA; /* Data in new file */
1928 info->dfile.file= new_file; /* Use new datafile */
1929 _ma_set_data_pagecache_callbacks(&info->dfile, info->s);
1930
1931 info->state->del=0;
1932 info->state->empty=0;
1933 share->state.dellink= HA_OFFSET_ERROR;
1934 info->state->data_file_length=sort_param.filepos;
1935 share->state.split=info->state->records; /* Only hole records */
1936 share->state.version=(ulong) time((time_t*) 0);
1937
1938 info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
1939
1940 if (param->testflag & T_WRITE_LOOP)
1941 {
1942 fputs(" \r",stdout);
1943 fflush(stdout);
1944 }
1945 got_error=0;
1946
1947err:
1948 if (got_error && new_file >= 0)
1949 {
1950 end_io_cache(&info->rec_cache);
1951 (void) mysql_file_close(new_file,MYF(MY_WME));
1952 (void) mysql_file_delete(key_file_tmp, param->temp_filename, MYF(MY_WME));
1953 }
1954 if (temp_buff)
1955 {
1956 my_afree(temp_buff);
1957 }
1958 my_free(sort_param.record);
1959 info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
1960 end_io_cache(&info->rec_cache);
1961 my_free(sort_info.buff);
1962 sort_info.buff=0;
1963 share->state.sortkey=sort_key;
1964 DBUG_RETURN(got_error);
1965} /* sort_records */
1966
1967
1968/* Sort records recursive using one index */
1969
1970static int sort_record_index(MARIA_SORT_PARAM *sort_param,
1971 MARIA_PAGE *ma_page, uint sort_key,
1972 File new_file,my_bool update_index)
1973{
1974 MARIA_HA *info= ma_page->info;
1975 MARIA_SHARE *share= info->s;
1976 uint page_flag, nod_flag,used_length;
1977 uchar *temp_buff,*keypos,*endpos;
1978 my_off_t next_page,rec_pos;
1979 uchar lastkey[MARIA_MAX_KEY_BUFF];
1980 char llbuff[22];
1981 MARIA_SORT_INFO *sort_info= sort_param->sort_info;
1982 HA_CHECK *param=sort_info->param;
1983 MARIA_KEY tmp_key;
1984 MARIA_PAGE new_page;
1985 const MARIA_KEYDEF *keyinfo= ma_page->keyinfo;
1986 DBUG_ENTER("sort_record_index");
1987
1988 page_flag= ma_page->flag;
1989 nod_flag= ma_page->node;
1990 temp_buff=0;
1991 tmp_key.keyinfo= (MARIA_KEYDEF*) keyinfo;
1992 tmp_key.data= lastkey;
1993
1994 if (nod_flag)
1995 {
1996 if (!(temp_buff= (uchar*) my_alloca(tmp_key.keyinfo->block_length)))
1997 {
1998 _ma_check_print_error(param,"Not Enough memory");
1999 DBUG_RETURN(-1);
2000 }
2001 }
2002 used_length= ma_page->size;
2003 keypos= ma_page->buff + share->keypage_header + nod_flag;
2004 endpos= ma_page->buff + used_length;
2005 for ( ;; )
2006 {
2007 if (nod_flag)
2008 {
2009 next_page= _ma_kpos(nod_flag, keypos);
2010 if (mysql_file_pread(share->kfile.file, temp_buff,
2011 (uint) tmp_key.keyinfo->block_length, next_page,
2012 MYF(MY_NABP+MY_WME)))
2013 {
2014 _ma_check_print_error(param,"Can't read keys from filepos: %s",
2015 llstr(next_page,llbuff));
2016 goto err;
2017 }
2018 _ma_page_setup(&new_page, info, ma_page->keyinfo, next_page, temp_buff);
2019
2020 if (sort_record_index(sort_param, &new_page, sort_key,
2021 new_file, update_index))
2022 goto err;
2023 }
2024 if (keypos >= endpos ||
2025 !(*keyinfo->get_key)(&tmp_key, page_flag, nod_flag, &keypos))
2026 break;
2027 rec_pos= _ma_row_pos_from_key(&tmp_key);
2028
2029 if ((*share->read_record)(info,sort_param->record,rec_pos))
2030 {
2031 _ma_check_print_error(param,"%d when reading datafile",my_errno);
2032 goto err;
2033 }
2034 if (rec_pos != sort_param->filepos && update_index)
2035 {
2036 _ma_dpointer(share, keypos - nod_flag - tmp_key.ref_length,
2037 sort_param->filepos);
2038 if (maria_movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
2039 sort_key))
2040 {
2041 _ma_check_print_error(param,"%d when updating key-pointers",my_errno);
2042 goto err;
2043 }
2044 }
2045 if (_ma_sort_write_record(sort_param))
2046 goto err;
2047 }
2048 /* Clear end of block to get better compression if the table is backuped */
2049 bzero(ma_page->buff + used_length, keyinfo->block_length - used_length);
2050 if (my_pwrite(share->kfile.file, ma_page->buff, (uint)keyinfo->block_length,
2051 ma_page->pos, param->myf_rw))
2052 {
2053 _ma_check_print_error(param,"%d when updating keyblock",my_errno);
2054 goto err;
2055 }
2056 if (temp_buff)
2057 my_afree(temp_buff);
2058 DBUG_RETURN(0);
2059err:
2060 if (temp_buff)
2061 my_afree(temp_buff);
2062 DBUG_RETURN(1);
2063} /* sort_record_index */
2064
2065
2066static my_bool write_log_record(HA_CHECK *param)
2067{
2068 /*
2069 Now that all operations including O_NEW_DATA|INDEX are successfully
2070 done, we can write a log record.
2071 */
2072 MARIA_HA *info= maria_open(param->isam_file_name, O_RDWR, 0);
2073 if (info == NULL)
2074 _ma_check_print_error(param, default_open_errmsg, my_errno,
2075 param->isam_file_name);
2076 else
2077 {
2078 if (write_log_record_for_repair(param, info))
2079 _ma_check_print_error(param, "%d when writing log record for"
2080 " Aria table '%s'", my_errno,
2081 param->isam_file_name);
2082 else if (maria_close(info))
2083 _ma_check_print_error(param, default_close_errmsg, my_errno,
2084 param->isam_file_name);
2085 else
2086 return FALSE;
2087 }
2088 return TRUE;
2089}
2090
2091#include "ma_check_standalone.h"
2092