~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzlecheck.cc

  • Committer: Monty Taylor
  • Date: 2008-10-14 21:20:42 UTC
  • mto: (511.1.4 codestyle)
  • mto: This revision was merged to the branch mainline in revision 521.
  • Revision ID: monty@inaugust.com-20081014212042-tef3njx3368b6lwt
Override copy ctr and op= because we have pointer members.

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