myisamchk.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:46k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16. /* Descript, check and repair of ISAM tables */
  17. #include "fulltext.h"
  18. #include <m_ctype.h>
  19. #include <stdarg.h>
  20. #include <getopt.h>
  21. #include <assert.h>
  22. #ifdef HAVE_SYS_VADVICE_H
  23. #include <sys/vadvise.h>
  24. #endif
  25. #ifdef HAVE_SYS_MMAN_H
  26. #include <sys/mman.h>
  27. #endif
  28. SET_STACK_SIZE(9000) /* Minimum stack size for program */
  29. #ifndef USE_RAID
  30. #define my_raid_create(A,B,C,D,E,F,G) my_create(A,B,C,G)
  31. #define my_raid_delete(A,B,C) my_delete(A,B)
  32. #endif
  33. static uint decode_bits;
  34. static char **default_argv;
  35. static const char *load_default_groups[]= { "myisamchk", 0 };
  36. static const char *set_charset_name;
  37. static uint8 set_charset_number;
  38. static CHARSET_INFO *set_charset;
  39. static const char *type_names[]=
  40. { "?","char","binary", "short", "long", "float",
  41.   "double","number","unsigned short",
  42.   "unsigned long","longlong","ulonglong","int24",
  43.   "uint24","int8","varchar", "varbin","?",
  44.   "?"};
  45. static const char *prefix_packed_txt="packed ",
  46.   *bin_packed_txt="prefix ",
  47.   *diff_txt="stripped ",
  48.   *null_txt="NULL",
  49.   *blob_txt="BLOB ";
  50. static const char *field_pack[]=
  51. {"","no endspace", "no prespace",
  52.  "no zeros", "blob", "constant", "table-lockup",
  53.  "always zero","varchar","unique-hash","?","?"};
  54. static void get_options(int *argc,char * * *argv);
  55. static void print_version(void);
  56. static void usage(void);
  57. static int myisamchk(MI_CHECK *param, char *filename);
  58. static void descript(MI_CHECK *param, register MI_INFO *info, my_string name);
  59. static int mi_sort_records(MI_CHECK *param,
  60.    register MI_INFO *info, my_string name,
  61.    uint sort_key,
  62.    my_bool write_info,
  63.    my_bool update_index);
  64. static int sort_record_index(MI_CHECK *param,MI_INFO *info,MI_KEYDEF *keyinfo,
  65.      my_off_t page,uchar *buff,uint sortkey,
  66.      File new_file, my_bool update_index);
  67. MI_CHECK check_param;
  68. /* Main program */
  69. int main(int argc, char **argv)
  70. {
  71.   int error;
  72.   MY_INIT(argv[0]);
  73. #ifdef __EMX__
  74.   _wildcard (&argc, &argv);
  75. #endif
  76.   myisamchk_init(&check_param);
  77.   check_param.opt_lock_memory=1; /* Lock memory if possible */
  78.   check_param.using_global_keycache = 0;
  79.   get_options(&argc,(char***) &argv);
  80.   myisam_quick_table_bits=decode_bits;
  81.   error=0;
  82.   while (--argc >= 0)
  83.   {
  84.     int new_error=myisamchk(&check_param, *(argv++));
  85.     VOID(fflush(stdout));
  86.     VOID(fflush(stderr));
  87.     if ((check_param.error_printed | check_param.warning_printed) &&
  88. (check_param.testflag & T_FORCE_CREATE) &&
  89. (!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
  90.    T_SORT_INDEX))))
  91.     {
  92.       uint old_testflag=check_param.testflag;
  93.       if (!(check_param.testflag & T_REP))
  94. check_param.testflag|= T_REP_BY_SORT;
  95.       check_param.testflag&= ~T_EXTEND; /* Don't needed  */
  96.       error|=myisamchk(&check_param, argv[-1]);
  97.       check_param.testflag= old_testflag;
  98.       VOID(fflush(stdout));
  99.       VOID(fflush(stderr));
  100.     }
  101.     else
  102.       error|=new_error;
  103.     if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
  104.     {
  105.       puts("n---------n");
  106.       VOID(fflush(stdout));
  107.     }
  108.   }
  109.   if (check_param.total_files > 1)
  110.   { /* Only if descript */
  111.     char buff[22],buff2[22];
  112.     if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
  113.       puts("n---------n");
  114.     printf("nTotal of all %d ISAM-files:nData records: %9s   Deleted blocks: %9sn",check_param.total_files,llstr(check_param.total_records,buff),
  115.    llstr(check_param.total_deleted,buff2));
  116.   }
  117.   free_defaults(default_argv);
  118.   ft_free_stopwords();
  119.   my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
  120.   exit(error);
  121. #ifndef _lint
  122.   return 0; /* No compiler warning */
  123. #endif
  124. } /* main */
  125. static CHANGEABLE_VAR changeable_vars[] = {
  126.   { "key_buffer_size",(long*) &check_param.use_buffers,(long) USE_BUFFER_INIT,
  127.     (long) MALLOC_OVERHEAD, (long) ~0L,(long) MALLOC_OVERHEAD,(long) IO_SIZE },
  128.   { "read_buffer_size", (long*) &check_param.read_buffer_length,(long) READ_BUFFER_INIT,
  129.       (long) MALLOC_OVERHEAD,(long) ~0L,(long) MALLOC_OVERHEAD,(long) 1L },
  130.   { "write_buffer_size", (long*) &check_param.write_buffer_length,(long) READ_BUFFER_INIT,
  131.       (long) MALLOC_OVERHEAD,(long) ~0L,(long) MALLOC_OVERHEAD,(long) 1L },
  132.   { "sort_buffer_size",(long*) &check_param.sort_buffer_length,(long) SORT_BUFFER_INIT,
  133.       (long) (MIN_SORT_BUFFER+MALLOC_OVERHEAD),(long) ~0L,
  134.       (long) MALLOC_OVERHEAD,(long) 1L },
  135.   { "sort_key_blocks",(long*) &check_param.sort_key_blocks,BUFFERS_WHEN_SORTING,4L,100L,0L,
  136.     1L },
  137.   { "decode_bits",(long*) &decode_bits,9L,4L,17L,0L,1L },
  138.   { NullS,(long*) 0,0L,0L,0L,0L,0L,} };
  139. enum options {OPT_CHARSETS_DIR=256, OPT_SET_CHARSET,OPT_START_CHECK_POS};
  140. static struct option long_options[] =
  141. {
  142.   {"analyze", no_argument,   0, 'a'},
  143.   {"block-search",      required_argument,0, 'b'},
  144.   {"backup", no_argument,   0, 'B'},
  145.   {"character-sets-dir",required_argument,0,  OPT_CHARSETS_DIR},
  146.   {"check",         no_argument,   0, 'c'},
  147.   {"check-only-changed",no_argument,   0, 'C'},
  148. #ifndef DBUG_OFF
  149.   {"debug",        optional_argument, 0, '#'},
  150. #endif
  151.   {"description",      no_argument,   0, 'd'},
  152.   {"data-file-length", required_argument, 0, 'D'},
  153.   {"extend-check",     no_argument,   0, 'e'},
  154.   {"fast",        no_argument,   0, 'F'},
  155.   {"force",        no_argument,   0, 'f'},
  156.   {"help",        no_argument,   0, '?'},
  157.   {"information",      no_argument,   0, 'i'},
  158.   {"keys-used",        required_argument, 0, 'k'},
  159.   {"medium-check",     no_argument,   0, 'm'},
  160.   {"no-symlinks",      no_argument,   0, 'l'},
  161.   {"quick",        no_argument,   0, 'q'},
  162.   {"read-only",        no_argument,   0, 'T'},
  163.   {"recover",        no_argument,   0, 'r'},
  164.   {"safe-recover",     no_argument,   0, 'o'},
  165.   {"start-check-pos",  required_argument, 0, OPT_START_CHECK_POS},
  166.   {"set-auto-increment",optional_argument, 0, 'A'},
  167.   {"set-character-set",required_argument,0,OPT_SET_CHARSET},
  168.   {"set-variable",     required_argument, 0, 'O'},
  169.   {"silent",        no_argument,   0, 's'},
  170.   {"sort-index",       no_argument,   0, 'S'},
  171.   {"sort-records",     required_argument, 0, 'R'},
  172.   {"sort-recover",     no_argument,   0, 'n'},
  173.   {"tmpdir",        required_argument, 0, 't'},
  174.   {"update-state",     no_argument,   0, 'U'},
  175.   {"unpack",        no_argument,   0, 'u'},
  176.   {"verbose",        no_argument,   0, 'v'},
  177.   {"version",        no_argument,   0, 'V'},
  178.   {"wait",        no_argument,   0, 'w'},
  179.   {0, 0, 0, 0}
  180. };
  181. static void print_version(void)
  182. {
  183.   printf("%s  Ver 1.45 for %s at %sn",my_progname,SYSTEM_TYPE,
  184.  MACHINE_TYPE);
  185. }
  186. static void usage(void)
  187. {
  188.   uint i;
  189.   print_version();
  190.   puts("By Monty, for your professional use");
  191.   puts("This software comes with NO WARRANTY: see the PUBLIC for details.n");
  192.   puts("Description, check and repair of ISAM tables.");
  193.   puts("Used without options all tables on the command will be checked for errors");
  194.   printf("Usage: %s [OPTIONS] tables[.MYI]n", my_progname);
  195.   puts("nGlobal options:n
  196.   -#, --debug=...     Output debug log. Often this is 'd:t:o,filename`n
  197.   -?, --help          Display this help and exit.n
  198.   -O, --set-variable var=optionn
  199.       Change the value of a variable.n
  200.   -s, --silent       Only print errors.  One can use two -s to maken
  201.       myisamchk very silentn
  202.   -v, --verbose       Print more information. This can be used withn
  203.                       --describe and --check. Use many -v for more verbosity!n
  204.   -V, --version       Print version and exit.n
  205.   -w, --wait          Wait if table is locked.n");
  206.   puts("Check options (check is the default action for myisamchk):n
  207.   -c, --check       Check table for errorsn
  208.   -e, --extend-check  Check the table VERY throughly.  Only use this inn
  209.                       extreme cases as myisamchk should normally be able ton
  210.                       find out if the table is ok even without this switchn
  211.   -F, --fast       Check only tables that hasn't been closed properlyn
  212.   -C, --check-only-changedn
  213.       Check only tables that has changed since last checkn
  214.   -f, --force         Restart with -r if there are any errors in the tablen
  215.   -i, --information   Print statistics information about table that is checkedn
  216.   -m, --medium-check  Faster than extended-check, but only finds 99.99% ofn
  217.       all errors.  Should be good enough for most casesn
  218.   -U  --update-state  Mark tables as crashed if you find any errorsn
  219.   -T, --read-only     Don't mark table as checkedn");
  220.   puts("Repair options (When using -r or -o) n
  221.   -B, --backup       Make a backup of the .MYD file as 'filename-time.BAK'n
  222.   -D, --data-file-length=#  Max length of data file (when recreating datan
  223.                       file when it's full)n
  224.   -e, --extend-check  Try to recover every possible row from the data filen
  225.       Normally this will also find a lot of garbage rows;n
  226.       Don't use this option if you are not totally desperate.n
  227.   -f, --force         Overwrite old temporary files.n
  228.   -k, --keys-used=#   Tell MyISAM to update only some specific keys. # is an
  229.               bit mask of which keys to use. This can be used ton
  230.       get faster inserts!n
  231.   -l, --no-symlinks   Do not follow symbolic links. Normallyn
  232.       myisamchk repairs the table a symlink points at.n
  233.   -r, --recover       Can fix almost anything except unique keys that aren'tn
  234.                       unique.n
  235.   -n, --sort-recover  Force recovering with sorting even if the temporaryn
  236.       file would be very big.n
  237.   -o, --safe-recover  Uses old recovery method; Slower than '-r' but cann
  238.       handle a couple of cases where '-r' reports that itn
  239.       can't fix the data file.n
  240.   --character-sets-dir=...n
  241.                       Directory where character sets aren
  242.   --set-character-set=namen
  243.         Change the character set used by the indexn
  244.   -t, --tmpdir=path   Path for temporary filesn
  245.   -q, --quick         Faster repair by not modifying the data file.n
  246.                       One can give a second '-q' to force myisamchk ton
  247.       modify the original datafile in case of duplicate keysn
  248.   -u, --unpack        Unpack file packed with myisampack.n
  249. ");
  250.   puts("Other actions:n
  251.   -a, --analyze       Analyze distribution of keys. Will make some joins inn
  252.       MySQL faster.  You can check the calculated distributionn
  253.       by using '--describe --verbose table_name'.n
  254.   -d, --description   Prints some information about table.n
  255.   -A, --set-auto-increment[=value]n
  256.       Force auto_increment to start at this or higher valuen
  257.       If no value is given, then sets the next auto_incrementn
  258.       value to the highest used value for the auto key + 1.n
  259.   -S, --sort-index    Sort index blocks.  This speeds up 'read-next' inn
  260.       applicationsn
  261.   -R, --sort-records=#n
  262.       Sort records according to an index.  This makes yourn
  263.       data much more localized and may speed up thingsn
  264.       (It may be VERY slow to do a sort the first time!)");
  265.   print_defaults("my",load_default_groups);
  266.   printf("nPossible variables for option --set-variable (-O) are:n");
  267.   for (i=0; changeable_vars[i].name ; i++)
  268.     printf("%-20s  current value: %lun",
  269.    changeable_vars[i].name,
  270.    *changeable_vars[i].varptr);
  271. }
  272.  /* Read options */
  273. static void get_options(register int *argc,register char ***argv)
  274. {
  275.   int c,option_index=0;
  276.   uint old_testflag;
  277.   load_defaults("my",load_default_groups,argc,argv);
  278.   default_argv= *argv;
  279.   set_all_changeable_vars(changeable_vars);
  280.   if (isatty(fileno(stdout)))
  281.     check_param.testflag|=T_WRITE_LOOP;
  282.   while ((c=getopt_long(*argc,*argv,
  283. "aBcCdeifF?lqrmnosSTuUvVw#:b:D:k:O:R:A::t:",
  284. long_options, &option_index)) != EOF)
  285.   {
  286.     switch(c) {
  287.     case 'a':
  288.       check_param.testflag|= T_STATISTICS;
  289.       break;
  290.     case 'A':
  291.       if (optarg)
  292. check_param.auto_increment_value=strtoull(optarg,NULL,0);
  293.       else
  294. check_param.auto_increment_value=0; /* Set to max used value */
  295.       check_param.testflag|= T_AUTO_INC;
  296.       break;
  297.     case 'b':
  298.       check_param.search_after_block=strtoul(optarg,NULL,10);
  299.       break;
  300.     case 'B':
  301.       check_param.testflag|= T_BACKUP_DATA;
  302.       break;
  303.     case 'c':
  304.       check_param.testflag|= T_CHECK;
  305.       break;
  306.     case 'C':
  307.       check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
  308.       break;
  309.     case 'D':
  310.       check_param.max_data_file_length=strtoll(optarg,NULL,10);
  311.       break;
  312.     case 's': /* silent */
  313.       if (check_param.testflag & T_SILENT)
  314. check_param.testflag|=T_VERY_SILENT;
  315.       check_param.testflag|= T_SILENT;
  316.       check_param.testflag&= ~T_WRITE_LOOP;
  317.       break;
  318.     case 'w':
  319.       check_param.testflag|= T_WAIT_FOREVER;
  320.       break;
  321.     case 'd': /* description if isam-file */
  322.       check_param.testflag|= T_DESCRIPT;
  323.       break;
  324.     case 'e': /* extend check */
  325.       check_param.testflag|= T_EXTEND;
  326.       break;
  327.     case 'i':
  328.       check_param.testflag|= T_INFO;
  329.       break;
  330.     case 'f':
  331.       check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
  332.       check_param.testflag|=T_FORCE_CREATE;
  333.       break;
  334.     case 'F':
  335.       check_param.testflag|=T_FAST;
  336.       break;
  337.     case 'k':
  338.       check_param.keys_in_use= (ulonglong) strtoll(optarg,NULL,10);
  339.       break;
  340.     case 'l':
  341.       check_param.opt_follow_links=0;
  342.       break;
  343.     case 'm':
  344.       check_param.testflag|= T_MEDIUM; /* Medium check */
  345.       break;
  346.     case 'r': /* Repair table */
  347.       check_param.testflag= (check_param.testflag & ~T_REP) | T_REP_BY_SORT;
  348.       break;
  349.     case 'o':
  350.       check_param.testflag= (check_param.testflag & ~T_REP_BY_SORT) | T_REP;
  351.       check_param.force_sort=0;
  352.       my_disable_async_io=1; /* More safety */
  353.       break;
  354.     case 'n':
  355.       check_param.testflag= (check_param.testflag & ~T_REP) | T_REP_BY_SORT;
  356.       check_param.force_sort=1;
  357.       break;
  358.     case 'q':
  359.       check_param.opt_rep_quick++;
  360.       break;
  361.     case 'u':
  362.       check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
  363.       break;
  364.     case 'v': /* Verbose */
  365.       check_param.testflag|= T_VERBOSE;
  366.       check_param.verbose++;
  367.       break;
  368.     case 'O':
  369.       if (set_changeable_var(optarg, changeable_vars))
  370.       {
  371. usage();
  372. exit(1);
  373.       }
  374.       break;
  375.     case 'R': /* Sort records */
  376.       old_testflag=check_param.testflag;
  377.       check_param.testflag|= T_SORT_RECORDS;
  378.       check_param.opt_sort_key=(uint) atoi(optarg)-1;
  379.       if (check_param.opt_sort_key >= MI_MAX_KEY)
  380.       {
  381. fprintf(stderr,
  382. "The value of the sort key is bigger than max key: %d.n",
  383. MI_MAX_KEY);
  384. exit(1);
  385.       }
  386.       break;
  387.     case 'S':       /* Sort index */
  388.       old_testflag=check_param.testflag;
  389.       check_param.testflag|= T_SORT_INDEX;
  390.       break;
  391.     case 't':
  392.       check_param.tmpdir=optarg;
  393.       break;
  394.     case 'T':
  395.       check_param.testflag|= T_READONLY;
  396.       break;
  397.     case 'U':
  398.       check_param.testflag|= T_UPDATE_STATE;
  399.       break;
  400.     case '#':
  401.       DBUG_PUSH(optarg ? optarg : "d:t:o,/tmp/myisamchk.trace");
  402.       break;
  403.     case 'V':
  404.       print_version();
  405.       exit(0);
  406.     case OPT_CHARSETS_DIR:
  407.       charsets_dir = optarg;
  408.       break;
  409.     case OPT_SET_CHARSET:
  410.       set_charset_name=optarg;
  411.       break;
  412. #ifdef DEBUG /* Only useful if debugging */
  413.     case OPT_START_CHECK_POS:
  414.       check_param.start_check_pos=strtoull(optarg,NULL,0);
  415.       break;
  416. #endif
  417.     case '?':
  418.       usage();
  419.       exit(0);
  420.     }
  421.   }
  422.   (*argc)-=optind;
  423.   (*argv)+=optind;
  424.   if (*argc == 0)
  425.   {
  426.     usage();
  427.     exit(-1);
  428.   }
  429.   if ((check_param.testflag & T_UNPACK) &&
  430.       (check_param.opt_rep_quick || (check_param.testflag & T_SORT_RECORDS)))
  431.   {
  432.     VOID(fprintf(stderr,
  433.  "%s: --unpack can't be used with --quick or --sort-recordsn",
  434.  my_progname));
  435.     exit(1);
  436.   }
  437.   if ((check_param.testflag & T_READONLY) &&
  438.       (check_param.testflag &
  439.        (T_REP_BY_SORT | T_REP | T_STATISTICS | T_AUTO_INC |
  440. T_SORT_RECORDS | T_SORT_INDEX)))
  441.   {
  442.     VOID(fprintf(stderr,
  443.  "%s: Can't use --readonly when repairing or sortingn",
  444.  my_progname));
  445.     exit(1);
  446.   }
  447.   if (set_charset_name)
  448.     if (!(set_charset=get_charset_by_name(set_charset_name, MYF(MY_WME))))
  449.       exit(1);
  450.   return;
  451. } /* get options */
  452. /* Check table */
  453. static int myisamchk(MI_CHECK *param, my_string filename)
  454. {
  455.   int error,lock_type,recreate;
  456.   int rep_quick= param->opt_rep_quick;
  457.   uint raid_chunks;
  458.   MI_INFO *info;
  459.   File datafile;
  460.   char fixed_name[FN_REFLEN];
  461.   char llbuff[22],llbuff2[22];
  462.   my_bool state_updated=0;
  463.   MYISAM_SHARE *share;
  464.   DBUG_ENTER("myisamchk");
  465.   param->out_flag=error=param->warning_printed=param->error_printed=
  466.     recreate=0;
  467.   datafile=0;
  468.   param->isam_file_name=filename; /* For error messages */
  469.   if (!(info=mi_open(filename,
  470.      (param->testflag & (T_DESCRIPT | T_READONLY)) ?
  471.      O_RDONLY : O_RDWR,
  472.      HA_OPEN_FOR_REPAIR |
  473.      ((param->testflag & T_WAIT_FOREVER) ?
  474.       HA_OPEN_WAIT_IF_LOCKED :
  475.       (param->testflag & T_DESCRIPT) ?
  476.       HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
  477.   {
  478.     /* Avoid twice printing of isam file name */
  479.     param->error_printed=1;
  480.     switch (my_errno) {
  481.     case HA_ERR_CRASHED:
  482.       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);
  483.       break;
  484.     case HA_ERR_WRONG_TABLE_DEF:
  485.       mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
  486.       break;
  487.     case HA_ERR_CRASHED_ON_USAGE:
  488.       mi_check_print_error(param,"'%s' is marked as crashed",filename);
  489.       break;
  490.     case HA_ERR_CRASHED_ON_REPAIR:
  491.       mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
  492.       break;
  493.     case HA_ERR_OLD_FILE:
  494.       mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
  495.       break;
  496.     case HA_ERR_END_OF_FILE:
  497.       mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
  498.       break;
  499.     case EAGAIN:
  500.       mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
  501.       break;
  502.     case ENOENT:
  503.       mi_check_print_error(param,"File '%s' doesn't exist",filename);
  504.       break;
  505.     case EACCES:
  506.       mi_check_print_error(param,"You don't have permission to use '%s'",filename);
  507.       break;
  508.     default:
  509.       mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
  510.   my_errno,filename);
  511.       break;
  512.     }
  513.     DBUG_RETURN(1);
  514.   }
  515.   share=info->s;
  516.   share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
  517.   share->r_locks=0;
  518.   raid_chunks=share->base.raid_chunks;
  519.   /*
  520.     Skipp the checking of the file if:
  521.     We are using --fast and the table is closed properly
  522.     We are using --check-only-changed-tables and the table hasn't changed
  523.   */
  524.   if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
  525.   {
  526.     my_bool need_to_check= mi_is_crashed(info) || share->state.open_count != 0;
  527.     if ((param->testflag & (T_REP_BY_SORT | T_REP | T_SORT_RECORDS)) &&
  528. ((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
  529.   STATE_CRASHED_ON_REPAIR) ||
  530.   !(param->testflag & T_CHECK_ONLY_CHANGED))))
  531.       need_to_check=1;
  532.     if ((param->testflag & T_STATISTICS) &&
  533. (share->state.changed & STATE_NOT_ANALYZED))
  534.       need_to_check=1;
  535.     if ((param->testflag & T_SORT_INDEX) &&
  536. (share->state.changed & STATE_NOT_SORTED_PAGES))
  537.       need_to_check=1;
  538.     if ((param->testflag & T_REP_BY_SORT) &&
  539. (share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
  540.       need_to_check=1;
  541.     if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
  542. (share->state.changed & (STATE_CHANGED | STATE_CRASHED |
  543.  STATE_CRASHED_ON_REPAIR)))
  544.       need_to_check=1;
  545.     if (!need_to_check)
  546.     {
  547.       if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
  548. printf("MyISAM file: %s is already checkedn",filename);
  549.       if (mi_close(info))
  550.       {
  551. mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
  552.      my_errno,filename);
  553. DBUG_RETURN(1);
  554.       }
  555.       DBUG_RETURN(0);
  556.     }
  557.   }
  558.   if ((param->testflag & (T_REP_BY_SORT | T_REP | T_STATISTICS |
  559.   T_SORT_RECORDS | T_SORT_INDEX)) &&
  560.       (((param->testflag & T_UNPACK) &&
  561. share->data_file_type == COMPRESSED_RECORD) ||
  562.        mi_uint2korr(share->state.header.state_info_length) !=
  563.        MI_STATE_INFO_SIZE ||
  564.        mi_uint2korr(share->state.header.base_info_length) !=
  565.        MI_BASE_INFO_SIZE ||
  566.        ((param->keys_in_use & ~share->state.key_map) &
  567. (((ulonglong) 1L << share->base.keys)-1)) ||
  568.        test_if_almost_full(info) ||
  569.        info->s->state.header.file_version[3] != myisam_file_magic[3] ||
  570.        (set_charset && set_charset_number != share->state.header.language)))
  571.   {
  572.     check_param.language=set_charset_number;
  573.     if (recreate_table(&check_param, &info,filename))
  574.     {
  575.       VOID(fprintf(stderr,
  576.    "MyISAM-table '%s' is not fixed because of errorsn",
  577.       filename));
  578.       return(-1);
  579.     }
  580.     recreate=1;
  581.     if (!(param->testflag & (T_REP | T_REP_BY_SORT)))
  582.     {
  583.       param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
  584.       if (!(param->testflag & T_SILENT))
  585. printf("- '%s' has old table-format. Recreating indexn",filename);
  586.       if (!rep_quick)
  587. rep_quick=1;
  588.     }
  589.     share=info->s;
  590.     share->r_locks=0;
  591.   }
  592.   if (param->testflag & T_DESCRIPT)
  593.   {
  594.     param->total_files++;
  595.     param->total_records+=info->state->records;
  596.     param->total_deleted+=info->state->del;
  597.     descript(&check_param, info, filename);
  598.   }
  599.   else
  600.   {
  601.     if (share->fulltext_index)
  602.       ft_init_stopwords(ft_precompiled_stopwords);       /* SerG */
  603.     if (!(param->testflag & T_READONLY))
  604.       lock_type = F_WRLCK; /* table is changed */
  605.     else
  606.       lock_type= F_RDLCK;
  607.     if (info->lock_type == F_RDLCK)
  608.       info->lock_type=F_UNLCK; /* Read only table */
  609.     if (_mi_readinfo(info,lock_type,0))
  610.     {
  611.       mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
  612.   filename,my_errno);
  613.       param->error_printed=0;
  614.       goto end2;
  615.     }
  616.     share->w_locks++; /* Mark for writeinfo */
  617.     info->lock_type= F_EXTRA_LCK; /* Simulate as locked */
  618.     info->tmp_lock_type=lock_type;
  619.     datafile=info->dfile;
  620.     if (param->testflag & (T_REP+T_REP_BY_SORT+T_SORT_RECORDS+T_SORT_INDEX))
  621.     {
  622.       if (param->testflag & (T_REP+T_REP_BY_SORT))
  623.       {
  624. ulonglong tmp=share->state.key_map;
  625. share->state.key_map= (((ulonglong) 1 << share->base.keys)-1)
  626.   & param->keys_in_use;
  627. if (tmp != share->state.key_map)
  628.   info->update|=HA_STATE_CHANGED;
  629.       }
  630.       VOID(fn_format(fixed_name,filename,"",MI_NAME_IEXT,
  631.      4+ (param->opt_follow_links ? 16 : 0)));
  632.       if (rep_quick && chk_del(&check_param, info,
  633.        param->testflag & ~T_VERBOSE))
  634.       {
  635. if (param->testflag & T_FORCE_CREATE)
  636. {
  637.   rep_quick=0;
  638.   mi_check_print_info(param,"Creating new data filen");
  639. }
  640. else
  641. {
  642.   error=1;
  643.   mi_check_print_error(param,
  644.        "Quick-recover aborted; Run recovery without switch 'q'");
  645. }
  646.       }
  647.       if (!error)
  648.       {
  649. if ((param->testflag & T_REP_BY_SORT) &&
  650.     (share->state.key_map ||
  651.      (rep_quick && !param->keys_in_use && !recreate)) &&
  652.     mi_test_if_sort_rep(info, info->state->records,
  653. check_param.force_sort))
  654. {
  655.   error=mi_repair_by_sort(&check_param,info,fixed_name,rep_quick);
  656.   state_updated=1;
  657. }
  658. else if (param->testflag & (T_REP | T_REP_BY_SORT))
  659.   error=mi_repair(&check_param, info,fixed_name,rep_quick);
  660.       }
  661.       if (!error && param->testflag & T_SORT_RECORDS)
  662.       {
  663. /*
  664.   The data file is nowadays reopened in the repair code so we should
  665.   soon remove the following reopen-code
  666. */
  667. #ifndef TO_BE_REMOVED
  668. if (param->out_flag & O_NEW_DATA)
  669. { /* Change temp file to org file */
  670.   VOID(my_close(info->dfile,MYF(MY_WME))); /* Close new file */
  671.   error|=change_to_newfile(fixed_name,MI_NAME_DEXT,DATA_TMP_EXT,
  672.    raid_chunks,
  673.    MYF(0));
  674.   if (mi_open_datafile(info,info->s))
  675.     error=1;
  676.   param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */
  677.   param->read_cache.file=info->dfile;
  678. }
  679. #endif
  680. if (! error)
  681. {
  682.   uint key;
  683.   /*
  684.     We can't update the index in mi_sort_records if we have a
  685.     prefix compressed index
  686.   */
  687.   my_bool update_index=1;
  688.   for (key=0 ; key < share->base.keys; key++)
  689.     if (share->keyinfo[key].flag & HA_BINARY_PACK_KEY)
  690.       update_index=0;
  691.   error=mi_sort_records(param,info,fixed_name,param->opt_sort_key,
  692. (my_bool) !(param->testflag & T_REP),
  693. update_index);
  694.   datafile=info->dfile; /* This is now locked */
  695.   if (!error && !update_index)
  696.   {
  697.     if (check_param.verbose)
  698.       puts("Table had a compressed index;  We must now recreate the index");
  699.     error=mi_repair_by_sort(&check_param,info,fixed_name,1);
  700.   }
  701. }
  702.       }
  703.       if (!error && param->testflag & T_SORT_INDEX)
  704. error=mi_sort_index(param,info,fixed_name);
  705.       if (!error)
  706. share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
  707.  STATE_CRASHED_ON_REPAIR);
  708.       else
  709. mi_mark_crashed(info);
  710.     }
  711.     else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
  712.     {
  713.       if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
  714. printf("Checking MyISAM file: %sn",filename);
  715.       if (!(param->testflag & T_SILENT))
  716. printf("Data records: %7s   Deleted blocks: %7sn",
  717.        llstr(info->state->records,llbuff),
  718.        llstr(info->state->del,llbuff2));
  719.       error =chk_status(param,info);
  720.       share->state.key_map &=param->keys_in_use;
  721.       error =chk_size(param,info);
  722.       if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
  723. error|=chk_del(param, info,param->testflag);
  724.       if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
  725.       !param->start_check_pos)))
  726.       {
  727. error|=chk_key(param, info);
  728. if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
  729.   error=update_state_info(param, info,
  730.   ((param->testflag & T_STATISTICS) ?
  731.    UPDATE_STAT : 0) |
  732.   ((param->testflag & T_AUTO_INC) ?
  733.    UPDATE_AUTO_INC : 0));
  734.       }
  735.       if ((!rep_quick && !error) ||
  736.   !(param->testflag & (T_FAST | T_FORCE_CREATE)))
  737.       {
  738. if (param->testflag & (T_EXTEND | T_MEDIUM))
  739.   VOID(init_key_cache(param->use_buffers,(uint) NEAD_MEM));
  740. VOID(init_io_cache(&param->read_cache,datafile,
  741.    (uint) param->read_buffer_length,
  742.    READ_CACHE,
  743.    (param->start_check_pos ?
  744.     param->start_check_pos :
  745.     share->pack.header_length),
  746.    1,
  747.    MYF(MY_WME)));
  748. lock_memory(param);
  749. if ((info->s->options & (HA_OPTION_PACK_RECORD |
  750.  HA_OPTION_COMPRESS_RECORD)) ||
  751.     (param->testflag & (T_EXTEND | T_MEDIUM)))
  752.   error|=chk_data_link(param, info, param->testflag & T_EXTEND);
  753. error|=flush_blocks(param,share->kfile);
  754. VOID(end_io_cache(&param->read_cache));
  755.       }
  756.       if (!error)
  757.       {
  758. if ((share->state.changed & STATE_CHANGED) &&
  759.     (param->testflag & T_UPDATE_STATE))
  760.   info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
  761. share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
  762.  STATE_CRASHED_ON_REPAIR);
  763.       }
  764.       else if (!mi_is_crashed(info) &&
  765.        (param->testflag & T_UPDATE_STATE))
  766.       { /* Mark crashed */
  767. mi_mark_crashed(info);
  768. info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
  769.       }
  770.     }
  771.   }
  772.   if ((param->testflag & T_AUTO_INC) ||
  773.       ((param->testflag & (T_REP | T_REP_BY_SORT)) &&
  774.        info->s->base.auto_key))
  775.     update_auto_increment_key(param, info,
  776.       (my_bool) !test(param->testflag & T_AUTO_INC));
  777.   if (!(param->testflag & T_DESCRIPT))
  778.   {
  779.     if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
  780.       error|=update_state_info(param, info,
  781.        UPDATE_OPEN_COUNT |
  782.        (((param->testflag & (T_REP | T_REP_BY_SORT)) ?
  783.  UPDATE_TIME : 0) |
  784. (state_updated ? UPDATE_STAT : 0) |
  785. ((param->testflag & T_SORT_RECORDS) ?
  786.  UPDATE_SORT : 0)));
  787.     VOID(lock_file(param, share->kfile,0L,F_UNLCK,"indexfile",filename));
  788.     info->update&= ~HA_STATE_CHANGED;
  789.   }
  790.   share->w_locks--;
  791. end2:
  792.   if (mi_close(info))
  793.   {
  794.     mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
  795.     DBUG_RETURN(1);
  796.   }
  797.   if (error == 0)
  798.   {
  799.     if (param->out_flag & O_NEW_DATA)
  800.       error|=change_to_newfile(fixed_name,MI_NAME_DEXT,DATA_TMP_EXT,
  801.        raid_chunks,
  802.        ((param->testflag & T_BACKUP_DATA) ?
  803. MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
  804.     if (param->out_flag & O_NEW_INDEX)
  805.       error|=change_to_newfile(fixed_name,MI_NAME_IEXT,INDEX_TMP_EXT,0,
  806.        MYF(0));
  807.   }
  808.   VOID(fflush(stdout)); VOID(fflush(stderr));
  809.   if (param->error_printed)
  810.   {
  811.     if (param->testflag & (T_REP+T_REP_BY_SORT+T_SORT_RECORDS+T_SORT_INDEX))
  812.     {
  813.       VOID(fprintf(stderr,
  814.    "MyISAM-table '%s' is not fixed because of errorsn",
  815.    filename));
  816.       if (check_param.testflag & (T_REP_BY_SORT | T_REP))
  817. VOID(fprintf(stderr,
  818.      "Try fixing it by using the --safe-recover (-o) or the --force (-f) optionn"));
  819.     }
  820.     else if (!(param->error_printed & 2) &&
  821.      !(param->testflag & T_FORCE_CREATE))
  822.       VOID(fprintf(stderr,
  823.       "MyISAM-table '%s' is corruptednFix it using switch "-r" or "-o"n",
  824.       filename));
  825.   }
  826.   else if (param->warning_printed &&
  827.    ! (param->testflag & (T_REP+T_REP_BY_SORT+T_SORT_RECORDS+T_SORT_INDEX+
  828.   T_FORCE_CREATE)))
  829.     VOID(fprintf(stderr, "MyISAM-table '%s' is usable but should be fixedn",
  830.  filename));
  831.   VOID(fflush(stderr));
  832.   DBUG_RETURN(error);
  833. } /* myisamchk */
  834.  /* Write info about table */
  835. static void descript(MI_CHECK *param, register MI_INFO *info, my_string name)
  836. {
  837.   uint key,keyseg_nr,field,start;
  838.   reg3 MI_KEYDEF *keyinfo;
  839.   reg2 MI_KEYSEG *keyseg;
  840.   reg4 const char *text;
  841.   char buff[160],length[10],*pos,*end;
  842.   enum en_fieldtype type;
  843.   MYISAM_SHARE *share=info->s;
  844.   char llbuff[22],llbuff2[22];
  845.   DBUG_ENTER("describe");
  846.   printf("nMyISAM file:         %sn",name);
  847.   fputs("Record format:       ",stdout);
  848.   if (share->options & HA_OPTION_COMPRESS_RECORD)
  849.     puts("Compressed");
  850.   else if (share->options & HA_OPTION_PACK_RECORD)
  851.     puts("Packed");
  852.   else
  853.     puts("Fixed length");
  854.   printf("Character set:       %s (%d)n",
  855.  get_charset_name(share->state.header.language),
  856.  share->state.header.language);
  857.   if (param->testflag & T_VERBOSE)
  858.   {
  859.     printf("File-version:        %dn",
  860.    (int) share->state.header.file_version[3]);
  861.     if (share->state.create_time)
  862.     {
  863.       get_date(buff,1,share->state.create_time);
  864.       printf("Creation time:       %sn",buff);
  865.     }
  866.     if (share->state.check_time)
  867.     {
  868.       get_date(buff,1,share->state.check_time);
  869.       printf("Recover time:        %sn",buff);
  870.     }
  871.     pos=buff;
  872.     if (share->state.changed & STATE_CRASHED)
  873.       strmov(buff,"crashed");
  874.     else
  875.     {
  876.       if (share->state.open_count)
  877. pos=strmov(pos,"open,");
  878.       if (share->state.changed & STATE_CHANGED)
  879. pos=strmov(pos,"changed,");
  880.       else
  881. pos=strmov(pos,"checked,");
  882.       if (!(share->state.changed & STATE_NOT_ANALYZED))
  883. pos=strmov(pos,"analyzed,");
  884.       if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
  885. pos=strmov(pos,"optimized keys,");
  886.       if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
  887. pos=strmov(pos,"sorted index pages,");
  888.       pos[-1]=0; /* Remove extra ',' */
  889.     }      
  890.     printf("Status:              %sn",buff);
  891.     if (share->base.auto_key)
  892.     {
  893.       printf("Auto increment key:  %13d  Last value:         %13sn",
  894.      share->base.auto_key,
  895.      llstr(share->state.auto_increment,llbuff));
  896.     }
  897.     if (share->base.raid_type)
  898.     {
  899.       printf("RAID:                Type:  %u   Chunks: %u  Chunksize: %lun",
  900.      share->base.raid_type,
  901.      share->base.raid_chunks,
  902.      share->base.raid_chunksize);
  903.     }
  904.     if (share->options & HA_OPTION_CHECKSUM)
  905.       printf("Checksum:  %23sn",llstr(info->s->state.checksum,llbuff));
  906. ;
  907.     if (share->options & HA_OPTION_DELAY_KEY_WRITE)
  908.       printf("Keys are only flushed at closen");
  909.   }
  910.   printf("Data records:        %13s  Deleted blocks:     %13sn",
  911.  llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
  912.   if (param->testflag & T_SILENT)
  913.     DBUG_VOID_RETURN; /* This is enough */
  914.   if (param->testflag & T_VERBOSE)
  915.   {
  916. #ifdef USE_RELOC
  917.     printf("Init-relocation:     %13sn",llstr(share->base.reloc,llbuff));
  918. #endif
  919.     printf("Datafile parts:      %13s  Deleted data:       %13sn",
  920.    llstr(share->state.split,llbuff),
  921.    llstr(info->state->empty,llbuff2));
  922.     printf("Datafile pointer (bytes):%9d  Keyfile pointer (bytes):%9dn",
  923.    share->rec_reflength,share->base.key_reflength);
  924.     printf("Datafile length:     %13s  Keyfile length:     %13sn",
  925.    llstr(info->state->data_file_length,llbuff),
  926.    llstr(info->state->key_file_length,llbuff2));
  927.     if (info->s->base.reloc == 1L && info->s->base.records == 1L)
  928.       puts("This is a one-record table");
  929.     else
  930.     {
  931.       if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
  932.   share->base.max_key_file_length != HA_OFFSET_ERROR)
  933. printf("Max datafile length: %13s  Max keyfile length: %13sn",
  934.        llstr(share->base.max_data_file_length-1,llbuff),
  935.        llstr(share->base.max_key_file_length-1,llbuff2));
  936.     }
  937.   }
  938.   printf("Recordlength:        %13dn",(int) share->base.pack_reclength);
  939.   if (share->state.key_map != (((ulonglong) 1 << share->base.keys) -1))
  940.   {
  941.     longlong2str(share->state.key_map,buff,2);
  942.     printf("Using only keys '%s' of %d possibly keysn",
  943.    buff, share->base.keys);
  944.   }
  945.   puts("ntable description:");
  946.   printf("Key Start Len Index   Type");
  947.   if (param->testflag & T_VERBOSE)
  948.     printf("                     Rec/key         Root  Blocksize");
  949.   VOID(putchar('n'));
  950.   for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
  951.        key < share->base.keys;
  952.        key++,keyinfo++)
  953.   {
  954.     keyseg=keyinfo->seg;
  955.     if (keyinfo->flag & HA_NOSAME) text="unique ";
  956.     else if (keyinfo->flag & HA_FULLTEXT) text="fulltext ";
  957.     else text="multip.";
  958.     pos=buff;
  959.     if (keyseg->flag & HA_REVERSE_SORT)
  960.       *pos++ = '-';
  961.     pos=strmov(pos,type_names[keyseg->type]);
  962.     *pos++ = ' ';
  963.     *pos=0;
  964.     if (keyinfo->flag & HA_PACK_KEY)
  965.       pos=strmov(pos,prefix_packed_txt);
  966.     if (keyinfo->flag & HA_BINARY_PACK_KEY)
  967.       pos=strmov(pos,bin_packed_txt);
  968.     if (keyseg->flag & HA_SPACE_PACK)
  969.       pos=strmov(pos,diff_txt);
  970.     if (keyseg->flag & HA_BLOB_PART)
  971.       pos=strmov(pos,blob_txt);
  972.     if (keyseg->flag & HA_NULL_PART)
  973.       pos=strmov(pos,null_txt);
  974.     *pos=0;
  975.     printf("%-4d%-6ld%-3d %-8s%-21s",
  976.    key+1,(long) keyseg->start+1,keyseg->length,text,buff);
  977.     if (share->state.key_root[key] != HA_OFFSET_ERROR)
  978.       llstr(share->state.key_root[key],buff);
  979.     else
  980.       buff[0]=0;
  981.     if (param->testflag & T_VERBOSE)
  982.       printf("%11lu %12s %10d",
  983.      share->state.rec_per_key_part[keyseg_nr++],
  984.      buff,keyinfo->block_length);
  985.     VOID(putchar('n'));
  986.     while ((++keyseg)->type != HA_KEYTYPE_END)
  987.     {
  988.       pos=buff;
  989.       if (keyseg->flag & HA_REVERSE_SORT)
  990. *pos++ = '-';
  991.       pos=strmov(pos,type_names[keyseg->type]);
  992.       *pos++= ' ';
  993.       if (keyseg->flag & HA_SPACE_PACK)
  994. pos=strmov(pos,diff_txt);
  995.       if (keyseg->flag & HA_BLOB_PART)
  996. pos=strmov(pos,blob_txt);
  997.       if (keyseg->flag & HA_NULL_PART)
  998. pos=strmov(pos,null_txt);
  999.       *pos=0;
  1000.       printf("    %-6ld%-3d         %-21s",
  1001.      (long) keyseg->start+1,keyseg->length,buff);
  1002.       if (param->testflag & T_VERBOSE)
  1003. printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
  1004.       VOID(putchar('n'));
  1005.     }
  1006.     keyseg++;
  1007.   }
  1008.   if (share->state.header.uniques)
  1009.   {
  1010.     MI_UNIQUEDEF *uniqueinfo;
  1011.     puts("nUnique  Key  Start  Len  Nullpos  Nullbit  Type");
  1012.     for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
  1013.  key < share->state.header.uniques; key++, uniqueinfo++)
  1014.     {
  1015.       my_bool new_row=0;
  1016.       char null_bit[8],null_pos[8];
  1017.       printf("%-8d%-5d",key+1,uniqueinfo->key+1);
  1018.       for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
  1019.       {
  1020. if (new_row)
  1021.   fputs("             ",stdout);
  1022. null_bit[0]=null_pos[0]=0;
  1023. if (keyseg->null_bit)
  1024. {
  1025.   sprintf(null_bit,"%d",keyseg->null_bit);
  1026.   sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
  1027. }
  1028. printf("%-7ld%-5d%-9s%-10s%-30sn",
  1029.        (long) keyseg->start+1,keyseg->length,
  1030.        null_pos,null_bit,
  1031.        type_names[keyseg->type]);
  1032. new_row=1;
  1033.       }
  1034.     }
  1035.   }
  1036.   if (param->verbose > 1)
  1037.   {
  1038.     char null_bit[8],null_pos[8];
  1039.     printf("nField Start Length Nullpos Nullbit Type");
  1040.     if (share->options & HA_OPTION_COMPRESS_RECORD)
  1041.       printf("                         Huff tree  Bits");
  1042.     VOID(putchar('n'));
  1043.     start=1;
  1044.     for (field=0 ; field < share->base.fields ; field++)
  1045.     {
  1046.       if (share->options & HA_OPTION_COMPRESS_RECORD)
  1047. type=share->rec[field].base_type;
  1048.       else
  1049. type=(enum en_fieldtype) share->rec[field].type;
  1050.       end=strmov(buff,field_pack[type]);
  1051.       if (share->options & HA_OPTION_COMPRESS_RECORD)
  1052.       {
  1053. if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
  1054.   end=strmov(end,", not_always");
  1055. if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
  1056.   end=strmov(end,", no empty");
  1057. if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
  1058. {
  1059.   sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
  1060.   end=strend(end);
  1061. }
  1062.       }
  1063.       if (buff[0] == ',')
  1064. strmov(buff,buff+2);
  1065.       int2str((long) share->rec[field].length,length,10);
  1066.       null_bit[0]=null_pos[0]=0;
  1067.       if (share->rec[field].null_bit)
  1068.       {
  1069. sprintf(null_bit,"%d",share->rec[field].null_bit);
  1070. sprintf(null_pos,"%d",share->rec[field].null_pos+1);
  1071.       }
  1072.       printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
  1073.      null_pos, null_bit, buff);
  1074.       if (share->options & HA_OPTION_COMPRESS_RECORD)
  1075.       {
  1076. if (share->rec[field].huff_tree)
  1077.   printf("%3d    %2d",
  1078.  (uint) (share->rec[field].huff_tree-share->decode_trees)+1,
  1079.  share->rec[field].huff_tree->quick_table_bits);
  1080.       }
  1081.       VOID(putchar('n'));
  1082.       start+=share->rec[field].length;
  1083.     }
  1084.   }
  1085.   DBUG_VOID_RETURN;
  1086. } /* describe */
  1087. /* Sort records according to one key */
  1088. static int mi_sort_records(MI_CHECK *param,
  1089.    register MI_INFO *info, my_string name,
  1090.    uint sort_key,
  1091.    my_bool write_info,
  1092.    my_bool update_index) 
  1093. {
  1094.   int got_error;
  1095.   uint key;
  1096.   MI_KEYDEF *keyinfo;
  1097.   File new_file;
  1098.   uchar *temp_buff;
  1099.   ha_rows old_record_count;
  1100.   MYISAM_SHARE *share=info->s;
  1101.   char llbuff[22],llbuff2[22];
  1102.   SORT_INFO *sort_info= &param->sort_info;
  1103.   DBUG_ENTER("sort_records");
  1104.   bzero((char*) sort_info,sizeof(*sort_info));
  1105.   sort_info->param=param;
  1106.   keyinfo= &share->keyinfo[sort_key];
  1107.   got_error=1;
  1108.   temp_buff=0;
  1109.   new_file= -1;
  1110.   if (!(((ulonglong) 1 << sort_key) & share->state.key_map))
  1111.   {
  1112.     mi_check_print_error(param,"Can't sort table '%s' on key %d;  No such key",
  1113. name,sort_key+1);
  1114.     param->error_printed=0;
  1115.     DBUG_RETURN(-1);
  1116.   }
  1117.   if (!(param->testflag & T_SILENT))
  1118.   {
  1119.     printf("- Sorting records for MyISAM-table '%s'n",name);
  1120.     if (write_info)
  1121.       printf("Data records: %9s   Deleted: %9sn",
  1122.      llstr(info->state->records,llbuff),
  1123.      llstr(info->state->del,llbuff2));
  1124.   }
  1125.   if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
  1126.     DBUG_RETURN(0); /* Nothing to do */
  1127.   init_key_cache(param->use_buffers,NEAD_MEM);
  1128.   if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
  1129.    WRITE_CACHE,share->pack.header_length,1,
  1130.    MYF(MY_WME | MY_WAIT_IF_FULL)))
  1131.     goto err;
  1132.   info->opt_flag|=WRITE_CACHE_USED;
  1133.   if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
  1134.   {
  1135.     mi_check_print_error(param,"Not enough memory for key block");
  1136.     goto err;
  1137.   }
  1138.   if (!(sort_info->record=(byte*) my_malloc((uint) share->base.pack_reclength,
  1139.    MYF(0))))
  1140.   {
  1141.     mi_check_print_error(param,"Not enough memory for record");
  1142.     goto err;
  1143.   }
  1144.   new_file=my_raid_create(fn_format(param->temp_filename,name,"",
  1145.     DATA_TMP_EXT,2+4),
  1146.   0,param->tmpfile_createflag,
  1147.   share->base.raid_type,
  1148.   share->base.raid_chunks,
  1149.   share->base.raid_chunksize,
  1150.   MYF(0));
  1151.   if (new_file < 0)
  1152.   {
  1153.     mi_check_print_error(param,"Can't create new tempfile: '%s'",
  1154.  param->temp_filename);
  1155.     goto err;
  1156.   }
  1157.   if (share->pack.header_length)
  1158.     if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
  1159.  "datafile-header"))
  1160.       goto err;
  1161.   info->rec_cache.file=new_file; /* Use this file for cacheing*/
  1162.   lock_memory(param);
  1163.   for (key=0 ; key < share->base.keys ; key++)
  1164.     share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
  1165.   if (my_pread(share->kfile,(byte*) temp_buff,
  1166.        (uint) keyinfo->block_length,
  1167.        share->state.key_root[sort_key],
  1168.        MYF(MY_NABP+MY_WME)))
  1169.   {
  1170.     mi_check_print_error(param,"Can't read indexpage from filepos: %s",
  1171. (ulong) share->state.key_root[sort_key]);
  1172.     goto err;
  1173.   }
  1174.   /* Setup param for sort_write_record */
  1175.   sort_info->info=info;
  1176.   sort_info->new_data_file_type=share->data_file_type;
  1177.   sort_info->fix_datafile=1;
  1178.   sort_info->filepos=share->pack.header_length;
  1179.   old_record_count=info->state->records;
  1180.   info->state->records=0;
  1181.   if (sort_info->new_data_file_type != COMPRESSED_RECORD)
  1182.     share->state.checksum=0;
  1183.   if (sort_record_index(param, info,keyinfo,share->state.key_root[sort_key],
  1184. temp_buff, sort_key,new_file,update_index) ||
  1185.       write_data_suffix(param, info) ||
  1186.       flush_io_cache(&info->rec_cache))
  1187.     goto err;
  1188.   if (info->state->records != old_record_count)
  1189.   {
  1190.     mi_check_print_error(param,"found %s of %s records",
  1191. llstr(info->state->records,llbuff),
  1192. llstr(old_record_count,llbuff2));
  1193.     goto err;
  1194.   }
  1195.   VOID(my_close(info->dfile,MYF(MY_WME)));
  1196.   param->out_flag|=O_NEW_DATA; /* Data in new file */
  1197.   info->dfile=new_file; /* Use new datafile */
  1198.   info->state->del=0;
  1199.   info->state->empty=0;
  1200.   share->state.dellink= HA_OFFSET_ERROR;
  1201.   info->state->data_file_length=sort_info->filepos;
  1202.   share->state.split=info->state->records; /* Only hole records */
  1203.   share->state.version=(ulong) time((time_t*) 0);
  1204.   info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
  1205.   if (param->testflag & T_WRITE_LOOP)
  1206.   {
  1207.     VOID(fputs("          r",stdout)); VOID(fflush(stdout));
  1208.   }
  1209.   got_error=0;
  1210. err:
  1211.   if (got_error && new_file >= 0)
  1212.   {
  1213.     VOID(end_io_cache(&info->rec_cache));
  1214.     (void) my_close(new_file,MYF(MY_WME));
  1215.     (void) my_raid_delete(param->temp_filename, share->base.raid_chunks,
  1216.   MYF(MY_WME));
  1217.   }
  1218.   if (temp_buff)
  1219.   {
  1220.     my_afree((gptr) temp_buff);
  1221.   }
  1222.   my_free(sort_info->record,MYF(MY_ALLOW_ZERO_PTR));
  1223.   info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
  1224.   VOID(end_io_cache(&info->rec_cache));
  1225.   my_free(sort_info->buff,MYF(MY_ALLOW_ZERO_PTR));
  1226.   sort_info->buff=0;
  1227.   share->state.sortkey=sort_key;
  1228.   DBUG_RETURN(flush_blocks(param, share->kfile) | got_error);
  1229. } /* sort_records */
  1230.  /* Sort records recursive using one index */
  1231. static int sort_record_index(MI_CHECK *param,MI_INFO *info, MI_KEYDEF *keyinfo,
  1232.      my_off_t page, uchar *buff, uint sort_key,
  1233.      File new_file,my_bool update_index)
  1234. {
  1235.   uint nod_flag,used_length,key_length;
  1236.   uchar *temp_buff,*keypos,*endpos;
  1237.   my_off_t next_page,rec_pos;
  1238.   uchar lastkey[MI_MAX_KEY_BUFF];
  1239.   char llbuff[22];
  1240.   SORT_INFO *sort_info= &param->sort_info;
  1241.   DBUG_ENTER("sort_record_index");
  1242.   nod_flag=mi_test_if_nod(buff);
  1243.   temp_buff=0;
  1244.   if (nod_flag)
  1245.   {
  1246.     if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
  1247.     {
  1248.       mi_check_print_error(param,"Not Enough memory");
  1249.       DBUG_RETURN(-1);
  1250.     }
  1251.   }
  1252.   used_length=mi_getint(buff);
  1253.   keypos=buff+2+nod_flag;
  1254.   endpos=buff+used_length;
  1255.   for ( ;; )
  1256.   {
  1257.     _sanity(__FILE__,__LINE__);
  1258.     if (nod_flag)
  1259.     {
  1260.       next_page=_mi_kpos(nod_flag,keypos);
  1261.       if (my_pread(info->s->kfile,(byte*) temp_buff,
  1262.   (uint) keyinfo->block_length, next_page,
  1263.    MYF(MY_NABP+MY_WME)))
  1264.       {
  1265. mi_check_print_error(param,"Can't read keys from filepos: %s",
  1266.     llstr(next_page,llbuff));
  1267. goto err;
  1268.       }
  1269.       if (sort_record_index(param, info,keyinfo,next_page,temp_buff,sort_key,
  1270.     new_file, update_index))
  1271. goto err;
  1272.     }
  1273.     _sanity(__FILE__,__LINE__);
  1274.     if (keypos >= endpos ||
  1275. (key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
  1276. == 0)
  1277.       break;
  1278.     rec_pos= _mi_dpos(info,0,lastkey+key_length);
  1279.     if ((*info->s->read_rnd)(info,sort_info->record,rec_pos,0))
  1280.     {
  1281.       mi_check_print_error(param,"%d when reading datafile",my_errno);
  1282.       goto err;
  1283.     }
  1284.     if (rec_pos != sort_info->filepos && update_index)
  1285.     {
  1286.       _mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
  1287.    sort_info->filepos);
  1288.       if (movepoint(info,sort_info->record,rec_pos,sort_info->filepos,
  1289.     sort_key))
  1290.       {
  1291. mi_check_print_error(param,"%d when updating key-pointers",my_errno);
  1292. goto err;
  1293.       }
  1294.     }
  1295.     if (sort_write_record(sort_info))
  1296.       goto err;
  1297.   }
  1298.   /* Clear end of block to get better compression if the table is backuped */
  1299.   bzero((byte*) buff+used_length,keyinfo->block_length-used_length);
  1300.   if (my_pwrite(info->s->kfile,(byte*) buff,(uint) keyinfo->block_length,
  1301. page,param->myf_rw))
  1302.   {
  1303.     mi_check_print_error(param,"%d when updating keyblock",my_errno);
  1304.     goto err;
  1305.   }
  1306.   if (temp_buff)
  1307.     my_afree((gptr) temp_buff);
  1308.   DBUG_RETURN(0);
  1309. err:
  1310.   if (temp_buff)
  1311.     my_afree((gptr) temp_buff);
  1312.   DBUG_RETURN(1);
  1313. } /* sort_record_index */
  1314. /* print warnings and errors */
  1315. /* VARARGS */
  1316. void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
  1317.  const char *fmt,...)
  1318. {
  1319.   va_list args;
  1320.   va_start(args,fmt);
  1321.   VOID(vfprintf(stdout, fmt, args));
  1322.   VOID(fputc('n',stdout));
  1323.   va_end(args);
  1324. }
  1325. /* VARARGS */
  1326. void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
  1327. {
  1328.   va_list args;
  1329.   DBUG_ENTER("mi_check_print_warning");
  1330.   fflush(stdout);
  1331.   if (!param->warning_printed && !param->error_printed)
  1332.   {
  1333.     if (param->testflag & T_SILENT)
  1334.       fprintf(stderr,"%s: MyISAM file %sn",my_progname,
  1335.       param->isam_file_name);
  1336.     param->out_flag|= O_DATA_LOST;
  1337.   }
  1338.   param->warning_printed=1;
  1339.   va_start(args,fmt);
  1340.   fprintf(stderr,"%s: warning: ",my_progname);
  1341.   VOID(vfprintf(stderr, fmt, args));
  1342.   VOID(fputc('n',stderr));
  1343.   fflush(stderr);
  1344.   va_end(args);
  1345.   DBUG_VOID_RETURN;
  1346. }
  1347. /* VARARGS */
  1348. void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
  1349. {
  1350.   va_list args;
  1351.   DBUG_ENTER("mi_check_print_error");
  1352.   DBUG_PRINT("enter",("format: %s",fmt));
  1353.   fflush(stdout);
  1354.   if (!param->warning_printed && !param->error_printed)
  1355.   {
  1356.     if (param->testflag & T_SILENT)
  1357.       fprintf(stderr,"%s: ISAM file %sn",my_progname,param->isam_file_name);
  1358.     param->out_flag|= O_DATA_LOST;
  1359.   }
  1360.   param->error_printed|=1;
  1361.   va_start(args,fmt);
  1362.   fprintf(stderr,"%s: error: ",my_progname);
  1363.   VOID(vfprintf(stderr, fmt, args));
  1364.   VOID(fputc('n',stderr));
  1365.   fflush(stderr);
  1366.   va_end(args);
  1367.   DBUG_VOID_RETURN;
  1368. }