myisamchk.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:61k
- /* Copyright (C) 2000-2003 MySQL AB
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
- /* Describe, check and repair of MyISAM tables */
- #include "fulltext.h"
- #include <m_ctype.h>
- #include <stdarg.h>
- #include <my_getopt.h>
- #ifdef HAVE_SYS_VADVICE_H
- #include <sys/vadvise.h>
- #endif
- #ifdef HAVE_SYS_MMAN_H
- #include <sys/mman.h>
- #endif
- SET_STACK_SIZE(9000) /* Minimum stack size for program */
- #ifndef USE_RAID
- #define my_raid_create(A,B,C,D,E,F,G) my_create(A,B,C,G)
- #define my_raid_delete(A,B,C) my_delete(A,B)
- #endif
- #ifdef OS2
- #define _sanity(a,b)
- #endif
- static uint decode_bits;
- static char **default_argv;
- static const char *load_default_groups[]= { "myisamchk", 0 };
- static const char *set_collation_name, *opt_tmpdir;
- static CHARSET_INFO *set_collation;
- static long opt_myisam_block_size;
- static long opt_key_cache_block_size;
- static const char *my_progname_short;
- static int stopwords_inited= 0;
- static MY_TMPDIR myisamchk_tmpdir;
- static const char *type_names[]=
- { "?","char","binary", "short", "long", "float",
- "double","number","unsigned short",
- "unsigned long","longlong","ulonglong","int24",
- "uint24","int8","varchar", "varbin","?",
- "?"};
- static const char *prefix_packed_txt="packed ",
- *bin_packed_txt="prefix ",
- *diff_txt="stripped ",
- *null_txt="NULL",
- *blob_txt="BLOB ";
- static const char *field_pack[]=
- {"","no endspace", "no prespace",
- "no zeros", "blob", "constant", "table-lockup",
- "always zero","varchar","unique-hash","?","?"};
- static const char *myisam_stats_method_str="nulls_unequal";
- static void get_options(int *argc,char * * *argv);
- static void print_version(void);
- static void usage(void);
- static int myisamchk(MI_CHECK *param, char *filename);
- static void descript(MI_CHECK *param, register MI_INFO *info, my_string name);
- static int mi_sort_records(MI_CHECK *param, register MI_INFO *info,
- my_string name, uint sort_key,
- my_bool write_info, my_bool update_index);
- static int sort_record_index(MI_SORT_PARAM *sort_param, MI_INFO *info,
- MI_KEYDEF *keyinfo,
- my_off_t page,uchar *buff,uint sortkey,
- File new_file, my_bool update_index);
- MI_CHECK check_param;
- /* Main program */
- int main(int argc, char **argv)
- {
- int error;
- MY_INIT(argv[0]);
- my_progname_short= my_progname+dirname_length(my_progname);
- #ifdef __EMX__
- _wildcard (&argc, &argv);
- #endif
- myisamchk_init(&check_param);
- check_param.opt_lock_memory=1; /* Lock memory if possible */
- check_param.using_global_keycache = 0;
- get_options(&argc,(char***) &argv);
- myisam_quick_table_bits=decode_bits;
- error=0;
- while (--argc >= 0)
- {
- int new_error=myisamchk(&check_param, *(argv++));
- if ((check_param.testflag & T_REP_ANY) != T_REP)
- check_param.testflag&= ~T_REP;
- VOID(fflush(stdout));
- VOID(fflush(stderr));
- if ((check_param.error_printed | check_param.warning_printed) &&
- (check_param.testflag & T_FORCE_CREATE) &&
- (!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
- T_SORT_INDEX))))
- {
- uint old_testflag=check_param.testflag;
- if (!(check_param.testflag & T_REP))
- check_param.testflag|= T_REP_BY_SORT;
- check_param.testflag&= ~T_EXTEND; /* Don't needed */
- error|=myisamchk(&check_param, argv[-1]);
- check_param.testflag= old_testflag;
- VOID(fflush(stdout));
- VOID(fflush(stderr));
- }
- else
- error|=new_error;
- if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
- {
- puts("n---------n");
- VOID(fflush(stdout));
- }
- }
- if (check_param.total_files > 1)
- { /* Only if descript */
- char buff[22],buff2[22];
- if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
- puts("n---------n");
- printf("nTotal of all %d MyISAM-files:nData records: %9s Deleted blocks: %9sn",check_param.total_files,llstr(check_param.total_records,buff),
- llstr(check_param.total_deleted,buff2));
- }
- free_defaults(default_argv);
- free_tmpdir(&myisamchk_tmpdir);
- ft_free_stopwords();
- my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
- exit(error);
- #ifndef _lint
- return 0; /* No compiler warning */
- #endif
- } /* main */
- enum options_mc {
- OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
- OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE,
- OPT_KEY_CACHE_BLOCK_SIZE, OPT_MYISAM_BLOCK_SIZE,
- OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
- OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN,
- OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE,
- OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD
- };
- static struct my_option my_long_options[] =
- {
- {"analyze", 'a',
- "Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- #ifdef __NETWARE__
- {"auto-close", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- #endif
- {"block-search", 'b',
- "No help available.",
- 0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"backup", 'B',
- "Make a backup of the .MYD file as 'filename-time.BAK'.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"character-sets-dir", OPT_CHARSETS_DIR,
- "Directory where character sets are.",
- (gptr*) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"check", 'c',
- "Check table for errors.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"check-only-changed", 'C',
- "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).",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"correct-checksum", OPT_CORRECT_CHECKSUM,
- "Correct checksum information for table.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- #ifndef DBUG_OFF
- {"debug", '#',
- "Output debug log. Often this is 'd:t:o,filename'.",
- 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
- #endif
- {"description", 'd',
- "Prints some information about table.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"data-file-length", 'D',
- "Max length of data file (when recreating data-file when it's full).",
- (gptr*) &check_param.max_data_file_length,
- (gptr*) &check_param.max_data_file_length,
- 0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"extend-check", 'e',
- "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.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"fast", 'F',
- "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).",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"force", 'f',
- "Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"HELP", 'H',
- "Display this help and exit.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"help", '?',
- "Display this help and exit.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"information", 'i',
- "Print statistics information about table that is checked.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"keys-used", 'k',
- "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.",
- (gptr*) &check_param.keys_in_use,
- (gptr*) &check_param.keys_in_use,
- 0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
- {"max-record-length", OPT_MAX_RECORD_LENGTH,
- "Skip rows bigger than this if myisamchk can't allocate memory to hold it",
- (gptr*) &check_param.max_record_length,
- (gptr*) &check_param.max_record_length,
- 0, GET_ULL, REQUIRED_ARG, LONGLONG_MAX, 0, LONGLONG_MAX, 0, 0, 0},
- {"medium-check", 'm',
- "Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"quick", 'q', "Faster repair by not modifying the data file.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"read-only", 'T',
- "Don't mark table as checked.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"recover", 'r',
- "Can fix almost anything except unique keys that aren't unique.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"parallel-recover", 'p',
- "Same as '-r' but creates all the keys in parallel.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"safe-recover", 'o',
- "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.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"sort-recover", 'n',
- "Force recovering with sorting even if the temporary file was very big.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- #ifdef DEBUG
- {"start-check-pos", OPT_START_CHECK_POS,
- "No help available.",
- 0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- #endif
- {"set-auto-increment", 'A',
- "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.",
- (gptr*) &check_param.auto_increment_value,
- (gptr*) &check_param.auto_increment_value,
- 0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"set-collation", OPT_SET_COLLATION,
- "Change the collation used by the index",
- (gptr*) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"set-variable", 'O',
- "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
- 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"silent", 's',
- "Only print errors. One can use two -s to make myisamchk very silent.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"sort-index", 'S',
- "Sort index blocks. This speeds up 'read-next' in applications.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"sort-records", 'R',
- "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!)",
- (gptr*) &check_param.opt_sort_key,
- (gptr*) &check_param.opt_sort_key,
- 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"tmpdir", 't',
- "Path for temporary files.",
- (gptr*) &opt_tmpdir,
- 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"update-state", 'U',
- "Mark tables as crashed if any errors were found.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"unpack", 'u',
- "Unpack file packed with myisampack.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"verbose", 'v',
- "Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"version", 'V',
- "Print version and exit.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"wait", 'w',
- "Wait if table is locked.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- { "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
- (gptr*) &check_param.use_buffers, (gptr*) &check_param.use_buffers, 0,
- GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
- (long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
- { "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "",
- (gptr*) &opt_key_cache_block_size,
- (gptr*) &opt_key_cache_block_size, 0,
- GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
- MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
- { "myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "",
- (gptr*) &opt_myisam_block_size, (gptr*) &opt_myisam_block_size, 0,
- GET_LONG, REQUIRED_ARG, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
- MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
- { "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
- (gptr*) &check_param.read_buffer_length,
- (gptr*) &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
- (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
- (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
- { "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
- (gptr*) &check_param.write_buffer_length,
- (gptr*) &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
- (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
- (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
- { "sort_buffer_size", OPT_SORT_BUFFER_SIZE, "",
- (gptr*) &check_param.sort_buffer_length,
- (gptr*) &check_param.sort_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
- (long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
- (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
- { "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
- (gptr*) &check_param.sort_key_blocks,
- (gptr*) &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
- BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
- { "decode_bits", OPT_DECODE_BITS, "", (gptr*) &decode_bits,
- (gptr*) &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
- { "ft_min_word_len", OPT_FT_MIN_WORD_LEN, "", (gptr*) &ft_min_word_len,
- (gptr*) &ft_min_word_len, 0, GET_ULONG, REQUIRED_ARG, 4, 1, HA_FT_MAXCHARLEN,
- 0, 1, 0},
- { "ft_max_word_len", OPT_FT_MAX_WORD_LEN, "", (gptr*) &ft_max_word_len,
- (gptr*) &ft_max_word_len, 0, GET_ULONG, REQUIRED_ARG, HA_FT_MAXCHARLEN, 10,
- HA_FT_MAXCHARLEN, 0, 1, 0},
- { "ft_stopword_file", OPT_FT_STOPWORD_FILE,
- "Use stopwords from this file instead of built-in list.",
- (gptr*) &ft_stopword_file, (gptr*) &ft_stopword_file, 0, GET_STR,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"stats_method", OPT_STATS_METHOD,
- "Specifies how index statistics collection code should threat NULLs. "
- "Possible values of name are "nulls_unequal" (default behavior for 4.1/5.0), "
- ""nulls_equal" (emulate 4.0 behavior), and "nulls_ignored".",
- (gptr*) &myisam_stats_method_str, (gptr*) &myisam_stats_method_str, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
- };
- #include <help_start.h>
- static void print_version(void)
- {
- printf("%s Ver 2.7 for %s at %sn", my_progname, SYSTEM_TYPE,
- MACHINE_TYPE);
- NETWARE_SET_SCREEN_MODE(1);
- }
- static void usage(void)
- {
- print_version();
- puts("By Monty, for your professional use");
- puts("This software comes with NO WARRANTY: see the PUBLIC for details.n");
- puts("Description, check and repair of MyISAM tables.");
- puts("Used without options all tables on the command will be checked for errors");
- printf("Usage: %s [OPTIONS] tables[.MYI]n", my_progname_short);
- printf("nGlobal options:n");
- #ifndef DBUG_OFF
- printf("
- -#, --debug=... Output debug log. Often this is 'd:t:o,filename'.n");
- #endif
- printf("
- -?, --help Display this help and exit.n
- -O, --set-variable var=option.n
- Change the value of a variable. Please note thatn
- this option is deprecated; you can set variablesn
- directly with '--variable-name=value'.n
- -t, --tmpdir=path Path for temporary files. Multiple paths can ben
- specified, separated by ");
- #if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
- printf("semicolon (;)");
- #else
- printf("colon (:)");
- #endif
- printf(", they will be usedn
- in a round-robin fashion.n
- -s, --silent Only print errors. One can use two -s to maken
- myisamchk very silent.n
- -v, --verbose Print more information. This can be used withn
- --description and --check. Use many -v for more verbosity.n
- -V, --version Print version and exit.n
- -w, --wait Wait if table is locked.nn");
- #ifdef DEBUG
- puts(" --start-check-pos=# Start reading file at given offset.n");
- #endif
- puts("Check options (check is the default action for myisamchk):n
- -c, --check Check table for errors.n
- -e, --extend-check Check the table VERY throughly. Only use this inn
- extreme cases as myisamchk should normally be able ton
- find out if the table is ok even without this switch.n
- -F, --fast Check only tables that haven't been closed properly.n
- -C, --check-only-changedn
- Check only tables that have changed since last check.n
- -f, --force Restart with '-r' if there are any errors in the table.n
- States will be updated as with '--update-state'.n
- -i, --information Print statistics information about table that is checked.n
- -m, --medium-check Faster than extend-check, but only finds 99.99% ofn
- all errors. Should be good enough for most cases.n
- -U --update-state Mark tables as crashed if you find any errors.n
- -T, --read-only Don't mark table as checked.n");
- puts("Repair options (When using '-r' or '-o'):n
- -B, --backup Make a backup of the .MYD file as 'filename-time.BAK'.n
- --correct-checksum Correct checksum information for table.n
- -D, --data-file-length=# Max length of data file (when recreating datan
- file when it's full).n
- -e, --extend-check Try to recover every possible row from the data filen
- Normally this will also find a lot of garbage rows;n
- Don't use this option if you are not totally desperate.n
- -f, --force Overwrite old temporary files.n
- -k, --keys-used=# Tell MyISAM to update only some specific keys. # is an
- bit mask of which keys to use. This can be used ton
- get faster inserts.n
- --max-record-length=#n
- Skip rows bigger than this if myisamchk can't allocaten
- memory to hold it.n
- -r, --recover Can fix almost anything except unique keys that aren'tn
- unique.n
- -n, --sort-recover Forces recovering with sorting even if the temporaryn
- file would be very big.n
- -p, --parallel-recovern
- Uses the same technique as '-r' and '-n', but createsn
- all the keys in parallel, in different threads.n
- -o, --safe-recover Uses old recovery method; Slower than '-r' but cann
- handle a couple of cases where '-r' reports that itn
- can't fix the data file.n
- --character-sets-dir=...n
- Directory where character sets are.n
- --set-collation=namen
- Change the collation used by the index.n
- -q, --quick Faster repair by not modifying the data file.n
- One can give a second '-q' to force myisamchk ton
- modify the original datafile in case of duplicate keys.n
- NOTE: Tables where the data file is currupted can't ben
- fixed with this option.n
- -u, --unpack Unpack file packed with myisampack.n
- ");
- puts("Other actions:n
- -a, --analyze Analyze distribution of keys. Will make some joins inn
- MySQL faster. You can check the calculated distributionn
- by using '--description --verbose table_name'.n
- --stats_method=name Specifies how index statistics collection code shouldn
- threat NULLs. Possible values of name are "nulls_unequal"n
- (default for 4.1/5.0), "nulls_equal" (emulate 4.0), and n
- "nulls_ignored".n
- -d, --description Prints some information about table.n
- -A, --set-auto-increment[=value]n
- Force auto_increment to start at this or higher valuen
- If no value is given, then sets the next auto_incrementn
- value to the highest used value for the auto key + 1.n
- -S, --sort-index Sort index blocks. This speeds up 'read-next' inn
- applications.n
- -R, --sort-records=#n
- Sort records according to an index. This makes yourn
- data much more localized and may speed up thingsn
- (It may be VERY slow to do a sort the first time!).n
- -b, --block-search=#n
- Find a record, a block at given offset belongs to.");
- print_defaults("my", load_default_groups);
- my_print_variables(my_long_options);
- }
- #include <help_end.h>
- const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
- "nulls_ignored", NullS};
- TYPELIB myisam_stats_method_typelib= {
- array_elements(myisam_stats_method_names) - 1, "",
- myisam_stats_method_names, NULL};
- /* Read options */
- static my_bool
- get_one_option(int optid,
- const struct my_option *opt __attribute__((unused)),
- char *argument)
- {
- switch (optid) {
- #ifdef __NETWARE__
- case OPT_AUTO_CLOSE:
- setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
- break;
- #endif
- case 'a':
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_STATISTICS;
- else
- check_param.testflag|= T_STATISTICS;
- break;
- case 'A':
- if (argument)
- check_param.auto_increment_value= strtoull(argument, NULL, 0);
- else
- check_param.auto_increment_value= 0; /* Set to max used value */
- check_param.testflag|= T_AUTO_INC;
- break;
- case 'b':
- check_param.search_after_block= strtoul(argument, NULL, 10);
- break;
- case 'B':
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_BACKUP_DATA;
- else
- check_param.testflag|= T_BACKUP_DATA;
- break;
- case 'c':
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_CHECK;
- else
- check_param.testflag|= T_CHECK;
- break;
- case 'C':
- if (argument == disabled_my_option)
- check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
- else
- check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
- break;
- case 'D':
- check_param.max_data_file_length=strtoll(argument, NULL, 10);
- break;
- case 's': /* silent */
- if (argument == disabled_my_option)
- check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
- else
- {
- if (check_param.testflag & T_SILENT)
- check_param.testflag|= T_VERY_SILENT;
- check_param.testflag|= T_SILENT;
- check_param.testflag&= ~T_WRITE_LOOP;
- }
- break;
- case 'w':
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_WAIT_FOREVER;
- else
- check_param.testflag|= T_WAIT_FOREVER;
- break;
- case 'd': /* description if isam-file */
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_DESCRIPT;
- else
- check_param.testflag|= T_DESCRIPT;
- break;
- case 'e': /* extend check */
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_EXTEND;
- else
- check_param.testflag|= T_EXTEND;
- break;
- case 'i':
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_INFO;
- else
- check_param.testflag|= T_INFO;
- break;
- case 'f':
- if (argument == disabled_my_option)
- {
- check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
- check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
- }
- else
- {
- check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
- check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
- }
- break;
- case 'F':
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_FAST;
- else
- check_param.testflag|= T_FAST;
- break;
- case 'k':
- check_param.keys_in_use= (ulonglong) strtoll(argument, NULL, 10);
- break;
- case 'm':
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_MEDIUM;
- else
- check_param.testflag|= T_MEDIUM; /* Medium check */
- break;
- case 'r': /* Repair table */
- check_param.testflag&= ~T_REP_ANY;
- if (argument != disabled_my_option)
- check_param.testflag|= T_REP_BY_SORT;
- break;
- case 'p':
- check_param.testflag&= ~T_REP_ANY;
- if (argument != disabled_my_option)
- check_param.testflag|= T_REP_PARALLEL;
- break;
- case 'o':
- check_param.testflag&= ~T_REP_ANY;
- check_param.force_sort= 0;
- if (argument != disabled_my_option)
- {
- check_param.testflag|= T_REP;
- my_disable_async_io= 1; /* More safety */
- }
- break;
- case 'n':
- check_param.testflag&= ~T_REP_ANY;
- if (argument == disabled_my_option)
- check_param.force_sort= 0;
- else
- {
- check_param.testflag|= T_REP_BY_SORT;
- check_param.force_sort= 1;
- }
- break;
- case 'q':
- if (argument == disabled_my_option)
- check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
- else
- check_param.testflag|=
- (check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
- break;
- case 'u':
- if (argument == disabled_my_option)
- check_param.testflag&= ~(T_UNPACK | T_REP_BY_SORT);
- else
- check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
- break;
- case 'v': /* Verbose */
- if (argument == disabled_my_option)
- {
- check_param.testflag&= ~T_VERBOSE;
- check_param.verbose=0;
- }
- else
- {
- check_param.testflag|= T_VERBOSE;
- check_param.verbose++;
- }
- break;
- case 'R': /* Sort records */
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_SORT_RECORDS;
- else
- {
- check_param.testflag|= T_SORT_RECORDS;
- check_param.opt_sort_key= (uint) atoi(argument) - 1;
- if (check_param.opt_sort_key >= MI_MAX_KEY)
- {
- fprintf(stderr,
- "The value of the sort key is bigger than max key: %d.n",
- MI_MAX_KEY);
- exit(1);
- }
- }
- break;
- case 'S': /* Sort index */
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_SORT_INDEX;
- else
- check_param.testflag|= T_SORT_INDEX;
- break;
- case 'T':
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_READONLY;
- else
- check_param.testflag|= T_READONLY;
- break;
- case 'U':
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_UPDATE_STATE;
- else
- check_param.testflag|= T_UPDATE_STATE;
- break;
- case '#':
- if (argument == disabled_my_option)
- {
- DBUG_POP();
- }
- else
- {
- DBUG_PUSH(argument ? argument : "d:t:o,/tmp/myisamchk.trace");
- }
- break;
- case 'V':
- print_version();
- exit(0);
- case OPT_CORRECT_CHECKSUM:
- if (argument == disabled_my_option)
- check_param.testflag&= ~T_CALC_CHECKSUM;
- else
- check_param.testflag|= T_CALC_CHECKSUM;
- break;
- case OPT_STATS_METHOD:
- {
- int method;
- enum_mi_stats_method method_conv;
- myisam_stats_method_str= argument;
- if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
- {
- fprintf(stderr, "Invalid value of stats_method: %s.n", argument);
- exit(1);
- }
- switch (method-1) {
- case 0:
- method_conv= MI_STATS_METHOD_NULLS_EQUAL;
- break;
- case 1:
- method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
- break;
- case 2:
- method_conv= MI_STATS_METHOD_IGNORE_NULLS;
- break;
- }
- check_param.stats_method= method_conv;
- break;
- }
- #ifdef DEBUG /* Only useful if debugging */
- case OPT_START_CHECK_POS:
- check_param.start_check_pos= strtoull(argument, NULL, 0);
- break;
- #endif
- case 'H':
- my_print_help(my_long_options);
- exit(0);
- case '?':
- usage();
- exit(0);
- }
- return 0;
- }
- static void get_options(register int *argc,register char ***argv)
- {
- int ho_error;
- load_defaults("my", load_default_groups, argc, argv);
- default_argv= *argv;
- if (isatty(fileno(stdout)))
- check_param.testflag|=T_WRITE_LOOP;
- if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
- exit(ho_error);
- /* If using repair, then update checksum if one uses --update-state */
- if ((check_param.testflag & T_UPDATE_STATE) &&
- (check_param.testflag & T_REP_ANY))
- check_param.testflag|= T_CALC_CHECKSUM;
- if (*argc == 0)
- {
- usage();
- exit(-1);
- }
- if ((check_param.testflag & T_UNPACK) &&
- (check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
- {
- VOID(fprintf(stderr,
- "%s: --unpack can't be used with --quick or --sort-recordsn",
- my_progname_short));
- exit(1);
- }
- if ((check_param.testflag & T_READONLY) &&
- (check_param.testflag &
- (T_REP_ANY | T_STATISTICS | T_AUTO_INC |
- T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
- {
- VOID(fprintf(stderr,
- "%s: Can't use --readonly when repairing or sortingn",
- my_progname_short));
- exit(1);
- }
- if (init_tmpdir(&myisamchk_tmpdir, opt_tmpdir))
- exit(1);
- check_param.tmpdir=&myisamchk_tmpdir;
- check_param.key_cache_block_size= opt_key_cache_block_size;
- if (set_collation_name)
- if (!(set_collation= get_charset_by_name(set_collation_name,
- MYF(MY_WME))))
- exit(1);
- myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
- return;
- } /* get options */
- /* Check table */
- static int myisamchk(MI_CHECK *param, my_string filename)
- {
- int error,lock_type,recreate;
- int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
- uint raid_chunks;
- MI_INFO *info;
- File datafile;
- char llbuff[22],llbuff2[22];
- my_bool state_updated=0;
- MYISAM_SHARE *share;
- DBUG_ENTER("myisamchk");
- param->out_flag=error=param->warning_printed=param->error_printed=
- recreate=0;
- datafile=0;
- param->isam_file_name=filename; /* For error messages */
- if (!(info=mi_open(filename,
- (param->testflag & (T_DESCRIPT | T_READONLY)) ?
- O_RDONLY : O_RDWR,
- HA_OPEN_FOR_REPAIR |
- ((param->testflag & T_WAIT_FOREVER) ?
- HA_OPEN_WAIT_IF_LOCKED :
- (param->testflag & T_DESCRIPT) ?
- HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
- {
- /* Avoid twice printing of isam file name */
- param->error_printed=1;
- switch (my_errno) {
- case HA_ERR_CRASHED:
- 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);
- break;
- case HA_ERR_NOT_A_TABLE:
- mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
- break;
- case HA_ERR_CRASHED_ON_USAGE:
- mi_check_print_error(param,"'%s' is marked as crashed",filename);
- break;
- case HA_ERR_CRASHED_ON_REPAIR:
- mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
- break;
- case HA_ERR_OLD_FILE:
- mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
- break;
- case HA_ERR_END_OF_FILE:
- mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
- break;
- case EAGAIN:
- mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
- break;
- case ENOENT:
- mi_check_print_error(param,"File '%s' doesn't exist",filename);
- break;
- case EACCES:
- mi_check_print_error(param,"You don't have permission to use '%s'",filename);
- break;
- default:
- mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
- my_errno,filename);
- break;
- }
- DBUG_RETURN(1);
- }
- share=info->s;
- share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
- share->tot_locks-= share->r_locks;
- share->r_locks=0;
- raid_chunks=share->base.raid_chunks;
- /*
- Skip the checking of the file if:
- We are using --fast and the table is closed properly
- We are using --check-only-changed-tables and the table hasn't changed
- */
- if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
- {
- my_bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
- if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
- ((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
- STATE_CRASHED_ON_REPAIR) ||
- !(param->testflag & T_CHECK_ONLY_CHANGED))))
- need_to_check=1;
- if (info->s->base.keys && info->state->records)
- {
- if ((param->testflag & T_STATISTICS) &&
- (share->state.changed & STATE_NOT_ANALYZED))
- need_to_check=1;
- if ((param->testflag & T_SORT_INDEX) &&
- (share->state.changed & STATE_NOT_SORTED_PAGES))
- need_to_check=1;
- if ((param->testflag & T_REP_BY_SORT) &&
- (share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
- need_to_check=1;
- }
- if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
- (share->state.changed & (STATE_CHANGED | STATE_CRASHED |
- STATE_CRASHED_ON_REPAIR)))
- need_to_check=1;
- if (!need_to_check)
- {
- if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
- printf("MyISAM file: %s is already checkedn",filename);
- if (mi_close(info))
- {
- mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
- my_errno,filename);
- DBUG_RETURN(1);
- }
- DBUG_RETURN(0);
- }
- }
- if ((param->testflag & (T_REP_ANY | T_STATISTICS |
- T_SORT_RECORDS | T_SORT_INDEX)) &&
- (((param->testflag & T_UNPACK) &&
- share->data_file_type == COMPRESSED_RECORD) ||
- mi_uint2korr(share->state.header.state_info_length) !=
- MI_STATE_INFO_SIZE ||
- mi_uint2korr(share->state.header.base_info_length) !=
- MI_BASE_INFO_SIZE ||
- ((param->keys_in_use & ~share->state.key_map) &
- (((ulonglong) 1L << share->base.keys)-1)) ||
- test_if_almost_full(info) ||
- info->s->state.header.file_version[3] != myisam_file_magic[3] ||
- (set_collation &&
- set_collation->number != share->state.header.language) ||
- myisam_block_size != MI_KEY_BLOCK_LENGTH))
- {
- if (set_collation)
- param->language= set_collation->number;
- if (recreate_table(param, &info,filename))
- {
- VOID(fprintf(stderr,
- "MyISAM-table '%s' is not fixed because of errorsn",
- filename));
- return(-1);
- }
- recreate=1;
- if (!(param->testflag & T_REP_ANY))
- {
- param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
- if (!(param->testflag & T_SILENT))
- printf("- '%s' has old table-format. Recreating indexn",filename);
- rep_quick|=T_QUICK;
- }
- share=info->s;
- share->tot_locks-= share->r_locks;
- share->r_locks=0;
- }
- if (param->testflag & T_DESCRIPT)
- {
- param->total_files++;
- param->total_records+=info->state->records;
- param->total_deleted+=info->state->del;
- descript(param, info, filename);
- }
- else
- {
- if (!stopwords_inited++)
- ft_init_stopwords();
- if (!(param->testflag & T_READONLY))
- lock_type = F_WRLCK; /* table is changed */
- else
- lock_type= F_RDLCK;
- if (info->lock_type == F_RDLCK)
- info->lock_type=F_UNLCK; /* Read only table */
- if (_mi_readinfo(info,lock_type,0))
- {
- mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
- filename,my_errno);
- param->error_printed=0;
- goto end2;
- }
- /*
- _mi_readinfo() has locked the table.
- We mark the table as locked (without doing file locks) to be able to
- use functions that only works on locked tables (like row caching).
- */
- mi_lock_database(info, F_EXTRA_LCK);
- datafile=info->dfile;
- if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
- {
- if (param->testflag & T_REP_ANY)
- {
- ulonglong tmp=share->state.key_map;
- share->state.key_map= (((ulonglong) 1 << share->base.keys)-1)
- & param->keys_in_use;
- if (tmp != share->state.key_map)
- info->update|=HA_STATE_CHANGED;
- }
- if (rep_quick && chk_del(param, info, param->testflag & ~T_VERBOSE))
- {
- if (param->testflag & T_FORCE_CREATE)
- {
- rep_quick=0;
- mi_check_print_info(param,"Creating new data filen");
- }
- else
- {
- error=1;
- mi_check_print_error(param,
- "Quick-recover aborted; Run recovery without switch 'q'");
- }
- }
- if (!error)
- {
- if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
- (share->state.key_map ||
- (rep_quick && !param->keys_in_use && !recreate)) &&
- mi_test_if_sort_rep(info, info->state->records,
- info->s->state.key_map,
- param->force_sort))
- {
- if (param->testflag & T_REP_BY_SORT)
- error=mi_repair_by_sort(param,info,filename,rep_quick);
- else
- error=mi_repair_parallel(param,info,filename,rep_quick);
- state_updated=1;
- }
- else if (param->testflag & T_REP_ANY)
- error=mi_repair(param, info,filename,rep_quick);
- }
- if (!error && param->testflag & T_SORT_RECORDS)
- {
- /*
- The data file is nowadays reopened in the repair code so we should
- soon remove the following reopen-code
- */
- #ifndef TO_BE_REMOVED
- if (param->out_flag & O_NEW_DATA)
- { /* Change temp file to org file */
- VOID(my_close(info->dfile,MYF(MY_WME))); /* Close new file */
- error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
- raid_chunks,
- MYF(0));
- if (mi_open_datafile(info,info->s, -1))
- error=1;
- param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */
- param->read_cache.file=info->dfile;
- }
- #endif
- if (! error)
- {
- uint key;
- /*
- We can't update the index in mi_sort_records if we have a
- prefix compressed or fulltext index
- */
- my_bool update_index=1;
- for (key=0 ; key < share->base.keys; key++)
- if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY|HA_FULLTEXT))
- update_index=0;
- error=mi_sort_records(param,info,filename,param->opt_sort_key,
- /* what is the following parameter for ? */
- (my_bool) !(param->testflag & T_REP),
- update_index);
- datafile=info->dfile; /* This is now locked */
- if (!error && !update_index)
- {
- if (param->verbose)
- puts("Table had a compressed index; We must now recreate the index");
- error=mi_repair_by_sort(param,info,filename,1);
- }
- }
- }
- if (!error && param->testflag & T_SORT_INDEX)
- error=mi_sort_index(param,info,filename);
- if (!error)
- share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
- STATE_CRASHED_ON_REPAIR);
- else
- mi_mark_crashed(info);
- }
- else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
- {
- if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
- printf("Checking MyISAM file: %sn",filename);
- if (!(param->testflag & T_SILENT))
- printf("Data records: %7s Deleted blocks: %7sn",
- llstr(info->state->records,llbuff),
- llstr(info->state->del,llbuff2));
- error =chk_status(param,info);
- share->state.key_map &=param->keys_in_use;
- error =chk_size(param,info);
- if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
- error|=chk_del(param, info,param->testflag);
- if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
- !param->start_check_pos)))
- {
- error|=chk_key(param, info);
- if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
- error=update_state_info(param, info,
- ((param->testflag & T_STATISTICS) ?
- UPDATE_STAT : 0) |
- ((param->testflag & T_AUTO_INC) ?
- UPDATE_AUTO_INC : 0));
- }
- if ((!rep_quick && !error) ||
- !(param->testflag & (T_FAST | T_FORCE_CREATE)))
- {
- if (param->testflag & (T_EXTEND | T_MEDIUM))
- VOID(init_key_cache(dflt_key_cache,opt_key_cache_block_size,
- param->use_buffers, 0, 0));
- VOID(init_io_cache(¶m->read_cache,datafile,
- (uint) param->read_buffer_length,
- READ_CACHE,
- (param->start_check_pos ?
- param->start_check_pos :
- share->pack.header_length),
- 1,
- MYF(MY_WME)));
- lock_memory(param);
- if ((info->s->options & (HA_OPTION_PACK_RECORD |
- HA_OPTION_COMPRESS_RECORD)) ||
- (param->testflag & (T_EXTEND | T_MEDIUM)))
- error|=chk_data_link(param, info, param->testflag & T_EXTEND);
- error|=flush_blocks(param, share->key_cache, share->kfile);
- VOID(end_io_cache(¶m->read_cache));
- }
- if (!error)
- {
- if ((share->state.changed & STATE_CHANGED) &&
- (param->testflag & T_UPDATE_STATE))
- info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
- share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
- STATE_CRASHED_ON_REPAIR);
- }
- else if (!mi_is_crashed(info) &&
- (param->testflag & T_UPDATE_STATE))
- { /* Mark crashed */
- mi_mark_crashed(info);
- info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
- }
- }
- }
- if ((param->testflag & T_AUTO_INC) ||
- ((param->testflag & T_REP_ANY) && info->s->base.auto_key))
- update_auto_increment_key(param, info,
- (my_bool) !test(param->testflag & T_AUTO_INC));
- if (!(param->testflag & T_DESCRIPT))
- {
- if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
- error|=update_state_info(param, info,
- UPDATE_OPEN_COUNT |
- (((param->testflag & T_REP_ANY) ?
- UPDATE_TIME : 0) |
- (state_updated ? UPDATE_STAT : 0) |
- ((param->testflag & T_SORT_RECORDS) ?
- UPDATE_SORT : 0)));
- VOID(lock_file(param, share->kfile,0L,F_UNLCK,"indexfile",filename));
- info->update&= ~HA_STATE_CHANGED;
- }
- mi_lock_database(info, F_UNLCK);
- end2:
- if (mi_close(info))
- {
- mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
- DBUG_RETURN(1);
- }
- if (error == 0)
- {
- if (param->out_flag & O_NEW_DATA)
- error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT,
- raid_chunks,
- ((param->testflag & T_BACKUP_DATA) ?
- MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
- if (param->out_flag & O_NEW_INDEX)
- error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0,
- MYF(0));
- }
- VOID(fflush(stdout)); VOID(fflush(stderr));
- if (param->error_printed)
- {
- if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
- {
- VOID(fprintf(stderr,
- "MyISAM-table '%s' is not fixed because of errorsn",
- filename));
- if (param->testflag & T_REP_ANY)
- VOID(fprintf(stderr,
- "Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flagn"));
- }
- else if (!(param->error_printed & 2) &&
- !(param->testflag & T_FORCE_CREATE))
- VOID(fprintf(stderr,
- "MyISAM-table '%s' is corruptednFix it using switch "-r" or "-o"n",
- filename));
- }
- else if (param->warning_printed &&
- ! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
- T_FORCE_CREATE)))
- VOID(fprintf(stderr, "MyISAM-table '%s' is usable but should be fixedn",
- filename));
- VOID(fflush(stderr));
- DBUG_RETURN(error);
- } /* myisamchk */
- /* Write info about table */
- static void descript(MI_CHECK *param, register MI_INFO *info, my_string name)
- {
- uint key,keyseg_nr,field,start;
- reg3 MI_KEYDEF *keyinfo;
- reg2 HA_KEYSEG *keyseg;
- reg4 const char *text;
- char buff[160],length[10],*pos,*end;
- enum en_fieldtype type;
- MYISAM_SHARE *share=info->s;
- char llbuff[22],llbuff2[22];
- DBUG_ENTER("describe");
- printf("nMyISAM file: %sn",name);
- fputs("Record format: ",stdout);
- if (share->options & HA_OPTION_COMPRESS_RECORD)
- puts("Compressed");
- else if (share->options & HA_OPTION_PACK_RECORD)
- puts("Packed");
- else
- puts("Fixed length");
- printf("Character set: %s (%d)n",
- get_charset_name(share->state.header.language),
- share->state.header.language);
- if (param->testflag & T_VERBOSE)
- {
- printf("File-version: %dn",
- (int) share->state.header.file_version[3]);
- if (share->state.create_time)
- {
- get_date(buff,1,share->state.create_time);
- printf("Creation time: %sn",buff);
- }
- if (share->state.check_time)
- {
- get_date(buff,1,share->state.check_time);
- printf("Recover time: %sn",buff);
- }
- pos=buff;
- if (share->state.changed & STATE_CRASHED)
- strmov(buff,"crashed");
- else
- {
- if (share->state.open_count)
- pos=strmov(pos,"open,");
- if (share->state.changed & STATE_CHANGED)
- pos=strmov(pos,"changed,");
- else
- pos=strmov(pos,"checked,");
- if (!(share->state.changed & STATE_NOT_ANALYZED))
- pos=strmov(pos,"analyzed,");
- if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
- pos=strmov(pos,"optimized keys,");
- if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
- pos=strmov(pos,"sorted index pages,");
- pos[-1]=0; /* Remove extra ',' */
- }
- printf("Status: %sn",buff);
- if (share->base.auto_key)
- {
- printf("Auto increment key: %13d Last value: %13sn",
- share->base.auto_key,
- llstr(share->state.auto_increment,llbuff));
- }
- if (share->base.raid_type)
- {
- printf("RAID: Type: %u Chunks: %u Chunksize: %lun",
- share->base.raid_type,
- share->base.raid_chunks,
- share->base.raid_chunksize);
- }
- if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
- printf("Checksum: %23sn",llstr(info->s->state.checksum,llbuff));
- ;
- if (share->options & HA_OPTION_DELAY_KEY_WRITE)
- printf("Keys are only flushed at closen");
- }
- printf("Data records: %13s Deleted blocks: %13sn",
- llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
- if (param->testflag & T_SILENT)
- DBUG_VOID_RETURN; /* This is enough */
- if (param->testflag & T_VERBOSE)
- {
- #ifdef USE_RELOC
- printf("Init-relocation: %13sn",llstr(share->base.reloc,llbuff));
- #endif
- printf("Datafile parts: %13s Deleted data: %13sn",
- llstr(share->state.split,llbuff),
- llstr(info->state->empty,llbuff2));
- printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9dn",
- share->rec_reflength,share->base.key_reflength);
- printf("Datafile length: %13s Keyfile length: %13sn",
- llstr(info->state->data_file_length,llbuff),
- llstr(info->state->key_file_length,llbuff2));
- if (info->s->base.reloc == 1L && info->s->base.records == 1L)
- puts("This is a one-record table");
- else
- {
- if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
- share->base.max_key_file_length != HA_OFFSET_ERROR)
- printf("Max datafile length: %13s Max keyfile length: %13sn",
- llstr(share->base.max_data_file_length-1,llbuff),
- llstr(share->base.max_key_file_length-1,llbuff2));
- }
- }
- printf("Recordlength: %13dn",(int) share->base.pack_reclength);
- if (share->state.key_map != (((ulonglong) 1 << share->base.keys) -1))
- {
- longlong2str(share->state.key_map,buff,2);
- printf("Using only keys '%s' of %d possibly keysn",
- buff, share->base.keys);
- }
- puts("ntable description:");
- printf("Key Start Len Index Type");
- if (param->testflag & T_VERBOSE)
- printf(" Rec/key Root Blocksize");
- VOID(putchar('n'));
- for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
- key < share->base.keys;
- key++,keyinfo++)
- {
- keyseg=keyinfo->seg;
- if (keyinfo->flag & HA_NOSAME) text="unique ";
- else if (keyinfo->flag & HA_FULLTEXT) text="fulltext ";
- else text="multip.";
- pos=buff;
- if (keyseg->flag & HA_REVERSE_SORT)
- *pos++ = '-';
- pos=strmov(pos,type_names[keyseg->type]);
- *pos++ = ' ';
- *pos=0;
- if (keyinfo->flag & HA_PACK_KEY)
- pos=strmov(pos,prefix_packed_txt);
- if (keyinfo->flag & HA_BINARY_PACK_KEY)
- pos=strmov(pos,bin_packed_txt);
- if (keyseg->flag & HA_SPACE_PACK)
- pos=strmov(pos,diff_txt);
- if (keyseg->flag & HA_BLOB_PART)
- pos=strmov(pos,blob_txt);
- if (keyseg->flag & HA_NULL_PART)
- pos=strmov(pos,null_txt);
- *pos=0;
- printf("%-4d%-6ld%-3d %-8s%-21s",
- key+1,(long) keyseg->start+1,keyseg->length,text,buff);
- if (share->state.key_root[key] != HA_OFFSET_ERROR)
- llstr(share->state.key_root[key],buff);
- else
- buff[0]=0;
- if (param->testflag & T_VERBOSE)
- printf("%11lu %12s %10d",
- share->state.rec_per_key_part[keyseg_nr++],
- buff,keyinfo->block_length);
- VOID(putchar('n'));
- while ((++keyseg)->type != HA_KEYTYPE_END)
- {
- pos=buff;
- if (keyseg->flag & HA_REVERSE_SORT)
- *pos++ = '-';
- pos=strmov(pos,type_names[keyseg->type]);
- *pos++= ' ';
- if (keyseg->flag & HA_SPACE_PACK)
- pos=strmov(pos,diff_txt);
- if (keyseg->flag & HA_BLOB_PART)
- pos=strmov(pos,blob_txt);
- if (keyseg->flag & HA_NULL_PART)
- pos=strmov(pos,null_txt);
- *pos=0;
- printf(" %-6ld%-3d %-21s",
- (long) keyseg->start+1,keyseg->length,buff);
- if (param->testflag & T_VERBOSE)
- printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
- VOID(putchar('n'));
- }
- keyseg++;
- }
- if (share->state.header.uniques)
- {
- MI_UNIQUEDEF *uniqueinfo;
- puts("nUnique Key Start Len Nullpos Nullbit Type");
- for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
- key < share->state.header.uniques; key++, uniqueinfo++)
- {
- my_bool new_row=0;
- char null_bit[8],null_pos[8];
- printf("%-8d%-5d",key+1,uniqueinfo->key+1);
- for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
- {
- if (new_row)
- fputs(" ",stdout);
- null_bit[0]=null_pos[0]=0;
- if (keyseg->null_bit)
- {
- sprintf(null_bit,"%d",keyseg->null_bit);
- sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
- }
- printf("%-7ld%-5d%-9s%-10s%-30sn",
- (long) keyseg->start+1,keyseg->length,
- null_pos,null_bit,
- type_names[keyseg->type]);
- new_row=1;
- }
- }
- }
- if (param->verbose > 1)
- {
- char null_bit[8],null_pos[8];
- printf("nField Start Length Nullpos Nullbit Type");
- if (share->options & HA_OPTION_COMPRESS_RECORD)
- printf(" Huff tree Bits");
- VOID(putchar('n'));
- start=1;
- for (field=0 ; field < share->base.fields ; field++)
- {
- if (share->options & HA_OPTION_COMPRESS_RECORD)
- type=share->rec[field].base_type;
- else
- type=(enum en_fieldtype) share->rec[field].type;
- end=strmov(buff,field_pack[type]);
- if (share->options & HA_OPTION_COMPRESS_RECORD)
- {
- if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
- end=strmov(end,", not_always");
- if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
- end=strmov(end,", no empty");
- if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
- {
- sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
- end=strend(end);
- }
- }
- if (buff[0] == ',')
- strmov(buff,buff+2);
- int10_to_str((long) share->rec[field].length,length,10);
- null_bit[0]=null_pos[0]=0;
- if (share->rec[field].null_bit)
- {
- sprintf(null_bit,"%d",share->rec[field].null_bit);
- sprintf(null_pos,"%d",share->rec[field].null_pos+1);
- }
- printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
- null_pos, null_bit, buff);
- if (share->options & HA_OPTION_COMPRESS_RECORD)
- {
- if (share->rec[field].huff_tree)
- printf("%3d %2d",
- (uint) (share->rec[field].huff_tree-share->decode_trees)+1,
- share->rec[field].huff_tree->quick_table_bits);
- }
- VOID(putchar('n'));
- start+=share->rec[field].length;
- }
- }
- DBUG_VOID_RETURN;
- } /* describe */
- /* Sort records according to one key */
- static int mi_sort_records(MI_CHECK *param,
- register MI_INFO *info, my_string name,
- uint sort_key,
- my_bool write_info,
- my_bool update_index)
- {
- int got_error;
- uint key;
- MI_KEYDEF *keyinfo;
- File new_file;
- uchar *temp_buff;
- ha_rows old_record_count;
- MYISAM_SHARE *share=info->s;
- char llbuff[22],llbuff2[22];
- SORT_INFO sort_info;
- MI_SORT_PARAM sort_param;
- DBUG_ENTER("sort_records");
- bzero((char*)&sort_info,sizeof(sort_info));
- bzero((char*)&sort_param,sizeof(sort_param));
- sort_param.sort_info=&sort_info;
- sort_info.param=param;
- keyinfo= &share->keyinfo[sort_key];
- got_error=1;
- temp_buff=0;
- new_file= -1;
- if (!(((ulonglong) 1 << sort_key) & share->state.key_map))
- {
- mi_check_print_warning(param,
- "Can't sort table '%s' on key %d; No such key",
- name,sort_key+1);
- param->error_printed=0;
- DBUG_RETURN(0); /* Nothing to do */
- }
- if (keyinfo->flag & HA_FULLTEXT)
- {
- mi_check_print_warning(param,"Can't sort table '%s' on FULLTEXT key %d",
- name,sort_key+1);
- param->error_printed=0;
- DBUG_RETURN(0); /* Nothing to do */
- }
- if (share->data_file_type == COMPRESSED_RECORD)
- {
- mi_check_print_warning(param,"Can't sort read-only table '%s'", name);
- param->error_printed=0;
- DBUG_RETURN(0); /* Nothing to do */
- }
- if (!(param->testflag & T_SILENT))
- {
- printf("- Sorting records for MyISAM-table '%s'n",name);
- if (write_info)
- printf("Data records: %9s Deleted: %9sn",
- llstr(info->state->records,llbuff),
- llstr(info->state->del,llbuff2));
- }
- if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
- DBUG_RETURN(0); /* Nothing to do */
- init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers,
- 0, 0);
- if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
- WRITE_CACHE,share->pack.header_length,1,
- MYF(MY_WME | MY_WAIT_IF_FULL)))
- goto err;
- info->opt_flag|=WRITE_CACHE_USED;
- if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
- {
- mi_check_print_error(param,"Not enough memory for key block");
- goto err;
- }
- if (!(sort_param.record=(byte*) my_malloc((uint) share->base.pack_reclength,
- MYF(0))))
- {
- mi_check_print_error(param,"Not enough memory for record");
- goto err;
- }
- fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32);
- new_file=my_raid_create(fn_format(param->temp_filename,
- param->temp_filename,"",
- DATA_TMP_EXT,2+4),
- 0,param->tmpfile_createflag,
- share->base.raid_type,
- share->base.raid_chunks,
- share->base.raid_chunksize,
- MYF(0));
- if (new_file < 0)
- {
- mi_check_print_error(param,"Can't create new tempfile: '%s'",
- param->temp_filename);
- goto err;
- }
- if (share->pack.header_length)
- if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
- "datafile-header"))
- goto err;
- info->rec_cache.file=new_file; /* Use this file for cacheing*/
- lock_memory(param);
- for (key=0 ; key < share->base.keys ; key++)
- share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
- if (my_pread(share->kfile,(byte*) temp_buff,
- (uint) keyinfo->block_length,
- share->state.key_root[sort_key],
- MYF(MY_NABP+MY_WME)))
- {
- mi_check_print_error(param,"Can't read indexpage from filepos: %s",
- (ulong) share->state.key_root[sort_key]);
- goto err;
- }
- /* Setup param for sort_write_record */
- sort_info.info=info;
- sort_info.new_data_file_type=share->data_file_type;
- sort_param.fix_datafile=1;
- sort_param.master=1;
- sort_param.filepos=share->pack.header_length;
- old_record_count=info->state->records;
- info->state->records=0;
- if (sort_info.new_data_file_type != COMPRESSED_RECORD)
- share->state.checksum=0;
- if (sort_record_index(&sort_param,info,keyinfo,share->state.key_root[sort_key],
- temp_buff, sort_key,new_file,update_index) ||
- write_data_suffix(&sort_info,1) ||
- flush_io_cache(&info->rec_cache))
- goto err;
- if (info->state->records != old_record_count)
- {
- mi_check_print_error(param,"found %s of %s records",
- llstr(info->state->records,llbuff),
- llstr(old_record_count,llbuff2));
- goto err;
- }
- VOID(my_close(info->dfile,MYF(MY_WME)));
- param->out_flag|=O_NEW_DATA; /* Data in new file */
- info->dfile=new_file; /* Use new datafile */
- info->state->del=0;
- info->state->empty=0;
- share->state.dellink= HA_OFFSET_ERROR;
- info->state->data_file_length=sort_param.filepos;
- share->state.split=info->state->records; /* Only hole records */
- share->state.version=(ulong) time((time_t*) 0);
- info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- if (param->testflag & T_WRITE_LOOP)
- {
- VOID(fputs(" r",stdout)); VOID(fflush(stdout));
- }
- got_error=0;
- err:
- if (got_error && new_file >= 0)
- {
- VOID(end_io_cache(&info->rec_cache));
- (void) my_close(new_file,MYF(MY_WME));
- (void) my_raid_delete(param->temp_filename, share->base.raid_chunks,
- MYF(MY_WME));
- }
- if (temp_buff)
- {
- my_afree((gptr) temp_buff);
- }
- my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR));
- info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
- VOID(end_io_cache(&info->rec_cache));
- my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
- sort_info.buff=0;
- share->state.sortkey=sort_key;
- DBUG_RETURN(flush_blocks(param, share->key_cache, share->kfile) |
- got_error);
- } /* sort_records */
- /* Sort records recursive using one index */
- static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
- MI_KEYDEF *keyinfo,
- my_off_t page, uchar *buff, uint sort_key,
- File new_file,my_bool update_index)
- {
- uint nod_flag,used_length,key_length;
- uchar *temp_buff,*keypos,*endpos;
- my_off_t next_page,rec_pos;
- uchar lastkey[MI_MAX_KEY_BUFF];
- char llbuff[22];
- SORT_INFO *sort_info= sort_param->sort_info;
- MI_CHECK *param=sort_info->param;
- DBUG_ENTER("sort_record_index");
- nod_flag=mi_test_if_nod(buff);
- temp_buff=0;
- if (nod_flag)
- {
- if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
- {
- mi_check_print_error(param,"Not Enough memory");
- DBUG_RETURN(-1);
- }
- }
- used_length=mi_getint(buff);
- keypos=buff+2+nod_flag;
- endpos=buff+used_length;
- for ( ;; )
- {
- _sanity(__FILE__,__LINE__);
- if (nod_flag)
- {
- next_page=_mi_kpos(nod_flag,keypos);
- if (my_pread(info->s->kfile,(byte*) temp_buff,
- (uint) keyinfo->block_length, next_page,
- MYF(MY_NABP+MY_WME)))
- {
- mi_check_print_error(param,"Can't read keys from filepos: %s",
- llstr(next_page,llbuff));
- goto err;
- }
- if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,sort_key,
- new_file, update_index))
- goto err;
- }
- _sanity(__FILE__,__LINE__);
- if (keypos >= endpos ||
- (key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
- == 0)
- break;
- rec_pos= _mi_dpos(info,0,lastkey+key_length);
- if ((*info->s->read_rnd)(info,sort_param->record,rec_pos,0))
- {
- mi_check_print_error(param,"%d when reading datafile",my_errno);
- goto err;
- }
- if (rec_pos != sort_param->filepos && update_index)
- {
- _mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
- sort_param->filepos);
- if (movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
- sort_key))
- {
- mi_check_print_error(param,"%d when updating key-pointers",my_errno);
- goto err;
- }
- }
- if (sort_write_record(sort_param))
- goto err;
- }
- /* Clear end of block to get better compression if the table is backuped */
- bzero((byte*) buff+used_length,keyinfo->block_length-used_length);
- if (my_pwrite(info->s->kfile,(byte*) buff,(uint) keyinfo->block_length,
- page,param->myf_rw))
- {
- mi_check_print_error(param,"%d when updating keyblock",my_errno);
- goto err;
- }
- if (temp_buff)
- my_afree((gptr) temp_buff);
- DBUG_RETURN(0);
- err:
- if (temp_buff)
- my_afree((gptr) temp_buff);
- DBUG_RETURN(1);
- } /* sort_record_index */
- /*
- Check if myisamchk was killed by a signal
- This is overloaded by other programs that want to be able to abort
- sorting
- */
- static my_bool not_killed= 0;
- volatile my_bool *killed_ptr(MI_CHECK *param __attribute__((unused)))
- {
- return ¬_killed; /* always NULL */
- }
- /* print warnings and errors */
- /* VARARGS */
- void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
- const char *fmt,...)
- {
- va_list args;
- va_start(args,fmt);
- VOID(vfprintf(stdout, fmt, args));
- VOID(fputc('n',stdout));
- va_end(args);
- }
- /* VARARGS */
- void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
- {
- va_list args;
- DBUG_ENTER("mi_check_print_warning");
- fflush(stdout);
- if (!param->warning_printed && !param->error_printed)
- {
- if (param->testflag & T_SILENT)
- fprintf(stderr,"%s: MyISAM file %sn",my_progname_short,
- param->isam_file_name);
- param->out_flag|= O_DATA_LOST;
- }
- param->warning_printed=1;
- va_start(args,fmt);
- fprintf(stderr,"%s: warning: ",my_progname_short);
- VOID(vfprintf(stderr, fmt, args));
- VOID(fputc('n',stderr));
- fflush(stderr);
- va_end(args);
- DBUG_VOID_RETURN;
- }
- /* VARARGS */
- void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
- {
- va_list args;
- DBUG_ENTER("mi_check_print_error");
- DBUG_PRINT("enter",("format: %s",fmt));
- fflush(stdout);
- if (!param->warning_printed && !param->error_printed)
- {
- if (param->testflag & T_SILENT)
- fprintf(stderr,"%s: MyISAM file %sn",my_progname_short,param->isam_file_name);
- param->out_flag|= O_DATA_LOST;
- }
- param->error_printed|=1;
- va_start(args,fmt);
- fprintf(stderr,"%s: error: ",my_progname_short);
- VOID(vfprintf(stderr, fmt, args));
- VOID(fputc('n',stderr));
- fflush(stderr);
- va_end(args);
- DBUG_VOID_RETURN;
- }