static int myisamchk()

in storage/myisam/myisamchk.cc [806:1169]


static int myisamchk(MI_CHECK *param, char *filename) {
  int error, lock_type, recreate;
  int rep_quick = param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
  MI_INFO *info;
  File datafile;
  char llbuff[22], llbuff2[22];
  bool state_updated = false;
  MYISAM_SHARE *share;
  DBUG_TRACE;

  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 an 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;
    }
    return 1;
  }
  share = info->s;
  share->options &= ~HA_OPTION_READ_ONLY_DATA; /* We are modifying it */
  share->tot_locks -= share->r_locks;
  share->r_locks = 0;

  /*
    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)) {
    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 = true;

    if (info->s->base.keys && info->state->records) {
      if ((param->testflag & T_STATISTICS) &&
          (share->state.changed & STATE_NOT_ANALYZED))
        need_to_check = true;
      if ((param->testflag & T_SORT_INDEX) &&
          (share->state.changed & STATE_NOT_SORTED_PAGES))
        need_to_check = true;
      if ((param->testflag & T_REP_BY_SORT) &&
          (share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
        need_to_check = true;
    }
    if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
        (share->state.changed &
         (STATE_CHANGED | STATE_CRASHED | STATE_CRASHED_ON_REPAIR)))
      need_to_check = true;
    if (!need_to_check) {
      if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
        printf("MyISAM file: %s is already checked\n", filename);
      if (mi_close(info)) {
        mi_check_print_error(param, "%d when closing MyISAM-table '%s'",
                             my_errno(), filename);
        return 1;
      }
      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 ||
       mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
                                       ~share->state.key_map) ||
       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 errors\n",
                    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 index\n", 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;
        mi_copy_keys_active(share->state.key_map, share->base.keys,
                            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 file\n");
        } 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) &&
            (mi_is_any_key_active(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)) {
          /*
            The new file might not be created with the right stats depending
            on how myisamchk is run, so we must copy file stats from old to new.
          */
          error = mi_repair_by_sort(param, info, filename, rep_quick, false);
          state_updated = true;
        } else if (param->testflag & T_REP_ANY)
          error = mi_repair(param, info, filename, rep_quick, false);
      }
      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
        */
        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, MYF(0));
          if (mi_open_datafile(info, info->s, nullptr, -1)) error = 1;
          param->out_flag &= ~O_NEW_DATA; /* We are using new datafile */
          param->read_cache.file = info->dfile;
        }
        if (!error) {
          uint key;
          /*
            We can't update the index in mi_sort_records if we have a
            prefix compressed or fulltext index
          */
          bool update_index = true;
          for (key = 0; key < share->base.keys; key++)
            if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY | HA_FULLTEXT)) {
              update_index = false;
              break;
            }

          error =
              mi_sort_records(param, info, filename, param->opt_sort_key,
                              /* what is the following parameter for ? */
                              (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, false);
          }
        }
      }
      if (!error && param->testflag & T_SORT_INDEX)
        error = mi_sort_index(param, info, filename, false);
      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: %s\n", filename);
      if (!(param->testflag & T_SILENT))
        printf("Data records: %7s   Deleted blocks: %7s\n",
               llstr(info->state->records, llbuff),
               llstr(info->state->del, llbuff2));
      error = chk_status(param, info);
      mi_intersect_keys_active(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,
                               (size_t)param->use_buffers, 0, 0);
        (void)init_io_cache(
            &param->read_cache, datafile, (uint)param->read_buffer_length,
            READ_CACHE,
            (param->start_check_pos ? param->start_check_pos
                                    : share->pack.header_length),
            true, MYF(MY_WME));
        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(&param->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,
                              (bool)!(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, 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);
    return 1;
  }
  if (error == 0) {
    if (param->out_flag & O_NEW_DATA)
      error |= change_to_newfile(
          filename, MI_NAME_DEXT, DATA_TMP_EXT,
          ((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, 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 errors\n",
                    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) "
                      "flag\n");
    } else if (!(param->error_printed & 2) &&
               !(param->testflag & T_FORCE_CREATE))
      (void)fprintf(stderr,
                    "MyISAM-table '%s' is corrupted\nFix 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 fixed\n",
                  filename);
  (void)fflush(stderr);
  return error;
} /* myisamchk */