~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/* By Jani Tolonen, 2001-04-20, MySQL Development Team */
17
18
#define CHECK_VERSION "2.5.0"
19
20
#include "client_priv.h"
21
#include <m_ctype.h>
22
#include <mysql_version.h>
23
#include <mysqld_error.h>
24
25
/* Exit codes */
26
27
#define EX_USAGE 1
28
#define EX_MYSQLERR 2
29
30
static MYSQL mysql_connection, *sock = 0;
31
static my_bool opt_alldbs = 0, opt_check_only_changed = 0, opt_extended = 0,
32
               opt_compress = 0, opt_databases = 0, opt_fast = 0,
33
               opt_medium_check = 0, opt_quick = 0, opt_all_in_1 = 0,
34
               opt_silent = 0, opt_auto_repair = 0, ignore_errors = 0,
35
               tty_password= 0, opt_frm= 0, debug_info_flag= 0, debug_check_flag= 0,
36
               opt_fix_table_names= 0, opt_fix_db_names= 0, opt_upgrade= 0,
37
               opt_write_binlog= 1;
38
static uint verbose = 0, opt_mysql_port=0;
39
static int my_end_arg;
40
static char * opt_mysql_unix_port = 0;
41
static char *opt_password = 0, *current_user = 0, 
42
	    *default_charset = (char *)MYSQL_DEFAULT_CHARSET_NAME,
43
	    *current_host = 0;
44
static int first_error = 0;
45
DYNAMIC_ARRAY tables4repair;
46
#ifdef HAVE_SMEM
47
static char *shared_memory_base_name=0;
48
#endif
49
static uint opt_protocol=0;
50
static CHARSET_INFO *charset_info= &my_charset_latin1;
51
52
enum operations { DO_CHECK, DO_REPAIR, DO_ANALYZE, DO_OPTIMIZE, DO_UPGRADE };
53
54
static struct my_option my_long_options[] =
55
{
56
  {"all-databases", 'A',
57
   "Check all the databases. This will be same as  --databases with all databases selected.",
58
   (uchar**) &opt_alldbs, (uchar**) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
59
   0, 0},
60
  {"analyze", 'a', "Analyze given tables.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
61
   0, 0, 0, 0},
62
  {"all-in-1", '1',
63
   "Instead of issuing one query for each table, use one query per database, naming all tables in the database in a comma-separated list.",
64
   (uchar**) &opt_all_in_1, (uchar**) &opt_all_in_1, 0, GET_BOOL, NO_ARG, 0, 0, 0,
65
   0, 0, 0},
66
  {"auto-repair", OPT_AUTO_REPAIR,
67
   "If a checked table is corrupted, automatically fix it. Repairing will be done after all tables have been checked, if corrupted ones were found.",
68
   (uchar**) &opt_auto_repair, (uchar**) &opt_auto_repair, 0, GET_BOOL, NO_ARG, 0,
69
   0, 0, 0, 0, 0},
70
  {"character-sets-dir", OPT_CHARSETS_DIR,
71
   "Directory where character sets are.", (uchar**) &charsets_dir,
72
   (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
73
  {"check", 'c', "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
74
   0, 0, 0, 0},
75
  {"check-only-changed", 'C',
76
   "Check only tables that have changed since last check or haven't been closed properly.",
77
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
78
  {"check-upgrade", 'g',
79
   "Check tables for version-dependent changes. May be used with --auto-repair to correct tables requiring version-dependent updates.",
80
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
81
  {"compress", OPT_COMPRESS, "Use compression in server/client protocol.",
82
   (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
83
   0, 0, 0},
84
  {"databases", 'B',
85
   "To check several databases. Note the difference in usage; In this case no tables are given. All name arguments are regarded as databasenames.",
86
   (uchar**) &opt_databases, (uchar**) &opt_databases, 0, GET_BOOL, NO_ARG,
87
   0, 0, 0, 0, 0, 0},
88
#ifdef DBUG_OFF
89
  {"debug", '#', "This is a non-debug version. Catch this and exit.",
90
   0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
91
#else
92
  {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
93
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
94
#endif
95
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
96
   (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0,
97
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
98
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
99
   (uchar**) &debug_info_flag, (uchar**) &debug_info_flag,
100
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
101
  {"default-character-set", OPT_DEFAULT_CHARSET,
102
   "Set the default character set.", (uchar**) &default_charset,
103
   (uchar**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
104
  {"fast",'F', "Check only tables that haven't been closed properly.",
105
   (uchar**) &opt_fast, (uchar**) &opt_fast, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
106
   0},
107
  {"fix-db-names", OPT_FIX_DB_NAMES, "Fix database names.",
108
    (uchar**) &opt_fix_db_names, (uchar**) &opt_fix_db_names,
109
    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
110
  {"fix-table-names", OPT_FIX_TABLE_NAMES, "Fix table names.",
111
    (uchar**) &opt_fix_table_names, (uchar**) &opt_fix_table_names,
112
    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
113
  {"force", 'f', "Continue even if we get an sql-error.",
114
   (uchar**) &ignore_errors, (uchar**) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
115
   0, 0, 0, 0},
116
  {"extended", 'e',
117
   "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.",
118
   (uchar**) &opt_extended, (uchar**) &opt_extended, 0, GET_BOOL, NO_ARG, 0, 0, 0,
119
   0, 0, 0},
120
  {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
121
   NO_ARG, 0, 0, 0, 0, 0, 0},
122
  {"host",'h', "Connect to host.", (uchar**) &current_host,
123
   (uchar**) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
124
  {"medium-check", 'm',
125
   "Faster than extended-check, but only finds 99.99 percent of all errors. Should be good enough for most cases.",
126
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
127
  {"write-binlog", OPT_WRITE_BINLOG,
128
   "Log ANALYZE, OPTIMIZE and REPAIR TABLE commands. Use --skip-write-binlog when commands should not be sent to replication slaves.",
129
   (uchar**) &opt_write_binlog, (uchar**) &opt_write_binlog, 0, GET_BOOL, NO_ARG,
130
   1, 0, 0, 0, 0, 0},
131
  {"optimize", 'o', "Optimize table.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0,
132
   0, 0},
133
  {"password", 'p',
134
   "Password to use when connecting to server. If password is not given it's solicited on the tty.",
135
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
136
  {"port", 'P', "Port number to use for connection or 0 for default to, in "
137
   "order of preference, my.cnf, $MYSQL_TCP_PORT, "
138
#if MYSQL_PORT_DEFAULT == 0
139
   "/etc/services, "
140
#endif
141
   "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
142
   (uchar**) &opt_mysql_port,
143
   (uchar**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
144
   0},
145
  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
146
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
147
  {"quick", 'q',
148
   "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.",
149
   (uchar**) &opt_quick, (uchar**) &opt_quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
150
   0},
151
  {"repair", 'r',
152
   "Can fix almost anything except unique keys that aren't unique.",
153
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
154
#ifdef HAVE_SMEM
155
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
156
   "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name,
157
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
158
#endif
159
  {"silent", 's', "Print only error messages.", (uchar**) &opt_silent,
160
   (uchar**) &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
161
  {"socket", 'S', "Socket file to use for connection.",
162
   (uchar**) &opt_mysql_unix_port, (uchar**) &opt_mysql_unix_port, 0, GET_STR,
163
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
164
  {"tables", OPT_TABLES, "Overrides option --databases (-B).", 0, 0, 0,
165
   GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
166
  {"use-frm", OPT_FRM,
167
   "When used with REPAIR, get table structure from .frm file, so the table can be repaired even if .MYI header is corrupted.",
168
   (uchar**) &opt_frm, (uchar**) &opt_frm, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
169
   0},
170
#ifndef DONT_ALLOW_USER_CHANGE
171
  {"user", 'u', "User for login if not current user.", (uchar**) &current_user,
172
   (uchar**) &current_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
173
#endif
174
  {"verbose", 'v', "Print info about the various stages.", 0, 0, 0, GET_NO_ARG,
175
   NO_ARG, 0, 0, 0, 0, 0, 0},
176
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
177
   NO_ARG, 0, 0, 0, 0, 0, 0},
178
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
179
};
180
181
static const char *load_default_groups[] = { "mysqlcheck", "client", 0 };
182
183
184
static void print_version(void);
185
static void usage(void);
186
static int get_options(int *argc, char ***argv);
187
static int process_all_databases();
188
static int process_databases(char **db_names);
189
static int process_selected_tables(char *db, char **table_names, int tables);
190
static int process_all_tables_in_db(char *database);
191
static int process_one_db(char *database);
192
static int use_db(char *database);
193
static int handle_request_for_tables(char *tables, uint length);
194
static int dbConnect(char *host, char *user,char *passwd);
195
static void dbDisconnect(char *host);
196
static void DBerror(MYSQL *mysql, const char *when);
197
static void safe_exit(int error);
198
static void print_result();
199
static uint fixed_name_length(const char *name);
200
static char *fix_table_name(char *dest, char *src);
201
int what_to_do = 0;
202
203
#include <help_start.h>
204
205
static void print_version(void)
206
{
207
  printf("%s  Ver %s Distrib %s, for %s (%s)\n", my_progname, CHECK_VERSION,
208
   MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
209
} /* print_version */
210
211
212
static void usage(void)
213
{
214
  print_version();
215
  puts("By Jani Tolonen, 2001-04-20, MySQL Development Team\n");
216
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n");
217
  puts("and you are welcome to modify and redistribute it under the GPL license.\n");
218
  puts("This program can be used to CHECK (-c,-m,-C), REPAIR (-r), ANALYZE (-a)");
219
  puts("or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be");
220
  puts("used at the same time. Not all options are supported by all storage engines.");
221
  puts("Please consult the MySQL manual for latest information about the");
222
  puts("above. The options -c,-r,-a and -o are exclusive to each other, which");
223
  puts("means that the last option will be used, if several was specified.\n");
224
  puts("The option -c will be used by default, if none was specified. You");
225
  puts("can change the default behavior by making a symbolic link, or");
226
  puts("copying this file somewhere with another name, the alternatives are:");
227
  puts("mysqlrepair:   The default option will be -r");
228
  puts("mysqlanalyze:  The default option will be -a");
229
  puts("mysqloptimize: The default option will be -o\n");
230
  printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
231
  printf("OR     %s [OPTIONS] --databases DB1 [DB2 DB3...]\n",
232
	 my_progname);
233
  printf("OR     %s [OPTIONS] --all-databases\n", my_progname);
234
  print_defaults("my", load_default_groups);
235
  my_print_help(my_long_options);
236
  my_print_variables(my_long_options);
237
} /* usage */
238
239
#include <help_end.h>
240
241
static my_bool
242
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
243
	       char *argument)
244
{
245
  switch(optid) {
246
  case 'a':
247
    what_to_do = DO_ANALYZE;
248
    break;
249
  case 'c':
250
    what_to_do = DO_CHECK;
251
    break;
252
  case 'C':
253
    what_to_do = DO_CHECK;
254
    opt_check_only_changed = 1;
255
    break;
256
  case 'I': /* Fall through */
257
  case '?':
258
    usage();
259
    exit(0);
260
  case 'm':
261
    what_to_do = DO_CHECK;
262
    opt_medium_check = 1;
263
    break;
264
  case 'o':
265
    what_to_do = DO_OPTIMIZE;
266
    break;
267
  case OPT_FIX_DB_NAMES:
268
    what_to_do= DO_UPGRADE;
269
    default_charset= (char*) "utf8";
270
    opt_databases= 1;
271
    break;
272
  case OPT_FIX_TABLE_NAMES:
273
    what_to_do= DO_UPGRADE;
274
    default_charset= (char*) "utf8";
275
    break;
276
  case 'p':
277
    if (argument)
278
    {
279
      char *start = argument;
280
      my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
281
      opt_password = my_strdup(argument, MYF(MY_FAE));
282
      while (*argument) *argument++= 'x';		/* Destroy argument */
283
      if (*start)
284
	start[1] = 0;                             /* Cut length of argument */
285
      tty_password= 0;
286
    }
287
    else
288
      tty_password = 1;
289
    break;
290
  case 'r':
291
    what_to_do = DO_REPAIR;
292
    break;
293
  case 'g':
294
    what_to_do= DO_CHECK;
295
    opt_upgrade= 1;
296
    break;
297
  case '#':
298
    DBUG_PUSH(argument ? argument : "d:t:o");
299
    debug_check_flag= 1;
300
    break;
301
  case OPT_TABLES:
302
    opt_databases = 0;
303
    break;
304
  case 'v':
305
    verbose++;
306
    break;
307
  case 'V': print_version(); exit(0);
308
  case OPT_MYSQL_PROTOCOL:
309
    opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
310
                                    opt->name);
311
    break;
312
  }
313
  return 0;
314
}
315
316
317
static int get_options(int *argc, char ***argv)
318
{
319
  int ho_error;
320
321
  if (*argc == 1)
322
  {
323
    usage();
324
    exit(0);
325
  }
326
327
  load_defaults("my", load_default_groups, argc, argv);
328
329
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
330
    exit(ho_error);
331
332
  if (!what_to_do)
333
  {
334
    int pnlen = strlen(my_progname);
335
336
    if (pnlen < 6) /* name too short */
337
      what_to_do = DO_CHECK;
338
    else if (!strcmp("repair", my_progname + pnlen - 6))
339
      what_to_do = DO_REPAIR;
340
    else if (!strcmp("analyze", my_progname + pnlen - 7))
341
      what_to_do = DO_ANALYZE;
342
    else if  (!strcmp("optimize", my_progname + pnlen - 8))
343
      what_to_do = DO_OPTIMIZE;
344
    else
345
      what_to_do = DO_CHECK;
346
  }
347
348
  /* TODO: This variable is not yet used */
349
  if (strcmp(default_charset, charset_info->csname) &&
350
      !(charset_info= get_charset_by_csname(default_charset, 
351
  					    MY_CS_PRIMARY, MYF(MY_WME))))
352
      exit(1);
353
  if (*argc > 0 && opt_alldbs)
354
  {
355
    printf("You should give only options, no arguments at all, with option\n");
356
    printf("--all-databases. Please see %s --help for more information.\n",
357
	   my_progname);
358
    return 1;
359
  }
360
  if (*argc < 1 && !opt_alldbs)
361
  {
362
    printf("You forgot to give the arguments! Please see %s --help\n",
363
	   my_progname);
364
    printf("for more information.\n");
365
    return 1;
366
  }
367
  if (tty_password)
368
    opt_password = get_tty_password(NullS);
369
  if (debug_info_flag)
370
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
371
  if (debug_check_flag)
372
    my_end_arg= MY_CHECK_ERROR;
373
  return(0);
374
} /* get_options */
375
376
377
static int process_all_databases()
378
{
379
  MYSQL_ROW row;
380
  MYSQL_RES *tableres;
381
  int result = 0;
382
383
  if (mysql_query(sock, "SHOW DATABASES") ||
384
      !(tableres = mysql_store_result(sock)))
385
  {
386
    my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
387
		    MYF(0), mysql_error(sock));
388
    return 1;
389
  }
390
  while ((row = mysql_fetch_row(tableres)))
391
  {
392
    if (process_one_db(row[0]))
393
      result = 1;
394
  }
395
  return result;
396
}
397
/* process_all_databases */
398
399
400
static int process_databases(char **db_names)
401
{
402
  int result = 0;
403
  for ( ; *db_names ; db_names++)
404
  {
405
    if (process_one_db(*db_names))
406
      result = 1;
407
  }
408
  return result;
409
} /* process_databases */
410
411
412
static int process_selected_tables(char *db, char **table_names, int tables)
413
{
414
  if (use_db(db))
415
    return 1;
416
  if (opt_all_in_1)
417
  {
418
    /* 
419
      We need table list in form `a`, `b`, `c`
420
      that's why we need 2 more chars added to to each table name
421
      space is for more readable output in logs and in case of error
422
    */	  
423
    char *table_names_comma_sep, *end;
424
    int i, tot_length = 0;
425
426
    for (i = 0; i < tables; i++)
427
      tot_length+= fixed_name_length(*(table_names + i)) + 2;
428
429
    if (!(table_names_comma_sep = (char *)
430
	  my_malloc((sizeof(char) * tot_length) + 4, MYF(MY_WME))))
431
      return 1;
432
433
    for (end = table_names_comma_sep + 1; tables > 0;
434
	 tables--, table_names++)
435
    {
436
      end= fix_table_name(end, *table_names);
437
      *end++= ',';
438
    }
439
    *--end = 0;
440
    handle_request_for_tables(table_names_comma_sep + 1, tot_length - 1);
441
    my_free(table_names_comma_sep, MYF(0));
442
  }
443
  else
444
    for (; tables > 0; tables--, table_names++)
445
      handle_request_for_tables(*table_names, fixed_name_length(*table_names));
446
  return 0;
447
} /* process_selected_tables */
448
449
450
static uint fixed_name_length(const char *name)
451
{
452
  const char *p;
453
  uint extra_length= 2;  /* count the first/last backticks */
454
  
455
  for (p= name; *p; p++)
456
  {
457
    if (*p == '`')
458
      extra_length++;
459
    else if (*p == '.')
460
      extra_length+= 2;
461
  }
462
  return (p - name) + extra_length;
463
}
464
465
466
static char *fix_table_name(char *dest, char *src)
467
{
468
  *dest++= '`';
469
  for (; *src; src++)
470
  {
471
    switch (*src) {
472
    case '.':            /* add backticks around '.' */
473
      *dest++= '`';
474
      *dest++= '.';
475
      *dest++= '`';
476
      break;
477
    case '`':            /* escape backtick character */
478
      *dest++= '`';
479
      /* fall through */
480
    default:
481
      *dest++= *src;
482
    }
483
  }
484
  *dest++= '`';
485
  return dest;
486
}
487
488
489
static int process_all_tables_in_db(char *database)
490
{
491
  MYSQL_RES *res;
492
  MYSQL_ROW row;
493
  uint num_columns;
494
495
  if (use_db(database))
496
    return 1;
497
  if (mysql_query(sock, "SHOW /*!50002 FULL*/ TABLES") ||
498
	!((res= mysql_store_result(sock))))
499
    return 1;
500
501
  num_columns= mysql_num_fields(res);
502
503
  if (opt_all_in_1)
504
  {
505
    /*
506
      We need table list in form `a`, `b`, `c`
507
      that's why we need 2 more chars added to to each table name
508
      space is for more readable output in logs and in case of error
509
     */
510
511
    char *tables, *end;
512
    uint tot_length = 0;
513
514
    while ((row = mysql_fetch_row(res)))
515
      tot_length+= fixed_name_length(row[0]) + 2;
516
    mysql_data_seek(res, 0);
517
518
    if (!(tables=(char *) my_malloc(sizeof(char)*tot_length+4, MYF(MY_WME))))
519
    {
520
      mysql_free_result(res);
521
      return 1;
522
    }
523
    for (end = tables + 1; (row = mysql_fetch_row(res)) ;)
524
    {
525
      if ((num_columns == 2) && (strcmp(row[1], "VIEW") == 0))
526
        continue;
527
528
      end= fix_table_name(end, row[0]);
529
      *end++= ',';
530
    }
531
    *--end = 0;
532
    if (tot_length)
533
      handle_request_for_tables(tables + 1, tot_length - 1);
534
    my_free(tables, MYF(0));
535
  }
536
  else
537
  {
538
    while ((row = mysql_fetch_row(res)))
539
    {
540
      /* Skip views if we don't perform renaming. */
541
      if ((what_to_do != DO_UPGRADE) && (num_columns == 2) && (strcmp(row[1], "VIEW") == 0))
542
        continue;
543
544
      handle_request_for_tables(row[0], fixed_name_length(row[0]));
545
    }
546
  }
547
  mysql_free_result(res);
548
  return 0;
549
} /* process_all_tables_in_db */
550
551
552
553
static int fix_table_storage_name(const char *name)
554
{
555
  char qbuf[100 + NAME_LEN*4];
556
  int rc= 0;
557
  if (strncmp(name, "#mysql50#", 9))
558
    return 1;
559
  sprintf(qbuf, "RENAME TABLE `%s` TO `%s`", name, name + 9);
560
  if (mysql_query(sock, qbuf))
561
  {
562
    fprintf(stderr, "Failed to %s\n", qbuf);
563
    fprintf(stderr, "Error: %s\n", mysql_error(sock));
564
    rc= 1;
565
  }
566
  if (verbose)
567
    printf("%-50s %s\n", name, rc ? "FAILED" : "OK");
568
  return rc;
569
}
570
571
static int fix_database_storage_name(const char *name)
572
{
573
  char qbuf[100 + NAME_LEN*4];
574
  int rc= 0;
575
  if (strncmp(name, "#mysql50#", 9))
576
    return 1;
577
  sprintf(qbuf, "ALTER DATABASE `%s` UPGRADE DATA DIRECTORY NAME", name);
578
  if (mysql_query(sock, qbuf))
579
  {
580
    fprintf(stderr, "Failed to %s\n", qbuf);
581
    fprintf(stderr, "Error: %s\n", mysql_error(sock));
582
    rc= 1;
583
  }
584
  if (verbose)
585
    printf("%-50s %s\n", name, rc ? "FAILED" : "OK");
586
  return rc;
587
}
588
589
static int process_one_db(char *database)
590
{
591
  if (what_to_do == DO_UPGRADE)
592
  {
593
    int rc= 0;
594
    if (opt_fix_db_names && !strncmp(database,"#mysql50#", 9))
595
    {
596
      rc= fix_database_storage_name(database);
597
      database+= 9;
598
    }
599
    if (rc || !opt_fix_table_names)
600
      return rc;
601
  }
602
  return process_all_tables_in_db(database);
603
}
604
605
606
static int use_db(char *database)
607
{
608
  if (mysql_get_server_version(sock) >= 50003 &&
609
      !my_strcasecmp(&my_charset_latin1, database, "information_schema"))
610
    return 1;
611
  if (mysql_select_db(sock, database))
612
  {
613
    DBerror(sock, "when selecting the database");
614
    return 1;
615
  }
616
  return 0;
617
} /* use_db */
618
619
620
static int handle_request_for_tables(char *tables, uint length)
621
{
622
  char *query, *end, options[100], message[100];
623
  uint query_length= 0;
624
  const char *op = 0;
625
626
  options[0] = 0;
627
  end = options;
628
  switch (what_to_do) {
629
  case DO_CHECK:
630
    op = "CHECK";
631
    if (opt_quick)              end = strmov(end, " QUICK");
632
    if (opt_fast)               end = strmov(end, " FAST");
633
    if (opt_medium_check)       end = strmov(end, " MEDIUM"); /* Default */
634
    if (opt_extended)           end = strmov(end, " EXTENDED");
635
    if (opt_check_only_changed) end = strmov(end, " CHANGED");
636
    if (opt_upgrade)            end = strmov(end, " FOR UPGRADE");
637
    break;
638
  case DO_REPAIR:
639
    op= (opt_write_binlog) ? "REPAIR" : "REPAIR NO_WRITE_TO_BINLOG";
640
    if (opt_quick)              end = strmov(end, " QUICK");
641
    if (opt_extended)           end = strmov(end, " EXTENDED");
642
    if (opt_frm)                end = strmov(end, " USE_FRM");
643
    break;
644
  case DO_ANALYZE:
645
    op= (opt_write_binlog) ? "ANALYZE" : "ANALYZE NO_WRITE_TO_BINLOG";
646
    break;
647
  case DO_OPTIMIZE:
648
    op= (opt_write_binlog) ? "OPTIMIZE" : "OPTIMIZE NO_WRITE_TO_BINLOG";
649
    break;
650
  case DO_UPGRADE:
651
    return fix_table_storage_name(tables);
652
  }
653
654
  if (!(query =(char *) my_malloc((sizeof(char)*(length+110)), MYF(MY_WME))))
655
    return 1;
656
  if (opt_all_in_1)
657
  {
658
    /* No backticks here as we added them before */
659
    query_length= my_sprintf(query,
660
			     (query, "%s TABLE %s %s", op, tables, options));
661
  }
662
  else
663
  {
664
    char *ptr;
665
666
    ptr= strmov(strmov(query, op), " TABLE ");
667
    ptr= fix_table_name(ptr, tables);
668
    ptr= strxmov(ptr, " ", options, NullS);
669
    query_length= (uint) (ptr - query);
670
  }
671
  if (mysql_real_query(sock, query, query_length))
672
  {
673
    sprintf(message, "when executing '%s TABLE ... %s'", op, options);
674
    DBerror(sock, message);
675
    return 1;
676
  }
677
  print_result();
678
  my_free(query, MYF(0));
679
  return 0;
680
}
681
682
683
static void print_result()
684
{
685
  MYSQL_RES *res;
686
  MYSQL_ROW row;
687
  char prev[NAME_LEN*2+2];
688
  uint i;
689
  my_bool found_error=0;
690
691
  res = mysql_use_result(sock);
692
693
  prev[0] = '\0';
694
  for (i = 0; (row = mysql_fetch_row(res)); i++)
695
  {
696
    int changed = strcmp(prev, row[0]);
697
    my_bool status = !strcmp(row[2], "status");
698
699
    if (status)
700
    {
701
      /*
702
        if there was an error with the table, we have --auto-repair set,
703
        and this isn't a repair op, then add the table to the tables4repair
704
        list
705
      */
706
      if (found_error && opt_auto_repair && what_to_do != DO_REPAIR &&
707
	  strcmp(row[3],"OK"))
708
	insert_dynamic(&tables4repair, (uchar*) prev);
709
      found_error=0;
710
      if (opt_silent)
711
	continue;
712
    }
713
    if (status && changed)
714
      printf("%-50s %s", row[0], row[3]);
715
    else if (!status && changed)
716
    {
717
      printf("%s\n%-9s: %s", row[0], row[2], row[3]);
718
      if (strcmp(row[2],"note"))
719
	found_error=1;
720
    }
721
    else
722
      printf("%-9s: %s", row[2], row[3]);
723
    strmov(prev, row[0]);
724
    putchar('\n');
725
  }
726
  /* add the last table to be repaired to the list */
727
  if (found_error && opt_auto_repair && what_to_do != DO_REPAIR)
728
    insert_dynamic(&tables4repair, (uchar*) prev);
729
  mysql_free_result(res);
730
}
731
732
733
static int dbConnect(char *host, char *user, char *passwd)
734
{
735
  DBUG_ENTER("dbConnect");
736
  if (verbose)
737
  {
738
    fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost");
739
  }
740
  mysql_init(&mysql_connection);
741
  if (opt_compress)
742
    mysql_options(&mysql_connection, MYSQL_OPT_COMPRESS, NullS);
743
#ifdef HAVE_OPENSSL
744
  if (opt_use_ssl)
745
    mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
746
		  opt_ssl_capath, opt_ssl_cipher);
747
#endif
748
  if (opt_protocol)
749
    mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
750
#ifdef HAVE_SMEM
751
  if (shared_memory_base_name)
752
    mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
753
#endif
754
  if (!(sock = mysql_real_connect(&mysql_connection, host, user, passwd,
755
         NULL, opt_mysql_port, opt_mysql_unix_port, 0)))
756
  {
757
    DBerror(&mysql_connection, "when trying to connect");
758
    return 1;
759
  }
760
  mysql_connection.reconnect= 1;
761
  return 0;
762
} /* dbConnect */
763
764
765
static void dbDisconnect(char *host)
766
{
767
  if (verbose)
768
    fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
769
  mysql_close(sock);
770
} /* dbDisconnect */
771
772
773
static void DBerror(MYSQL *mysql, const char *when)
774
{
775
  DBUG_ENTER("DBerror");
776
  my_printf_error(0,"Got error: %d: %s %s", MYF(0),
777
		  mysql_errno(mysql), mysql_error(mysql), when);
778
  safe_exit(EX_MYSQLERR);
779
  DBUG_VOID_RETURN;
780
} /* DBerror */
781
782
783
static void safe_exit(int error)
784
{
785
  if (!first_error)
786
    first_error= error;
787
  if (ignore_errors)
788
    return;
789
  if (sock)
790
    mysql_close(sock);
791
  exit(error);
792
}
793
794
795
int main(int argc, char **argv)
796
{
797
  MY_INIT(argv[0]);
798
  /*
799
  ** Check out the args
800
  */
801
  if (get_options(&argc, &argv))
802
  {
803
    my_end(my_end_arg);
804
    exit(EX_USAGE);
805
  }
806
  if (dbConnect(current_host, current_user, opt_password))
807
    exit(EX_MYSQLERR);
808
809
  if (opt_auto_repair &&
810
      my_init_dynamic_array(&tables4repair, sizeof(char)*(NAME_LEN*2+2),16,64))
811
  {
812
    first_error = 1;
813
    goto end;
814
  }
815
816
  if (opt_alldbs)
817
    process_all_databases();
818
  /* Only one database and selected table(s) */
819
  else if (argc > 1 && !opt_databases)
820
    process_selected_tables(*argv, (argv + 1), (argc - 1));
821
  /* One or more databases, all tables */
822
  else
823
    process_databases(argv);
824
  if (opt_auto_repair)
825
  {
826
    uint i;
827
828
    if (!opt_silent && tables4repair.elements)
829
      puts("\nRepairing tables");
830
    what_to_do = DO_REPAIR;
831
    for (i = 0; i < tables4repair.elements ; i++)
832
    {
833
      char *name= (char*) dynamic_array_ptr(&tables4repair, i);
834
      handle_request_for_tables(name, fixed_name_length(name));
835
    }
836
  }
837
 end:
838
  dbDisconnect(current_host);
839
  if (opt_auto_repair)
840
    delete_dynamic(&tables4repair);
841
  my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
842
#ifdef HAVE_SMEM
843
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
844
#endif
845
  my_end(my_end_arg);
846
  return(first_error!=0);
847
} /* main */