~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>
77.1.39 by Monty Taylor
More mysql->drizzle renaming.
22
#include <drizzle_version.h>
1 by brian
clean slate
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);
53.2.4 by Monty Taylor
Changes so that client/ builds cleanly with no warnings.
187
static int process_all_databases(void);
1 by brian
clean slate
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);
53.2.4 by Monty Taylor
Changes so that client/ builds cleanly with no warnings.
198
static void print_result(void);
1 by brian
clean slate
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
  if (opt_protocol)
744
    mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
745
#ifdef HAVE_SMEM
746
  if (shared_memory_base_name)
747
    mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
748
#endif
749
  if (!(sock = mysql_real_connect(&mysql_connection, host, user, passwd,
750
         NULL, opt_mysql_port, opt_mysql_unix_port, 0)))
751
  {
752
    DBerror(&mysql_connection, "when trying to connect");
753
    return 1;
754
  }
755
  mysql_connection.reconnect= 1;
756
  return 0;
757
} /* dbConnect */
758
759
760
static void dbDisconnect(char *host)
761
{
762
  if (verbose)
763
    fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
764
  mysql_close(sock);
765
} /* dbDisconnect */
766
767
768
static void DBerror(MYSQL *mysql, const char *when)
769
{
770
  DBUG_ENTER("DBerror");
771
  my_printf_error(0,"Got error: %d: %s %s", MYF(0),
772
		  mysql_errno(mysql), mysql_error(mysql), when);
773
  safe_exit(EX_MYSQLERR);
774
  DBUG_VOID_RETURN;
775
} /* DBerror */
776
777
778
static void safe_exit(int error)
779
{
780
  if (!first_error)
781
    first_error= error;
782
  if (ignore_errors)
783
    return;
784
  if (sock)
785
    mysql_close(sock);
786
  exit(error);
787
}
788
789
790
int main(int argc, char **argv)
791
{
792
  MY_INIT(argv[0]);
793
  /*
794
  ** Check out the args
795
  */
796
  if (get_options(&argc, &argv))
797
  {
798
    my_end(my_end_arg);
799
    exit(EX_USAGE);
800
  }
801
  if (dbConnect(current_host, current_user, opt_password))
802
    exit(EX_MYSQLERR);
803
804
  if (opt_auto_repair &&
805
      my_init_dynamic_array(&tables4repair, sizeof(char)*(NAME_LEN*2+2),16,64))
806
  {
807
    first_error = 1;
808
    goto end;
809
  }
810
811
  if (opt_alldbs)
812
    process_all_databases();
813
  /* Only one database and selected table(s) */
814
  else if (argc > 1 && !opt_databases)
815
    process_selected_tables(*argv, (argv + 1), (argc - 1));
816
  /* One or more databases, all tables */
817
  else
818
    process_databases(argv);
819
  if (opt_auto_repair)
820
  {
821
    uint i;
822
823
    if (!opt_silent && tables4repair.elements)
824
      puts("\nRepairing tables");
825
    what_to_do = DO_REPAIR;
826
    for (i = 0; i < tables4repair.elements ; i++)
827
    {
828
      char *name= (char*) dynamic_array_ptr(&tables4repair, i);
829
      handle_request_for_tables(name, fixed_name_length(name));
830
    }
831
  }
832
 end:
833
  dbDisconnect(current_host);
834
  if (opt_auto_repair)
835
    delete_dynamic(&tables4repair);
836
  my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
837
#ifdef HAVE_SMEM
838
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
839
#endif
840
  my_end(my_end_arg);
841
  return(first_error!=0);
842
} /* main */