~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzlecheck.cc

  • Committer: Eric Herman
  • Date: 2008-12-07 15:29:44 UTC
  • mto: (656.1.14 devel)
  • mto: This revision was merged to the branch mainline in revision 670.
  • Revision ID: eric@mysql.com-20081207152944-cq1nx1cyi0huqj0f
Added pointer to online version of the FAQ

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2008 Drizzle development team
 
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, MYSQL Development Team */
 
17
 
 
18
#define CHECK_VERSION "2.5.0"
 
19
 
 
20
#include "client_priv.h"
 
21
#include <vector>
 
22
#include <string>
 
23
#include <mystrings/m_ctype.h>
 
24
 
 
25
template class std::vector<std::string>;
 
26
 
 
27
using namespace std;
 
28
/* Exit codes */
 
29
 
 
30
#define EX_USAGE 1
 
31
#define EX_MYSQLERR 2
 
32
 
 
33
static DRIZZLE drizzle_connection, *sock = 0;
 
34
static bool opt_alldbs = 0, opt_check_only_changed = 0, opt_extended = 0,
 
35
               opt_compress = 0, opt_databases = 0, opt_fast = 0,
 
36
               opt_medium_check = 0, opt_quick = 0, opt_all_in_1 = 0,
 
37
               opt_silent = 0, opt_auto_repair = 0, ignore_errors = 0,
 
38
               tty_password= 0, opt_frm= 0, debug_info_flag= 0, debug_check_flag= 0,
 
39
               opt_fix_table_names= 0, opt_fix_db_names= 0, opt_upgrade= 0,
 
40
               opt_write_binlog= 1;
 
41
static uint verbose = 0, opt_mysql_port=0;
 
42
static int my_end_arg;
 
43
static char * opt_mysql_unix_port = 0;
 
44
static char *opt_password = 0, *current_user = 0,
 
45
      *default_charset = (char *)DRIZZLE_DEFAULT_CHARSET_NAME,
 
46
      *current_host = 0;
 
47
static int first_error = 0;
 
48
vector<string> tables4repair;
 
49
static uint opt_protocol=0;
 
50
static const CHARSET_INFO *charset_info= &my_charset_utf8_general_ci;
 
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
   (char**) &opt_alldbs, (char**) &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
   (char**) &opt_all_in_1, (char**) &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
   (char**) &opt_auto_repair, (char**) &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.", (char**) &charsets_dir,
 
72
   (char**) &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
   (char**) &opt_compress, (char**) &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
   (char**) &opt_databases, (char**) &opt_databases, 0, GET_BOOL, NO_ARG,
 
87
   0, 0, 0, 0, 0, 0},
 
88
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
 
89
   (char**) &debug_check_flag, (char**) &debug_check_flag, 0,
 
90
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
91
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
 
92
   (char**) &debug_info_flag, (char**) &debug_info_flag,
 
93
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
94
  {"default-character-set", OPT_DEFAULT_CHARSET,
 
95
   "Set the default character set.", (char**) &default_charset,
 
96
   (char**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
97
  {"fast",'F', "Check only tables that haven't been closed properly.",
 
98
   (char**) &opt_fast, (char**) &opt_fast, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
 
99
   0},
 
100
  {"fix-db-names", OPT_FIX_DB_NAMES, "Fix database names.",
 
101
    (char**) &opt_fix_db_names, (char**) &opt_fix_db_names,
 
102
    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
103
  {"fix-table-names", OPT_FIX_TABLE_NAMES, "Fix table names.",
 
104
    (char**) &opt_fix_table_names, (char**) &opt_fix_table_names,
 
105
    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
106
  {"force", 'f', "Continue even if we get an sql-error.",
 
107
   (char**) &ignore_errors, (char**) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
 
108
   0, 0, 0, 0},
 
109
  {"extended", 'e',
 
110
   "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.",
 
111
   (char**) &opt_extended, (char**) &opt_extended, 0, GET_BOOL, NO_ARG, 0, 0, 0,
 
112
   0, 0, 0},
 
113
  {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
 
114
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
115
  {"host",'h', "Connect to host.", (char**) &current_host,
 
116
   (char**) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
117
  {"medium-check", 'm',
 
118
   "Faster than extended-check, but only finds 99.99 percent of all errors. Should be good enough for most cases.",
 
119
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
120
  {"write-binlog", OPT_WRITE_BINLOG,
 
121
   "Log ANALYZE, OPTIMIZE and REPAIR TABLE commands. Use --skip-write-binlog when commands should not be sent to replication slaves.",
 
122
   (char**) &opt_write_binlog, (char**) &opt_write_binlog, 0, GET_BOOL, NO_ARG,
 
123
   1, 0, 0, 0, 0, 0},
 
124
  {"optimize", 'o', "Optimize table.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0,
 
125
   0, 0},
 
126
  {"password", 'p',
 
127
   "Password to use when connecting to server. If password is not given it's solicited on the tty.",
 
128
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
129
  {"port", 'P', "Port number to use for connection or 0 for default to, in "
 
130
   "order of preference, drizzle.cnf, $DRIZZLE_TCP_PORT, "
 
131
   "built-in default (" STRINGIFY_ARG(DRIZZLE_PORT) ").",
 
132
   (char**) &opt_mysql_port,
 
133
   (char**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
 
134
   0},
 
135
  {"protocol", OPT_DRIZZLE_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.",
 
139
   (char**) &opt_quick, (char**) &opt_quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
 
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},
 
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},
 
146
  {"socket", 'S', "Socket file to use for connection.",
 
147
   (char**) &opt_mysql_unix_port, (char**) &opt_mysql_unix_port, 0, GET_STR,
 
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.",
 
153
   (char**) &opt_frm, (char**) &opt_frm, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
 
154
   0},
 
155
#ifndef DONT_ALLOW_USER_CHANGE
 
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},
 
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);
 
172
static int process_all_databases(void);
 
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(const char *tables, uint length);
 
179
static int dbConnect(char *host, char *user,char *passwd);
 
180
static void dbDisconnect(char *host);
 
181
static void DBerror(DRIZZLE *drizzle, const char *when);
 
182
static void safe_exit(int error);
 
183
static void print_result(void);
 
184
static uint fixed_name_length(const char *name);
 
185
static char *fix_table_name(char *dest, const char *src);
 
186
int what_to_do = 0;
 
187
 
 
188
static void print_version(void)
 
189
{
 
190
  printf("%s  Ver %s Distrib %s, for %s (%s)\n", my_progname, CHECK_VERSION,
 
191
   drizzle_get_client_info(), SYSTEM_TYPE, MACHINE_TYPE);
 
192
} /* print_version */
 
193
 
 
194
static void usage(void)
 
195
{
 
196
  print_version();
 
197
  puts("By Jani Tolonen, 2001-04-20, MySQL Development Team\n");
 
198
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n");
 
199
  puts("and you are welcome to modify and redistribute it under the GPL license.\n");
 
200
  puts("This program can be used to CHECK (-c,-m,-C), REPAIR (-r), ANALYZE (-a)");
 
201
  puts("or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be");
 
202
  puts("used at the same time. Not all options are supported by all storage engines.");
 
203
  puts("Please consult the Drizzle manual for latest information about the");
 
204
  puts("above. The options -c,-r,-a and -o are exclusive to each other, which");
 
205
  puts("means that the last option will be used, if several was specified.\n");
 
206
  puts("The option -c will be used by default, if none was specified. You");
 
207
  puts("can change the default behavior by making a symbolic link, or");
 
208
  puts("copying this file somewhere with another name, the alternatives are:");
 
209
  puts("mysqlrepair:   The default option will be -r");
 
210
  puts("mysqlanalyze:  The default option will be -a");
 
211
  puts("mysqloptimize: The default option will be -o\n");
 
212
  printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
 
213
  printf("OR     %s [OPTIONS] --databases DB1 [DB2 DB3...]\n",
 
214
   my_progname);
 
215
  printf("OR     %s [OPTIONS] --all-databases\n", my_progname);
 
216
  print_defaults("drizzle", load_default_groups);
 
217
  my_print_help(my_long_options);
 
218
  my_print_variables(my_long_options);
 
219
} /* usage */
 
220
 
 
221
extern "C"
 
222
bool get_one_option(int optid, const struct my_option *, char *argument)
 
223
{
 
224
  switch(optid) {
 
225
  case 'a':
 
226
    what_to_do = DO_ANALYZE;
 
227
    break;
 
228
  case 'c':
 
229
    what_to_do = DO_CHECK;
 
230
    break;
 
231
  case 'C':
 
232
    what_to_do = DO_CHECK;
 
233
    opt_check_only_changed = 1;
 
234
    break;
 
235
  case 'I': /* Fall through */
 
236
  case '?':
 
237
    usage();
 
238
    exit(0);
 
239
  case 'm':
 
240
    what_to_do = DO_CHECK;
 
241
    opt_medium_check = 1;
 
242
    break;
 
243
  case 'o':
 
244
    what_to_do = DO_OPTIMIZE;
 
245
    break;
 
246
  case OPT_FIX_DB_NAMES:
 
247
    what_to_do= DO_UPGRADE;
 
248
    default_charset= (char*) "utf8";
 
249
    opt_databases= 1;
 
250
    break;
 
251
  case OPT_FIX_TABLE_NAMES:
 
252
    what_to_do= DO_UPGRADE;
 
253
    default_charset= (char*) "utf8";
 
254
    break;
 
255
  case 'p':
 
256
    if (argument)
 
257
    {
 
258
      char *start = argument;
 
259
      free(opt_password);
 
260
      opt_password = my_strdup(argument, MYF(MY_FAE));
 
261
      while (*argument) *argument++= 'x';    /* Destroy argument */
 
262
      if (*start)
 
263
  start[1] = 0;                             /* Cut length of argument */
 
264
      tty_password= 0;
 
265
    }
 
266
    else
 
267
      tty_password = 1;
 
268
    break;
 
269
  case 'r':
 
270
    what_to_do = DO_REPAIR;
 
271
    break;
 
272
  case 'g':
 
273
    what_to_do= DO_CHECK;
 
274
    opt_upgrade= 1;
 
275
    break;
 
276
  case OPT_TABLES:
 
277
    opt_databases = 0;
 
278
    break;
 
279
  case 'v':
 
280
    verbose++;
 
281
    break;
 
282
  case 'V': print_version(); exit(0);
 
283
  case OPT_DRIZZLE_PROTOCOL:
 
284
    break;
 
285
  }
 
286
  return 0;
 
287
}
 
288
 
 
289
 
 
290
static int get_options(int *argc, char ***argv)
 
291
{
 
292
  int ho_error;
 
293
 
 
294
  if (*argc == 1)
 
295
  {
 
296
    usage();
 
297
    exit(0);
 
298
  }
 
299
 
 
300
  load_defaults("drizzle", load_default_groups, argc, argv);
 
301
 
 
302
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
 
303
    exit(ho_error);
 
304
 
 
305
  if (!what_to_do)
 
306
  {
 
307
    int pnlen = strlen(my_progname);
 
308
 
 
309
    if (pnlen < 6) /* name too short */
 
310
      what_to_do = DO_CHECK;
 
311
    else if (!strcmp("repair", my_progname + pnlen - 6))
 
312
      what_to_do = DO_REPAIR;
 
313
    else if (!strcmp("analyze", my_progname + pnlen - 7))
 
314
      what_to_do = DO_ANALYZE;
 
315
    else if  (!strcmp("optimize", my_progname + pnlen - 8))
 
316
      what_to_do = DO_OPTIMIZE;
 
317
    else
 
318
      what_to_do = DO_CHECK;
 
319
  }
 
320
 
 
321
  /* TODO: This variable is not yet used */
 
322
  if (strcmp(default_charset, charset_info->csname) &&
 
323
      !(charset_info= get_charset_by_csname(default_charset,
 
324
                MY_CS_PRIMARY, MYF(MY_WME))))
 
325
      exit(1);
 
326
  if (*argc > 0 && opt_alldbs)
 
327
  {
 
328
    printf("You should give only options, no arguments at all, with option\n");
 
329
    printf("--all-databases. Please see %s --help for more information.\n",
 
330
     my_progname);
 
331
    return 1;
 
332
  }
 
333
  if (*argc < 1 && !opt_alldbs)
 
334
  {
 
335
    printf("You forgot to give the arguments! Please see %s --help\n",
 
336
     my_progname);
 
337
    printf("for more information.\n");
 
338
    return 1;
 
339
  }
 
340
  if (tty_password)
 
341
    opt_password = get_tty_password(NULL);
 
342
  if (debug_info_flag)
 
343
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
 
344
  if (debug_check_flag)
 
345
    my_end_arg= MY_CHECK_ERROR;
 
346
  return(0);
 
347
} /* get_options */
 
348
 
 
349
 
 
350
static int process_all_databases()
 
351
{
 
352
  DRIZZLE_ROW row;
 
353
  DRIZZLE_RES *tableres;
 
354
  int result = 0;
 
355
 
 
356
  if (drizzle_query(sock, "SHOW DATABASES") ||
 
357
      !(tableres = drizzle_store_result(sock)))
 
358
  {
 
359
    my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
 
360
        MYF(0), drizzle_error(sock));
 
361
    return 1;
 
362
  }
 
363
  while ((row = drizzle_fetch_row(tableres)))
 
364
  {
 
365
    if (process_one_db(row[0]))
 
366
      result = 1;
 
367
  }
 
368
  return result;
 
369
}
 
370
/* process_all_databases */
 
371
 
 
372
 
 
373
static int process_databases(char **db_names)
 
374
{
 
375
  int result = 0;
 
376
  for ( ; *db_names ; db_names++)
 
377
  {
 
378
    if (process_one_db(*db_names))
 
379
      result = 1;
 
380
  }
 
381
  return result;
 
382
} /* process_databases */
 
383
 
 
384
 
 
385
static int process_selected_tables(char *db, char **table_names, int tables)
 
386
{
 
387
  if (use_db(db))
 
388
    return 1;
 
389
  if (opt_all_in_1)
 
390
  {
 
391
    /*
 
392
      We need table list in form `a`, `b`, `c`
 
393
      that's why we need 2 more chars added to to each table name
 
394
      space is for more readable output in logs and in case of error
 
395
    */
 
396
    char *table_names_comma_sep, *end;
 
397
    int i, tot_length = 0;
 
398
 
 
399
    for (i = 0; i < tables; i++)
 
400
      tot_length+= fixed_name_length(*(table_names + i)) + 2;
 
401
 
 
402
    if (!(table_names_comma_sep = (char *)
 
403
          malloc((sizeof(char) * tot_length) + 4)))
 
404
      return 1;
 
405
 
 
406
    for (end = table_names_comma_sep + 1; tables > 0;
 
407
         tables--, table_names++)
 
408
    {
 
409
      end= fix_table_name(end, *table_names);
 
410
      *end++= ',';
 
411
    }
 
412
    *--end = 0;
 
413
    handle_request_for_tables(table_names_comma_sep + 1, tot_length - 1);
 
414
    free(table_names_comma_sep);
 
415
  }
 
416
  else
 
417
    for (; tables > 0; tables--, table_names++)
 
418
      handle_request_for_tables(*table_names, fixed_name_length(*table_names));
 
419
  return 0;
 
420
} /* process_selected_tables */
 
421
 
 
422
 
 
423
static uint fixed_name_length(const char *name)
 
424
{
 
425
  const char *p;
 
426
  uint extra_length= 2;  /* count the first/last backticks */
 
427
 
 
428
  for (p= name; *p; p++)
 
429
  {
 
430
    if (*p == '`')
 
431
      extra_length++;
 
432
    else if (*p == '.')
 
433
      extra_length+= 2;
 
434
  }
 
435
  return (p - name) + extra_length;
 
436
}
 
437
 
 
438
 
 
439
static char *fix_table_name(char *dest, const char *src)
 
440
{
 
441
  *dest++= '`';
 
442
  for (; *src; src++)
 
443
  {
 
444
    switch (*src) {
 
445
    case '.':            /* add backticks around '.' */
 
446
      *dest++= '`';
 
447
      *dest++= '.';
 
448
      *dest++= '`';
 
449
      break;
 
450
    case '`':            /* escape backtick character */
 
451
      *dest++= '`';
 
452
      /* fall through */
 
453
    default:
 
454
      *dest++= *src;
 
455
    }
 
456
  }
 
457
  *dest++= '`';
 
458
  return dest;
 
459
}
 
460
 
 
461
 
 
462
static int process_all_tables_in_db(char *database)
 
463
{
 
464
  DRIZZLE_RES *res;
 
465
  DRIZZLE_ROW row;
 
466
  uint num_columns;
 
467
 
 
468
  if (use_db(database))
 
469
    return 1;
 
470
  if (drizzle_query(sock, "SHOW /*!50002 FULL*/ TABLES") ||
 
471
  !((res= drizzle_store_result(sock))))
 
472
    return 1;
 
473
 
 
474
  num_columns= drizzle_num_fields(res);
 
475
 
 
476
  if (opt_all_in_1)
 
477
  {
 
478
    /*
 
479
      We need table list in form `a`, `b`, `c`
 
480
      that's why we need 2 more chars added to to each table name
 
481
      space is for more readable output in logs and in case of error
 
482
     */
 
483
 
 
484
    char *tables, *end;
 
485
    uint tot_length = 0;
 
486
 
 
487
    while ((row = drizzle_fetch_row(res)))
 
488
      tot_length+= fixed_name_length(row[0]) + 2;
 
489
    drizzle_data_seek(res, 0);
 
490
 
 
491
    if (!(tables=(char *) malloc(sizeof(char)*tot_length+4)))
 
492
    {
 
493
      drizzle_free_result(res);
 
494
      return 1;
 
495
    }
 
496
    for (end = tables + 1; (row = drizzle_fetch_row(res)) ;)
 
497
    {
 
498
      if ((num_columns == 2) && (strcmp(row[1], "VIEW") == 0))
 
499
        continue;
 
500
 
 
501
      end= fix_table_name(end, row[0]);
 
502
      *end++= ',';
 
503
    }
 
504
    *--end = 0;
 
505
    if (tot_length)
 
506
      handle_request_for_tables(tables + 1, tot_length - 1);
 
507
    free(tables);
 
508
  }
 
509
  else
 
510
  {
 
511
    while ((row = drizzle_fetch_row(res)))
 
512
    {
 
513
      /* Skip views if we don't perform renaming. */
 
514
      if ((what_to_do != DO_UPGRADE) && (num_columns == 2) && (strcmp(row[1], "VIEW") == 0))
 
515
        continue;
 
516
 
 
517
      handle_request_for_tables(row[0], fixed_name_length(row[0]));
 
518
    }
 
519
  }
 
520
  drizzle_free_result(res);
 
521
  return 0;
 
522
} /* process_all_tables_in_db */
 
523
 
 
524
 
 
525
 
 
526
static int fix_table_storage_name(const char *name)
 
527
{
 
528
  char qbuf[100 + NAME_LEN*4];
 
529
  int rc= 0;
 
530
  if (strncmp(name, "#mysql50#", 9))
 
531
    return 1;
 
532
  sprintf(qbuf, "RENAME TABLE `%s` TO `%s`", name, name + 9);
 
533
  if (drizzle_query(sock, qbuf))
 
534
  {
 
535
    fprintf(stderr, "Failed to %s\n", qbuf);
 
536
    fprintf(stderr, "Error: %s\n", drizzle_error(sock));
 
537
    rc= 1;
 
538
  }
 
539
  if (verbose)
 
540
    printf("%-50s %s\n", name, rc ? "FAILED" : "OK");
 
541
  return rc;
 
542
}
 
543
 
 
544
static int fix_database_storage_name(const char *name)
 
545
{
 
546
  char qbuf[100 + NAME_LEN*4];
 
547
  int rc= 0;
 
548
  if (strncmp(name, "#mysql50#", 9))
 
549
    return 1;
 
550
  sprintf(qbuf, "ALTER DATABASE `%s` UPGRADE DATA DIRECTORY NAME", name);
 
551
  if (drizzle_query(sock, qbuf))
 
552
  {
 
553
    fprintf(stderr, "Failed to %s\n", qbuf);
 
554
    fprintf(stderr, "Error: %s\n", drizzle_error(sock));
 
555
    rc= 1;
 
556
  }
 
557
  if (verbose)
 
558
    printf("%-50s %s\n", name, rc ? "FAILED" : "OK");
 
559
  return rc;
 
560
}
 
561
 
 
562
static int process_one_db(char *database)
 
563
{
 
564
  if (what_to_do == DO_UPGRADE)
 
565
  {
 
566
    int rc= 0;
 
567
    if (opt_fix_db_names && !strncmp(database,"#mysql50#", 9))
 
568
    {
 
569
      rc= fix_database_storage_name(database);
 
570
      database+= 9;
 
571
    }
 
572
    if (rc || !opt_fix_table_names)
 
573
      return rc;
 
574
  }
 
575
  return process_all_tables_in_db(database);
 
576
}
 
577
 
 
578
 
 
579
static int use_db(char *database)
 
580
{
 
581
  if (drizzle_get_server_version(sock) >= 50003 &&
 
582
      !my_strcasecmp(&my_charset_utf8_general_ci, database, "information_schema"))
 
583
    return 1;
 
584
  if (drizzle_select_db(sock, database))
 
585
  {
 
586
    DBerror(sock, "when selecting the database");
 
587
    return 1;
 
588
  }
 
589
  return 0;
 
590
} /* use_db */
 
591
 
 
592
 
 
593
static int handle_request_for_tables(const char *tables, uint length)
 
594
{
 
595
  char *query, *end, options[100], message[100];
 
596
  uint query_length= 0;
 
597
  const char *op = 0;
 
598
 
 
599
  options[0] = 0;
 
600
  end = options;
 
601
  switch (what_to_do) {
 
602
  case DO_CHECK:
 
603
    op = "CHECK";
 
604
    if (opt_quick)              end = strcpy(end, " QUICK")+6;
 
605
    if (opt_fast)               end = strcpy(end, " FAST")+5;
 
606
    if (opt_medium_check)       end = strcpy(end, " MEDIUM")+7; /* Default */
 
607
    if (opt_extended)           end = strcpy(end, " EXTENDED")+9;
 
608
    if (opt_check_only_changed) end = strcpy(end, " CHANGED")+8;
 
609
    if (opt_upgrade)            end = strcpy(end, " FOR UPGRADE")+12;
 
610
    break;
 
611
  case DO_REPAIR:
 
612
    op= (opt_write_binlog) ? "REPAIR" : "REPAIR NO_WRITE_TO_BINLOG";
 
613
    if (opt_quick)              end = strcpy(end, " QUICK")+6;
 
614
    if (opt_extended)           end = strcpy(end, " EXTENDED")+9;
 
615
    if (opt_frm)                end = strcpy(end, " USE_FRM")+8;
 
616
    break;
 
617
  case DO_ANALYZE:
 
618
    op= (opt_write_binlog) ? "ANALYZE" : "ANALYZE NO_WRITE_TO_BINLOG";
 
619
    break;
 
620
  case DO_OPTIMIZE:
 
621
    op= (opt_write_binlog) ? "OPTIMIZE" : "OPTIMIZE NO_WRITE_TO_BINLOG";
 
622
    break;
 
623
  case DO_UPGRADE:
 
624
    return fix_table_storage_name(tables);
 
625
  }
 
626
 
 
627
  if (!(query =(char *) malloc((sizeof(char)*(length+110)))))
 
628
    return 1;
 
629
  if (opt_all_in_1)
 
630
  {
 
631
    /* No backticks here as we added them before */
 
632
    query_length= sprintf(query, "%s TABLE %s %s", op, tables, options);
 
633
  }
 
634
  else
 
635
  {
 
636
    char *ptr;
 
637
    ptr= query;
 
638
    ptr= strcpy(query, op)+strlen(op);
 
639
    ptr= strcpy(ptr, " TABLE ")+7;
 
640
    ptr= fix_table_name(ptr, tables);
 
641
    ptr= strxmov(ptr, " ", options, NULL);
 
642
    query_length= (uint) (ptr - query);
 
643
  }
 
644
  if (drizzle_real_query(sock, query, query_length))
 
645
  {
 
646
    sprintf(message, "when executing '%s TABLE ... %s'", op, options);
 
647
    DBerror(sock, message);
 
648
    return 1;
 
649
  }
 
650
  print_result();
 
651
  free(query);
 
652
  return 0;
 
653
}
 
654
 
 
655
 
 
656
static void print_result()
 
657
{
 
658
  DRIZZLE_RES *res;
 
659
  DRIZZLE_ROW row;
 
660
  char prev[NAME_LEN*2+2];
 
661
  uint i;
 
662
  bool found_error=0;
 
663
 
 
664
  res = drizzle_use_result(sock);
 
665
 
 
666
  prev[0] = '\0';
 
667
  for (i = 0; (row = drizzle_fetch_row(res)); i++)
 
668
  {
 
669
    int changed = strcmp(prev, row[0]);
 
670
    bool status = !strcmp(row[2], "status");
 
671
 
 
672
    if (status)
 
673
    {
 
674
      /*
 
675
        if there was an error with the table, we have --auto-repair set,
 
676
        and this isn't a repair op, then add the table to the tables4repair
 
677
        list
 
678
      */
 
679
      if (found_error && opt_auto_repair && what_to_do != DO_REPAIR &&
 
680
          strcmp(row[3],"OK"))
 
681
        tables4repair.push_back(string(prev));
 
682
      found_error=0;
 
683
      if (opt_silent)
 
684
  continue;
 
685
    }
 
686
    if (status && changed)
 
687
      printf("%-50s %s", row[0], row[3]);
 
688
    else if (!status && changed)
 
689
    {
 
690
      printf("%s\n%-9s: %s", row[0], row[2], row[3]);
 
691
      if (strcmp(row[2],"note"))
 
692
  found_error=1;
 
693
    }
 
694
    else
 
695
      printf("%-9s: %s", row[2], row[3]);
 
696
    strcpy(prev, row[0]);
 
697
    putchar('\n');
 
698
  }
 
699
  /* add the last table to be repaired to the list */
 
700
  if (found_error && opt_auto_repair && what_to_do != DO_REPAIR)
 
701
    tables4repair.push_back(string(prev));
 
702
  drizzle_free_result(res);
 
703
}
 
704
 
 
705
 
 
706
static int dbConnect(char *host, char *user, char *passwd)
 
707
{
 
708
 
 
709
  if (verbose)
 
710
  {
 
711
    fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost");
 
712
  }
 
713
  drizzle_create(&drizzle_connection);
 
714
  if (opt_compress)
 
715
    drizzle_options(&drizzle_connection, DRIZZLE_OPT_COMPRESS, NULL);
 
716
  if (opt_protocol)
 
717
    drizzle_options(&drizzle_connection,DRIZZLE_OPT_PROTOCOL,(char*)&opt_protocol);
 
718
  if (!(sock = drizzle_connect(&drizzle_connection, host, user, passwd,
 
719
         NULL, opt_mysql_port, opt_mysql_unix_port, 0)))
 
720
  {
 
721
    DBerror(&drizzle_connection, "when trying to connect");
 
722
    return 1;
 
723
  }
 
724
  drizzle_connection.reconnect= 1;
 
725
  return 0;
 
726
} /* dbConnect */
 
727
 
 
728
 
 
729
static void dbDisconnect(char *host)
 
730
{
 
731
  if (verbose)
 
732
    fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
 
733
  drizzle_close(sock);
 
734
} /* dbDisconnect */
 
735
 
 
736
 
 
737
static void DBerror(DRIZZLE *drizzle, const char *when)
 
738
{
 
739
  my_printf_error(0,"Got error: %d: %s %s", MYF(0),
 
740
      drizzle_errno(drizzle), drizzle_error(drizzle), when);
 
741
  safe_exit(EX_MYSQLERR);
 
742
  return;
 
743
} /* DBerror */
 
744
 
 
745
 
 
746
static void safe_exit(int error)
 
747
{
 
748
  if (!first_error)
 
749
    first_error= error;
 
750
  if (ignore_errors)
 
751
    return;
 
752
  if (sock)
 
753
    drizzle_close(sock);
 
754
  exit(error);
 
755
}
 
756
 
 
757
 
 
758
int main(int argc, char **argv)
 
759
{
 
760
  MY_INIT(argv[0]);
 
761
  /*
 
762
  ** Check out the args
 
763
  */
 
764
  if (get_options(&argc, &argv))
 
765
  {
 
766
    my_end(my_end_arg);
 
767
    exit(EX_USAGE);
 
768
  }
 
769
  if (dbConnect(current_host, current_user, opt_password))
 
770
    exit(EX_MYSQLERR);
 
771
 
 
772
  if (opt_auto_repair)
 
773
  {
 
774
    tables4repair.reserve(64);
 
775
    if (tables4repair.capacity() == 0)
 
776
    {
 
777
      first_error = 1;
 
778
      goto end;
 
779
    }
 
780
  }
 
781
 
 
782
 
 
783
  if (opt_alldbs)
 
784
    process_all_databases();
 
785
  /* Only one database and selected table(s) */
 
786
  else if (argc > 1 && !opt_databases)
 
787
    process_selected_tables(*argv, (argv + 1), (argc - 1));
 
788
  /* One or more databases, all tables */
 
789
  else
 
790
    process_databases(argv);
 
791
  if (opt_auto_repair)
 
792
  {
 
793
 
 
794
    if (!opt_silent && (tables4repair.size() > 0))
 
795
      puts("\nRepairing tables");
 
796
    what_to_do = DO_REPAIR;
 
797
    vector<string>::iterator i;
 
798
    for ( i= tables4repair.begin() ; i < tables4repair.end() ; i++)
 
799
    {
 
800
      const char *name= (*i).c_str();
 
801
      handle_request_for_tables(name, fixed_name_length(name));
 
802
    }
 
803
  }
 
804
 end:
 
805
  dbDisconnect(current_host);
 
806
  free(opt_password);
 
807
  my_end(my_end_arg);
 
808
  return(first_error!=0);
 
809
} /* main */