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