mysqlcheck.c 21.6 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000 MySQL AB
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

   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 */

/* By Jani Tolonen, 2001-04-20, MySQL Development Team */

unknown's avatar
unknown committed
19
#define CHECK_VERSION "2.4.3"
20

unknown's avatar
unknown committed
21
#include "client_priv.h"
22
#include <m_ctype.h>
23 24 25
#include <mysql_version.h>
#include <mysqld_error.h>
#include <sslopt-vars.h>
26 27 28 29 30 31 32 33 34 35

/* Exit codes */

#define EX_USAGE 1
#define EX_MYSQLERR 2

static MYSQL mysql_connection, *sock = 0;
static my_bool opt_alldbs = 0, opt_check_only_changed = 0, opt_extended = 0,
               opt_compress = 0, opt_databases = 0, opt_fast = 0,
               opt_medium_check = 0, opt_quick = 0, opt_all_in_1 = 0,
36
               opt_silent = 0, opt_auto_repair = 0, ignore_errors = 0,
unknown's avatar
unknown committed
37
               tty_password = 0, opt_frm = 0;
38 39
static uint verbose = 0, opt_mysql_port=0;
static my_string opt_mysql_unix_port = 0;
40
static char *opt_password = 0, *current_user = 0, 
41 42
	    *default_charset = (char *)MYSQL_DEFAULT_CHARSET_NAME,
	    *current_host = 0;
43
static int first_error = 0;
unknown's avatar
unknown committed
44
DYNAMIC_ARRAY tables4repair;
45 46 47 48
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
#endif
static uint opt_protocol=0;
49
static CHARSET_INFO *charset_info= &my_charset_latin1;
50 51 52

enum operations {DO_CHECK, DO_REPAIR, DO_ANALYZE, DO_OPTIMIZE};

53
static struct my_option my_long_options[] =
54
{
55 56 57 58 59 60 61
  {"all-databases", 'A',
   "Check all the databases. This will be same as  --databases with all databases selected.",
   (gptr*) &opt_alldbs, (gptr*) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
   0, 0},
  {"analyze", 'a', "Analyze given tables.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
   0, 0, 0, 0},
  {"all-in-1", '1',
unknown's avatar
unknown committed
62
   "Instead of issuing one query for each table, use one query per database, naming all tables in the database in a comma-separated list.",
63 64 65 66 67 68 69
   (gptr*) &opt_all_in_1, (gptr*) &opt_all_in_1, 0, GET_BOOL, NO_ARG, 0, 0, 0,
   0, 0, 0},
  {"auto-repair", OPT_AUTO_REPAIR,
   "If a checked table is corrupted, automatically fix it. Repairing will be done after all tables have been checked, if corrupted ones were found.",
   (gptr*) &opt_auto_repair, (gptr*) &opt_auto_repair, 0, GET_BOOL, NO_ARG, 0,
   0, 0, 0, 0, 0},
  {"character-sets-dir", OPT_CHARSETS_DIR,
70
   "Directory where character sets are.", (gptr*) &charsets_dir,
71
   (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
72
  {"check", 'c', "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
73 74 75 76 77 78 79 80 81 82 83
   0, 0, 0, 0},
  {"check-only-changed", 'C',
   "Check only tables that have changed since last check or haven't been closed properly.",
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"compress", OPT_COMPRESS, "Use compression in server/client protocol.",
   (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
   0, 0, 0},
  {"databases", 'B',
   "To check several databases. Note the difference in usage; In this case no tables are given. All name arguments are regarded as databasenames.",
   (gptr*) &opt_databases, (gptr*) &opt_databases, 0, GET_BOOL, NO_ARG,
   0, 0, 0, 0, 0, 0},
84
  {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
85 86
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
  {"default-character-set", OPT_DEFAULT_CHARSET,
87
   "Set the default character set.", (gptr*) &default_charset,
88
   (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
89
  {"fast",'F', "Check only tables that haven't been closed properly.",
90 91 92 93 94 95
   (gptr*) &opt_fast, (gptr*) &opt_fast, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
   0},
  {"force", 'f', "Continue even if we get an sql-error.",
   (gptr*) &ignore_errors, (gptr*) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
   0, 0, 0, 0},
  {"extended", 'e',
unknown's avatar
unknown committed
96
   "If you are using this option with CHECK TABLE, it will ensure that the table is 100 percent consistent, but will take a long time. If you are using this option with REPAIR TABLE, it will force using old slow repair with keycache method, instead of much faster repair by sorting.",
97 98 99 100 101
   (gptr*) &opt_extended, (gptr*) &opt_extended, 0, GET_BOOL, NO_ARG, 0, 0, 0,
   0, 0, 0},
  {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
  {"host",'h', "Connect to host.", (gptr*) &current_host,
102
   (gptr*) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
103 104 105 106 107 108 109 110
  {"medium-check", 'm',
   "Faster than extended-check, but only finds 99.99 percent of all errors. Should be good enough for most cases.",
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"optimize", 'o', "Optimize table.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0,
   0, 0},
  {"password", 'p',
   "Password to use when connecting to server. If password is not given it's solicited on the tty.",
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
111
#ifdef __WIN__
112 113
  {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
114
#endif
115 116 117
  {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
   (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
   0},
118
  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
119
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
120 121 122 123 124 125 126
  {"quick", 'q',
   "If you are using this option with CHECK TABLE, it prevents the check from scanning the rows to check for wrong links. This is the fastest check. If you are using this option with REPAIR TABLE, it will try to repair only the index tree. This is the fastest repair method for a table.",
   (gptr*) &opt_quick, (gptr*) &opt_quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
   0},
  {"repair", '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},
127 128
#ifdef HAVE_SMEM
  {"shared_memory_base_name", OPT_SHARED_MEMORY_BASE_NAME,
129
   "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name,
130 131
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
132 133 134 135 136
  {"silent", 's', "Print only error messages.", (gptr*) &opt_silent,
   (gptr*) &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"socket", 'S', "Socket file to use for connection.",
   (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR,
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
137
#include <sslopt-longopts.h>
138 139
  {"tables", OPT_TABLES, "Overrides option --databases (-B).", 0, 0, 0,
   GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
140
#ifndef DONT_ALLOW_USER_CHANGE
141 142
  {"user", 'u', "User for login if not current user.", (gptr*) &current_user,
   (gptr*) &current_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
143
#endif
unknown's avatar
unknown committed
144 145 146 147
  {"use-frm", OPT_FRM,
   "When used with REPAIR, get table structure from .frm file, so the table can be repaired even if .MYI header is corrupted.",
   (gptr*) &opt_frm, (gptr*) &opt_frm, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
   0},
148 149 150 151 152
  {"verbose", 'v', "Print info about the various stages.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
153
};
unknown's avatar
unknown committed
154

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
static const char *load_default_groups[] = { "mysqlcheck", "client", 0 };


static void print_version(void);
static void usage(void);
static int get_options(int *argc, char ***argv);
static int process_all_databases();
static int process_databases(char **db_names);
static int process_selected_tables(char *db, char **table_names, int tables);
static int process_all_tables_in_db(char *database);
static int use_db(char *database);
static int handle_request_for_tables(char *tables, uint length);
static int dbConnect(char *host, char *user,char *passwd);
static void dbDisconnect(char *host);
static void DBerror(MYSQL *mysql, const char *when);
static void safe_exit(int error);
static void print_result();
unknown's avatar
unknown committed
172
static char *fix_table_name(char *dest, char *src);
173 174 175 176 177 178 179 180 181 182 183 184 185
int what_to_do = 0;

static void print_version(void)
{
  printf("%s  Ver %s Distrib %s, for %s (%s)\n", my_progname, CHECK_VERSION,
   MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
} /* print_version */


static void usage(void)
{
  print_version();
  puts("By Jani Tolonen, 2001-04-20, MySQL Development Team\n");
186 187
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n");
  puts("and you are welcome to modify and redistribute it under the GPL license.\n");
188 189
  puts("This program can be used to CHECK (-c,-m,-C), REPAIR (-r), ANALYZE (-a)");
  puts("or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be");
unknown's avatar
unknown committed
190
  puts("used at the same time. It works on MyISAM and in some cases on BDB tables.");
191
  puts("Please consult the MySQL manual for latest information about the");
unknown's avatar
unknown committed
192 193 194 195 196 197 198 199
  puts("above. The options -c,-r,-a and -o are exclusive to each other, which");
  puts("means that the last option will be used, if several was specified.\n");
  puts("The option -c will be used by default, if none was specified. You");
  puts("can change the default behavior by making a symbolic link, or");
  puts("copying this file somewhere with another name, the alternatives are:");
  puts("mysqlrepair:   The default option will be -r");
  puts("mysqlanalyze:  The default option will be -a");
  puts("mysqloptimize: The default option will be -o\n");
200 201 202 203 204
  printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
  printf("OR     %s [OPTIONS] --databases DB1 [DB2 DB3...]\n",
	 my_progname);
  printf("OR     %s [OPTIONS] --all-databases\n", my_progname);
  print_defaults("my", load_default_groups);
205 206
  my_print_help(my_long_options);
  my_print_variables(my_long_options);
207 208
} /* usage */

unknown's avatar
unknown committed
209

210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
	       char *argument)
{
  switch(optid) {
  case 'a':
    what_to_do = DO_ANALYZE;
    break;
  case 'c':
    what_to_do = DO_CHECK;
    break;
  case 'C':
    what_to_do = DO_CHECK;
    opt_check_only_changed = 1;
    break;
  case 'I': /* Fall through */
  case '?':
    usage();
    exit(0);
  case 'm':
    what_to_do = DO_CHECK;
    opt_medium_check = 1;
    break;
  case 'o':
    what_to_do = DO_OPTIMIZE;
    break;
  case 'p':
    if (argument)
    {
      char *start = argument;
      my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
      opt_password = my_strdup(argument, MYF(MY_FAE));
      while (*argument) *argument++= 'x';		/* Destroy argument */
      if (*start)
unknown's avatar
unknown committed
244
	start[1] = 0;                             /* Cut length of argument */
245 246 247 248 249 250 251 252 253
    }
    else
      tty_password = 1;
    break;
  case 'r':
    what_to_do = DO_REPAIR;
    break;
  case 'W':
#ifdef __WIN__
254
    opt_protocol = MYSQL_PROTOCOL_PIPE;
255 256 257 258 259
#endif
    break;
  case '#':
    DBUG_PUSH(argument ? argument : "d:t:o");
    break;
260
#include <sslopt-case.h>
261 262 263 264 265 266 267
  case OPT_TABLES:
    opt_databases = 0;
    break;
  case 'v':
    verbose++;
    break;
  case 'V': print_version(); exit(0);
268 269 270 271 272 273 274 275 276
  case OPT_MYSQL_PROTOCOL:
  {
    if ((opt_protocol = find_type(argument, &sql_protocol_typelib,0)) == ~(ulong) 0)
    {
      fprintf(stderr, "Unknown option to protocol: %s\n", argument);
      exit(1);
    }
    break;
  }
277 278 279 280 281
  }
  return 0;
}


282 283
static int get_options(int *argc, char ***argv)
{
284
  int ho_error;
285

unknown's avatar
unknown committed
286 287 288 289 290 291
  if (*argc == 1)
  {
    usage();
    exit(0);
  }

292
  load_defaults("my", load_default_groups, argc, argv);
293 294

  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
295
    exit(ho_error);
296

297
  if (!what_to_do)
unknown's avatar
unknown committed
298 299 300
  {
    int pnlen = strlen(my_progname);

301
    if (pnlen < 6) /* name too short */
unknown's avatar
unknown committed
302 303 304 305 306 307 308 309 310 311
      what_to_do = DO_CHECK;
    else if (!strcmp("repair", my_progname + pnlen - 6))
      what_to_do = DO_REPAIR;
    else if (!strcmp("analyze", my_progname + pnlen - 7))
      what_to_do = DO_ANALYZE;
    else if  (!strcmp("optimize", my_progname + pnlen - 8))
      what_to_do = DO_OPTIMIZE;
    else
      what_to_do = DO_CHECK;
  }
unknown's avatar
unknown committed
312 313

  /* TODO: This variable is not yet used */
314 315
  if (strcmp(default_charset, charset_info->csname) &&
      !(charset_info= get_charset_by_csname(default_charset, 
316
  					    MY_CS_PRIMARY, MYF(MY_WME))))
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
      exit(1);
  if (*argc > 0 && opt_alldbs)
  {
    printf("You should give only options, no arguments at all, with option\n");
    printf("--all-databases. Please see %s --help for more information.\n",
	   my_progname);
    return 1;
  }
  if (*argc < 1 && !opt_alldbs)
  {
    printf("You forgot to give the arguments! Please see %s --help\n",
	   my_progname);
    printf("for more information.\n");
    return 1;
  }
  if (tty_password)
    opt_password = get_tty_password(NullS);
  return(0);
} /* get_options */


static int process_all_databases()
{
  MYSQL_ROW row;
  MYSQL_RES *tableres;
  int result = 0;

  if (mysql_query(sock, "SHOW DATABASES") ||
      !(tableres = mysql_store_result(sock)))
  {
    my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
		    MYF(0), mysql_error(sock));
    return 1;
  }
  while ((row = mysql_fetch_row(tableres)))
  {
    if (process_all_tables_in_db(row[0]))
      result = 1;
  }
  return result;
}
/* process_all_databases */


static int process_databases(char **db_names)
{
  int result = 0;
  for ( ; *db_names ; db_names++)
  {
    if (process_all_tables_in_db(*db_names))
      result = 1;
  }
  return result;
} /* process_databases */


static int process_selected_tables(char *db, char **table_names, int tables)
{
  if (use_db(db))
    return 1;
  if (opt_all_in_1)
  {
379 380 381 382 383
    /* 
      We need table list in form `a`, `b`, `c`
      that's why we need 4 more chars added to to each table name
      space is for more readable output in logs and in case of error
    */	  
384 385 386 387
    char *table_names_comma_sep, *end;
    int i, tot_length = 0;

    for (i = 0; i < tables; i++)
388
      tot_length += strlen(*(table_names + i)) + 4;
unknown's avatar
unknown committed
389

390
    if (!(table_names_comma_sep = (char *)
391
	  my_malloc((sizeof(char) * tot_length) + 4, MYF(MY_WME))))
392 393 394 395 396
      return 1;

    for (end = table_names_comma_sep + 1; tables > 0;
	 tables--, table_names++)
    {
unknown's avatar
unknown committed
397 398
      end= fix_table_name(end, *table_names);
      *end++= ',';
399 400 401 402 403 404 405 406 407 408 409 410
    }
    *--end = 0;
    handle_request_for_tables(table_names_comma_sep + 1, tot_length - 1);
    my_free(table_names_comma_sep, MYF(0));
  }
  else
    for (; tables > 0; tables--, table_names++)
      handle_request_for_tables(*table_names, strlen(*table_names));
  return 0;
} /* process_selected_tables */


unknown's avatar
unknown committed
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
static char *fix_table_name(char *dest, char *src)
{
  char *db_sep;

  *dest++= '`';
  if ((db_sep= strchr(src, '.')))
  {
    dest= strmake(dest, src, (uint) (db_sep - src));
    dest= strmov(dest, "`.`");
    src= db_sep + 1;
  }
  dest= strxmov(dest, src, "`", NullS);
  return dest;
}


427 428 429 430 431 432 433 434 435 436 437
static int process_all_tables_in_db(char *database)
{
  MYSQL_RES *res;
  MYSQL_ROW row;

  LINT_INIT(res);
  if (use_db(database))
    return 1;
  if (!(mysql_query(sock, "SHOW TABLES") ||
	(res = mysql_store_result(sock))))
    return 1;
unknown's avatar
unknown committed
438

439 440
  if (opt_all_in_1)
  {
441 442 443 444 445 446
    /* 
      We need table list in form `a`, `b`, `c`
      that's why we need 4 more chars added to to each table name
      space is for more readable output in logs and in case of error
     */
	  
447 448 449 450
    char *tables, *end;
    uint tot_length = 0;

    while ((row = mysql_fetch_row(res)))
451
      tot_length += strlen(row[0]) + 4;
452
    mysql_data_seek(res, 0);
unknown's avatar
unknown committed
453

454
    if (!(tables=(char *) my_malloc(sizeof(char)*tot_length+4, MYF(MY_WME))))
455 456 457 458 459 460
    {
      mysql_free_result(res);
      return 1;
    }
    for (end = tables + 1; (row = mysql_fetch_row(res)) ;)
    {
unknown's avatar
unknown committed
461 462
      end= fix_table_name(end, row[0]);
      *end++= ',';
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
    }
    *--end = 0;
    if (tot_length)
      handle_request_for_tables(tables + 1, tot_length - 1);
    my_free(tables, MYF(0));
  }
  else
  {
    while ((row = mysql_fetch_row(res)))
      handle_request_for_tables(row[0], strlen(row[0]));
  }
  mysql_free_result(res);
  return 0;
} /* process_all_tables_in_db */


static int use_db(char *database)
{
  if (mysql_select_db(sock, database))
  {
    DBerror(sock, "when selecting the database");
    return 1;
  }
  return 0;
} /* use_db */


static int handle_request_for_tables(char *tables, uint length)
{
492
  char *query, *end, options[100], message[100];
unknown's avatar
unknown committed
493
  uint query_length= 0;
494 495 496
  const char *op = 0;

  options[0] = 0;
497
  end = options;
498 499 500
  switch (what_to_do) {
  case DO_CHECK:
    op = "CHECK";
501 502 503 504 505
    if (opt_quick)              end = strmov(end, " QUICK");
    if (opt_fast)               end = strmov(end, " FAST");
    if (opt_medium_check)       end = strmov(end, " MEDIUM"); /* Default */
    if (opt_extended)           end = strmov(end, " EXTENDED");
    if (opt_check_only_changed) end = strmov(end, " CHANGED");
506 507 508
    break;
  case DO_REPAIR:
    op = "REPAIR";
509 510
    if (opt_quick)              end = strmov(end, " QUICK");
    if (opt_extended)           end = strmov(end, " EXTENDED");
unknown's avatar
unknown committed
511
    if (opt_frm)                end = strmov(end, " USE_FRM");
512 513 514 515 516 517 518 519 520 521 522
    break;
  case DO_ANALYZE:
    op = "ANALYZE";
    break;
  case DO_OPTIMIZE:
    op = "OPTIMIZE";
    break;
  }

  if (!(query =(char *) my_malloc((sizeof(char)*(length+110)), MYF(MY_WME))))
    return 1;
523
  if (opt_all_in_1)
unknown's avatar
unknown committed
524
  {
525
    /* No backticks here as we added them before */
unknown's avatar
unknown committed
526 527 528
    query_length= my_sprintf(query,
			     (query, "%s TABLE %s %s", op, tables, options));
  }
529
  else
unknown's avatar
unknown committed
530 531 532 533 534 535 536 537 538
  {
    char *ptr;

    ptr= strmov(strmov(query, op), " TABLE ");
    ptr= fix_table_name(ptr, tables);
    ptr= strxmov(ptr, " ", options, NullS);
    query_length= (uint) (ptr - query);
  }
  if (mysql_real_query(sock, query, query_length))
539
  {
540
    sprintf(message, "when executing '%s TABLE ... %s'", op, options);
541
    DBerror(sock, message);
542 543 544 545 546 547 548 549 550 551 552 553
    return 1;
  }
  print_result();
  my_free(query, MYF(0));
  return 0;
}


static void print_result()
{
  MYSQL_RES *res;
  MYSQL_ROW row;
unknown's avatar
unknown committed
554
  char prev[NAME_LEN*2+2];
555 556
  uint i;
  my_bool found_error=0;
557 558 559 560 561

  res = mysql_use_result(sock);
  prev[0] = '\0';
  for (i = 0; (row = mysql_fetch_row(res)); i++)
  {
562
    int changed = strcmp(prev, row[0]);
563 564 565 566
    my_bool status = !strcmp(row[2], "status");

    if (status)
    {
567 568 569
      if (found_error && opt_auto_repair && what_to_do != DO_REPAIR &&
	  (!opt_fast || strcmp(row[3],"OK")))
	insert_dynamic(&tables4repair, prev);
570 571 572 573
      found_error=0;
      if (opt_silent)
	continue;
    }
574 575 576
    if (status && changed)
      printf("%-50s %s", row[0], row[3]);
    else if (!status && changed)
unknown's avatar
unknown committed
577
    {
578
      printf("%s\n%-9s: %s", row[0], row[2], row[3]);
579 580
      if (strcmp(row[2],"note"))
	found_error=1;
unknown's avatar
unknown committed
581
    }
582 583 584
    else
      printf("%-9s: %s", row[2], row[3]);
    strmov(prev, row[0]);
585
    putchar('\n');
586
  }
587 588 589
  if (found_error && opt_auto_repair && what_to_do != DO_REPAIR &&
      (!opt_fast || strcmp(row[3],"OK")))
    insert_dynamic(&tables4repair, prev);
590 591 592 593
  mysql_free_result(res);
}


594
static int dbConnect(char *host, char *user, char *passwd)
595 596 597 598 599 600 601 602 603 604 605 606
{
  DBUG_ENTER("dbConnect");
  if (verbose)
  {
    fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost");
  }
  mysql_init(&mysql_connection);
  if (opt_compress)
    mysql_options(&mysql_connection, MYSQL_OPT_COMPRESS, NullS);
#ifdef HAVE_OPENSSL
  if (opt_use_ssl)
    mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
607
		  opt_ssl_capath, opt_ssl_cipher);
608 609 610 611 612 613
#endif
  if (opt_protocol)
    mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
#ifdef HAVE_SMEM
  if (shared_memory_base_name)
    mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
#endif
  if (!(sock = mysql_real_connect(&mysql_connection, host, user, passwd,
         NULL, opt_mysql_port, opt_mysql_unix_port, 0)))
  {
    DBerror(&mysql_connection, "when trying to connect");
    return 1;
  }
  return 0;
} /* dbConnect */


static void dbDisconnect(char *host)
{
  if (verbose)
    fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
  mysql_close(sock);
} /* dbDisconnect */


static void DBerror(MYSQL *mysql, const char *when)
{
  DBUG_ENTER("DBerror");
  my_printf_error(0,"Got error: %d: %s %s", MYF(0),
		  mysql_errno(mysql), mysql_error(mysql), when);
  safe_exit(EX_MYSQLERR);
  DBUG_VOID_RETURN;
} /* DBerror */


static void safe_exit(int error)
{
  if (!first_error)
    first_error= error;
  if (ignore_errors)
    return;
  if (sock)
    mysql_close(sock);
  exit(error);
}


int main(int argc, char **argv)
{
  MY_INIT(argv[0]);
  /*
  ** Check out the args
  */
  if (get_options(&argc, &argv))
  {
    my_end(0);
    exit(EX_USAGE);
  }
  if (dbConnect(current_host, current_user, opt_password))
    exit(EX_MYSQLERR);

669 670
  if (opt_auto_repair &&
      my_init_dynamic_array(&tables4repair, sizeof(char)*(NAME_LEN*2+2),16,64))
unknown's avatar
unknown committed
671 672 673 674 675
  {
    first_error = 1;
    goto end;
  }

676 677 678 679 680 681 682 683
  if (opt_alldbs)
    process_all_databases();
  /* Only one database and selected table(s) */
  else if (argc > 1 && !opt_databases)
    process_selected_tables(*argv, (argv + 1), (argc - 1));
  /* One or more databases, all tables */
  else
    process_databases(argv);
unknown's avatar
unknown committed
684 685 686 687 688 689 690 691 692 693 694 695 696 697
  if (opt_auto_repair)
  {
    uint i;

    if (!opt_silent && tables4repair.elements)
      puts("\nRepairing tables");
    what_to_do = DO_REPAIR;
    for (i = 0; i < tables4repair.elements ; i++)
    {
      char *name= (char*) dynamic_array_ptr(&tables4repair, i);
      handle_request_for_tables(name, strlen(name));
    }
  }
 end:
698
  dbDisconnect(current_host);
unknown's avatar
unknown committed
699 700
  if (opt_auto_repair)
    delete_dynamic(&tables4repair);
701
  my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
702 703 704
#ifdef HAVE_SMEM
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
#endif
705
  my_end(0);
unknown's avatar
unknown committed
706
  return(first_error!=0);
707
} /* main */