~skinny.moey/drizzle/branch-rev

« back to all changes in this revision

Viewing changes to client/mysqlcheck.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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