~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzlecheck.cc

  • Committer: Monty Taylor
  • Date: 2009-04-14 19:16:51 UTC
  • mto: (997.2.5 mordred)
  • mto: This revision was merged to the branch mainline in revision 994.
  • Revision ID: mordred@inaugust.com-20090414191651-ltbww6hpqks8k7qk
Clarified instructions in README.

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
/* Added this for string translation. */
 
26
#include <drizzled/gettext.h>
 
27
 
 
28
 
 
29
using namespace std;
 
30
 
 
31
template class vector<string>;
 
32
 
 
33
/* Exit codes */
 
34
 
 
35
#define EX_USAGE 1
 
36
#define EX_MYSQLERR 2
 
37
 
 
38
static drizzle_st drizzle;
 
39
static drizzle_con_st dcon;
 
40
static bool opt_alldbs= false, opt_check_only_changed= false,
 
41
            opt_extended= false, opt_databases= false,
 
42
            opt_fast= false, opt_medium_check= false, opt_quick= false,
 
43
            opt_all_in_1= false, opt_silent= false, opt_auto_repair= false,
 
44
            ignore_errors= false, tty_password= false, opt_frm= false,
 
45
            debug_info_flag= false, debug_check_flag= false,
 
46
            opt_fix_table_names= false, opt_fix_db_names= false,
 
47
            opt_upgrade= false, opt_write_binlog= true;
 
48
static uint32_t verbose= 0;
 
49
static uint32_t opt_drizzle_port= 0;
 
50
static int my_end_arg;
 
51
static char * opt_drizzle_unix_port= NULL;
 
52
static char *opt_password= NULL, *current_user= NULL,
 
53
      *default_charset= (char *)DRIZZLE_DEFAULT_CHARSET_NAME,
 
54
      *current_host= NULL;
 
55
static int first_error= 0;
 
56
vector<string> tables4repair;
 
57
static const CHARSET_INFO *charset_info= &my_charset_utf8_general_ci;
 
58
 
 
59
enum operations { DO_CHECK, DO_REPAIR, DO_ANALYZE, DO_OPTIMIZE, DO_UPGRADE };
 
60
 
 
61
static struct my_option my_long_options[] =
 
62
{
 
63
  {"all-databases", 'A',
 
64
   "Check all the databases. This will be same as  --databases with all databases selected.",
 
65
   (char**) &opt_alldbs, (char**) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
66
   0, 0},
 
67
  {"analyze", 'a', "Analyze given tables.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
 
68
   0, 0, 0, 0},
 
69
  {"all-in-1", '1',
 
70
   "Instead of issuing one query for each table, use one query per database, naming all tables in the database in a comma-separated list.",
 
71
   (char**) &opt_all_in_1, (char**) &opt_all_in_1, 0, GET_BOOL, NO_ARG, 0, 0, 0,
 
72
   0, 0, 0},
 
73
  {"auto-repair", OPT_AUTO_REPAIR,
 
74
   "If a checked table is corrupted, automatically fix it. Repairing will be done after all tables have been checked, if corrupted ones were found.",
 
75
   (char**) &opt_auto_repair, (char**) &opt_auto_repair, 0, GET_BOOL, NO_ARG, 0,
 
76
   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
  {"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, drizzle.cnf, $DRIZZLE_TCP_PORT, "
 
132
   "built-in default (" STRINGIFY_ARG(DRIZZLE_PORT) ").",
 
133
   0, 0, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
134
  {"protocol", OPT_DRIZZLE_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
 
135
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
136
  {"quick", 'q',
 
137
   "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.",
 
138
   (char**) &opt_quick, (char**) &opt_quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
 
139
   0},
 
140
  {"repair", 'r',
 
141
   "Can fix almost anything except unique keys that aren't unique.",
 
142
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
143
  {"silent", 's', "Print only error messages.", (char**) &opt_silent,
 
144
   (char**) &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
145
  {"socket", 'S', "Socket file to use for connection.",
 
146
   (char**) &opt_drizzle_unix_port, (char**) &opt_drizzle_unix_port, 0, GET_STR,
 
147
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
148
  {"tables", OPT_TABLES, "Overrides option --databases (-B).", 0, 0, 0,
 
149
   GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
150
  {"use-frm", OPT_FRM,
 
151
   "When used with REPAIR, get table structure from .frm file, so the table can be repaired even if .MYI header is corrupted.",
 
152
   (char**) &opt_frm, (char**) &opt_frm, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
 
153
   0},
 
154
#ifndef DONT_ALLOW_USER_CHANGE
 
155
  {"user", 'u', "User for login if not current user.", (char**) &current_user,
 
156
   (char**) &current_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
157
#endif
 
158
  {"verbose", 'v', "Print info about the various stages.", 0, 0, 0, GET_NO_ARG,
 
159
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
160
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
 
161
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
162
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
163
};
 
164
 
 
165
static const char *load_default_groups[] = { "mysqlcheck", "client", 0 };
 
166
 
 
167
 
 
168
static void print_version(void);
 
169
static void usage(void);
 
170
static int get_options(int *argc, char ***argv);
 
171
static int process_all_databases(void);
 
172
static int process_databases(char **db_names);
 
173
static int process_selected_tables(char *db, char **table_names, int tables);
 
174
static int process_all_tables_in_db(char *database);
 
175
static int process_one_db(char *database);
 
176
static int use_db(char *database);
 
177
static int handle_request_for_tables(const char *tables, uint32_t length);
 
178
static int dbConnect(char *host, char *user,char *passwd);
 
179
static void dbDisconnect(char *host);
 
180
static void DBerror(drizzle_con_st *con, const char *when);
 
181
static void safe_exit(int error);
 
182
static void print_result(drizzle_result_st *result);
 
183
static uint32_t fixed_name_length(const char *name);
 
184
static char *fix_table_name(char *dest, const char *src);
 
185
int what_to_do = 0;
 
186
 
 
187
static void print_version(void)
 
188
{
 
189
  printf("%s  Ver %s Distrib %s, for %s (%s)\n", my_progname, CHECK_VERSION,
 
190
         drizzle_version(), SYSTEM_TYPE, MACHINE_TYPE);
 
191
} /* print_version */
 
192
 
 
193
static void usage(void)
 
194
{
 
195
  print_version();
 
196
  puts("By Jani Tolonen, 2001-04-20, MySQL Development Team\n");
 
197
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n");
 
198
  puts("and you are welcome to modify and redistribute it under the GPL license.\n");
 
199
  puts("This program can be used to CHECK (-c,-m,-C), REPAIR (-r), ANALYZE (-a)");
 
200
  puts("or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be");
 
201
  puts("used at the same time. Not all options are supported by all storage engines.");
 
202
  puts("Please consult the Drizzle manual for latest information about the");
 
203
  puts("above. The options -c,-r,-a and -o are exclusive to each other, which");
 
204
  puts("means that the last option will be used, if several was specified.\n");
 
205
  puts("The option -c will be used by default, if none was specified. You");
 
206
  puts("can change the default behavior by making a symbolic link, or");
 
207
  puts("copying this file somewhere with another name, the alternatives are:");
 
208
  puts("mysqlrepair:   The default option will be -r");
 
209
  puts("mysqlanalyze:  The default option will be -a");
 
210
  puts("mysqloptimize: The default option will be -o\n");
 
211
  printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
 
212
  printf("OR     %s [OPTIONS] --databases DB1 [DB2 DB3...]\n",
 
213
   my_progname);
 
214
  printf("OR     %s [OPTIONS] --all-databases\n", my_progname);
 
215
  print_defaults("drizzle", load_default_groups);
 
216
  my_print_help(my_long_options);
 
217
  my_print_variables(my_long_options);
 
218
} /* usage */
 
219
 
 
220
extern "C"
 
221
bool get_one_option(int optid, const struct my_option *, char *argument)
 
222
{
 
223
  char *endchar= NULL;
 
224
  uint64_t temp_drizzle_port= 0;
 
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
    temp_drizzle_port= (uint64_t) strtoul(argument, &endchar, 10);
 
259
    /* if there is an alpha character this is not a valid port */
 
260
    if (strlen(endchar) != 0)
 
261
    {
 
262
      fprintf(stderr, _("Non-integer value supplied for port.  If you are trying to enter a password please use --password instead.\n"));
 
263
      exit(EX_USAGE);
 
264
    }
 
265
    /* If the port number is > 65535 it is not a valid port
 
266
       This also helps with potential data loss casting unsigned long to a
 
267
       uint32_t. */
 
268
    if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
 
269
    {
 
270
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
 
271
      exit(EX_USAGE);
 
272
    }
 
273
    else
 
274
    {
 
275
      opt_drizzle_port= (uint32_t) temp_drizzle_port;
 
276
    }
 
277
    break;
 
278
  case 'P':
 
279
    if (argument)
 
280
    {
 
281
      char *start= argument;
 
282
      if (opt_password)
 
283
        free(opt_password);
 
284
      opt_password = strdup(argument);
 
285
      if (opt_password == NULL)
 
286
      {
 
287
        fprintf(stderr, "Memory allocation error while copying password. "
 
288
                        "Aborting.\n");
 
289
        exit(ENOMEM);
 
290
      }
 
291
      while (*argument)
 
292
      {
 
293
        /* Overwriting password with 'x' */
 
294
        *argument++= 'x';
 
295
      }
 
296
      if (*start)
 
297
      {
 
298
        /* Cut length of argument */
 
299
        start[1] = 0;
 
300
      }
 
301
      tty_password= 0;
 
302
    }
 
303
    else
 
304
      tty_password = 1;
 
305
    break;
 
306
  case 'r':
 
307
    what_to_do = DO_REPAIR;
 
308
    break;
 
309
  case 'g':
 
310
    what_to_do= DO_CHECK;
 
311
    opt_upgrade= 1;
 
312
    break;
 
313
  case OPT_TABLES:
 
314
    opt_databases = 0;
 
315
    break;
 
316
  case 'v':
 
317
    verbose++;
 
318
    break;
 
319
  case 'V': print_version(); exit(0);
 
320
  case OPT_DRIZZLE_PROTOCOL:
 
321
    break;
 
322
  }
 
323
  return 0;
 
324
}
 
325
 
 
326
 
 
327
static int get_options(int *argc, char ***argv)
 
328
{
 
329
  int ho_error;
 
330
 
 
331
  if (*argc == 1)
 
332
  {
 
333
    usage();
 
334
    exit(0);
 
335
  }
 
336
 
 
337
  load_defaults("drizzle", load_default_groups, argc, argv);
 
338
 
 
339
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
 
340
    exit(ho_error);
 
341
 
 
342
  if (!what_to_do)
 
343
  {
 
344
    int pnlen = strlen(my_progname);
 
345
 
 
346
    if (pnlen < 6) /* name too short */
 
347
      what_to_do = DO_CHECK;
 
348
    else if (!strcmp("repair", my_progname + pnlen - 6))
 
349
      what_to_do = DO_REPAIR;
 
350
    else if (!strcmp("analyze", my_progname + pnlen - 7))
 
351
      what_to_do = DO_ANALYZE;
 
352
    else if  (!strcmp("optimize", my_progname + pnlen - 8))
 
353
      what_to_do = DO_OPTIMIZE;
 
354
    else
 
355
      what_to_do = DO_CHECK;
 
356
  }
 
357
 
 
358
  /* TODO: This variable is not yet used */
 
359
  if (strcmp(default_charset, charset_info->csname) &&
 
360
      !(charset_info= get_charset_by_csname(default_charset, MY_CS_PRIMARY)))
 
361
      exit(1);
 
362
  if (*argc > 0 && opt_alldbs)
 
363
  {
 
364
    printf("You should give only options, no arguments at all, with option\n");
 
365
    printf("--all-databases. Please see %s --help for more information.\n",
 
366
     my_progname);
 
367
    return 1;
 
368
  }
 
369
  if (*argc < 1 && !opt_alldbs)
 
370
  {
 
371
    printf("You forgot to give the arguments! Please see %s --help\n",
 
372
     my_progname);
 
373
    printf("for more information.\n");
 
374
    return 1;
 
375
  }
 
376
  if (tty_password)
 
377
    opt_password = client_get_tty_password(NULL);
 
378
  if (debug_info_flag)
 
379
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
 
380
  if (debug_check_flag)
 
381
    my_end_arg= MY_CHECK_ERROR;
 
382
  return(0);
 
383
} /* get_options */
 
384
 
 
385
 
 
386
static int process_all_databases()
 
387
{
 
388
  drizzle_row_t row;
 
389
  drizzle_result_st result;
 
390
  drizzle_return_t ret;
 
391
  int error = 0;
 
392
 
 
393
  if (drizzle_query_str(&dcon, &result, "SHOW DATABASES", &ret) == NULL ||
 
394
      ret != DRIZZLE_RETURN_OK ||
 
395
      drizzle_result_buffer(&result) != DRIZZLE_RETURN_OK)
 
396
  {
 
397
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
 
398
    {
 
399
      fprintf(stderr, "Error: Couldn't execute 'SHOW DATABASES': %s",
 
400
              drizzle_result_error(&result));
 
401
      drizzle_result_free(&result);
 
402
    }
 
403
    else
 
404
    {
 
405
      fprintf(stderr, "Error: Couldn't execute 'SHOW DATABASES': %s",
 
406
              drizzle_con_error(&dcon));
 
407
    }
 
408
 
 
409
    return 1;
 
410
  }
 
411
  while ((row = drizzle_row_next(&result)))
 
412
  {
 
413
    if (process_one_db((char *)row[0]))
 
414
      error = 1;
 
415
  }
 
416
  drizzle_result_free(&result);
 
417
  return error;
 
418
}
 
419
/* process_all_databases */
 
420
 
 
421
 
 
422
static int process_databases(char **db_names)
 
423
{
 
424
  int result = 0;
 
425
  for ( ; *db_names ; db_names++)
 
426
  {
 
427
    if (process_one_db(*db_names))
 
428
      result = 1;
 
429
  }
 
430
  return result;
 
431
} /* process_databases */
 
432
 
 
433
 
 
434
static int process_selected_tables(char *db, char **table_names, int tables)
 
435
{
 
436
  if (use_db(db))
 
437
    return 1;
 
438
  if (opt_all_in_1)
 
439
  {
 
440
    /*
 
441
      We need table list in form `a`, `b`, `c`
 
442
      that's why we need 2 more chars added to to each table name
 
443
      space is for more readable output in logs and in case of error
 
444
    */
 
445
    char *table_names_comma_sep, *end;
 
446
    int i, tot_length = 0;
 
447
 
 
448
    for (i = 0; i < tables; i++)
 
449
      tot_length+= fixed_name_length(*(table_names + i)) + 2;
 
450
 
 
451
    if (!(table_names_comma_sep = (char *)
 
452
          malloc((sizeof(char) * tot_length) + 4)))
 
453
      return 1;
 
454
 
 
455
    for (end = table_names_comma_sep + 1; tables > 0;
 
456
         tables--, table_names++)
 
457
    {
 
458
      end= fix_table_name(end, *table_names);
 
459
      *end++= ',';
 
460
    }
 
461
    *--end = 0;
 
462
    handle_request_for_tables(table_names_comma_sep + 1, tot_length - 1);
 
463
    free(table_names_comma_sep);
 
464
  }
 
465
  else
 
466
    for (; tables > 0; tables--, table_names++)
 
467
      handle_request_for_tables(*table_names, fixed_name_length(*table_names));
 
468
  return 0;
 
469
} /* process_selected_tables */
 
470
 
 
471
 
 
472
static uint32_t fixed_name_length(const char *name)
 
473
{
 
474
  const char *p;
 
475
  uint32_t extra_length= 2;  /* count the first/last backticks */
 
476
 
 
477
  for (p= name; *p; p++)
 
478
  {
 
479
    if (*p == '`')
 
480
      extra_length++;
 
481
    else if (*p == '.')
 
482
      extra_length+= 2;
 
483
  }
 
484
  return (p - name) + extra_length;
 
485
}
 
486
 
 
487
 
 
488
static char *fix_table_name(char *dest, const char *src)
 
489
{
 
490
  *dest++= '`';
 
491
  for (; *src; src++)
 
492
  {
 
493
    switch (*src) {
 
494
    case '.':            /* add backticks around '.' */
 
495
      *dest++= '`';
 
496
      *dest++= '.';
 
497
      *dest++= '`';
 
498
      break;
 
499
    case '`':            /* escape backtick character */
 
500
      *dest++= '`';
 
501
      /* fall through */
 
502
    default:
 
503
      *dest++= *src;
 
504
    }
 
505
  }
 
506
  *dest++= '`';
 
507
  return dest;
 
508
}
 
509
 
 
510
 
 
511
static int process_all_tables_in_db(char *database)
 
512
{
 
513
  drizzle_result_st result;
 
514
  drizzle_row_t row;
 
515
  drizzle_return_t ret;
 
516
  uint32_t num_columns;
 
517
 
 
518
  if (use_db(database))
 
519
    return 1;
 
520
  if (drizzle_query_str(&dcon, &result, "SHOW /*!50002 FULL*/ TABLES",
 
521
       &ret) == NULL ||
 
522
      ret != DRIZZLE_RETURN_OK ||
 
523
      drizzle_result_buffer(&result) != DRIZZLE_RETURN_OK)
 
524
  {
 
525
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
 
526
      drizzle_result_free(&result);
 
527
    return 1;
 
528
  }
 
529
 
 
530
  num_columns= drizzle_result_column_count(&result);
 
531
 
 
532
  if (opt_all_in_1)
 
533
  {
 
534
    /*
 
535
      We need table list in form `a`, `b`, `c`
 
536
      that's why we need 2 more chars added to to each table name
 
537
      space is for more readable output in logs and in case of error
 
538
     */
 
539
 
 
540
    char *tables, *end;
 
541
    uint32_t tot_length = 0;
 
542
 
 
543
    while ((row = drizzle_row_next(&result)))
 
544
      tot_length+= fixed_name_length((char *)row[0]) + 2;
 
545
    drizzle_row_seek(&result, 0);
 
546
 
 
547
    if (!(tables=(char *) malloc(sizeof(char)*tot_length+4)))
 
548
    {
 
549
      drizzle_result_free(&result);
 
550
      return 1;
 
551
    }
 
552
    for (end = tables + 1; (row = drizzle_row_next(&result)) ;)
 
553
    {
 
554
      if ((num_columns == 2) && (strcmp((char *)row[1], "VIEW") == 0))
 
555
        continue;
 
556
 
 
557
      end= fix_table_name(end, (char *)row[0]);
 
558
      *end++= ',';
 
559
    }
 
560
    *--end = 0;
 
561
    if (tot_length)
 
562
      handle_request_for_tables(tables + 1, tot_length - 1);
 
563
    free(tables);
 
564
  }
 
565
  else
 
566
  {
 
567
    while ((row = drizzle_row_next(&result)))
 
568
    {
 
569
      /* Skip views if we don't perform renaming. */
 
570
      if ((what_to_do != DO_UPGRADE) && (num_columns == 2) && (strcmp((char *)row[1], "VIEW") == 0))
 
571
        continue;
 
572
 
 
573
      handle_request_for_tables((char *)row[0],
 
574
                                fixed_name_length((char *)row[0]));
 
575
    }
 
576
  }
 
577
  drizzle_result_free(&result);
 
578
  return 0;
 
579
} /* process_all_tables_in_db */
 
580
 
 
581
 
 
582
 
 
583
static int fix_table_storage_name(const char *name)
 
584
{
 
585
  char qbuf[100 + DRIZZLE_MAX_COLUMN_NAME_SIZE*4];
 
586
  drizzle_result_st result;
 
587
  drizzle_return_t ret;
 
588
  int rc= 0;
 
589
  if (strncmp(name, "#mysql50#", 9))
 
590
    return 1;
 
591
  sprintf(qbuf, "RENAME TABLE `%s` TO `%s`", name, name + 9);
 
592
  if (drizzle_query_str(&dcon, &result, qbuf, &ret) == NULL ||
 
593
      ret != DRIZZLE_RETURN_OK)
 
594
  {
 
595
    fprintf(stderr, "Failed to %s\n", qbuf);
 
596
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
 
597
    {
 
598
      fprintf(stderr, "Error: %s\n", drizzle_result_error(&result));
 
599
      drizzle_result_free(&result);
 
600
    }
 
601
    else
 
602
      fprintf(stderr, "Error: %s\n", drizzle_con_error(&dcon));
 
603
    rc= 1;
 
604
  }
 
605
  else
 
606
    drizzle_result_free(&result);
 
607
  if (verbose)
 
608
    printf("%-50s %s\n", name, rc ? "FAILED" : "OK");
 
609
  return rc;
 
610
}
 
611
 
 
612
static int fix_database_storage_name(const char *name)
 
613
{
 
614
  char qbuf[100 + DRIZZLE_MAX_COLUMN_NAME_SIZE*4];
 
615
  drizzle_result_st result;
 
616
  drizzle_return_t ret;
 
617
  int rc= 0;
 
618
  if (strncmp(name, "#mysql50#", 9))
 
619
    return 1;
 
620
  sprintf(qbuf, "ALTER DATABASE `%s` UPGRADE DATA DIRECTORY NAME", name);
 
621
  if (drizzle_query_str(&dcon, &result, qbuf, &ret) == NULL ||
 
622
      ret != DRIZZLE_RETURN_OK)
 
623
  {
 
624
    fprintf(stderr, "Failed to %s\n", qbuf);
 
625
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
 
626
    {
 
627
      fprintf(stderr, "Error: %s\n", drizzle_result_error(&result));
 
628
      drizzle_result_free(&result);
 
629
    }
 
630
    else
 
631
      fprintf(stderr, "Error: %s\n", drizzle_con_error(&dcon));
 
632
    rc= 1;
 
633
  }
 
634
  else
 
635
    drizzle_result_free(&result);
 
636
  if (verbose)
 
637
    printf("%-50s %s\n", name, rc ? "FAILED" : "OK");
 
638
  return rc;
 
639
}
 
640
 
 
641
static int process_one_db(char *database)
 
642
{
 
643
  if (what_to_do == DO_UPGRADE)
 
644
  {
 
645
    int rc= 0;
 
646
    if (opt_fix_db_names && !strncmp(database,"#mysql50#", 9))
 
647
    {
 
648
      rc= fix_database_storage_name(database);
 
649
      database+= 9;
 
650
    }
 
651
    if (rc || !opt_fix_table_names)
 
652
      return rc;
 
653
  }
 
654
  return process_all_tables_in_db(database);
 
655
}
 
656
 
 
657
 
 
658
static int use_db(char *database)
 
659
{
 
660
  drizzle_result_st result;
 
661
  drizzle_return_t ret;
 
662
  if (drizzle_con_server_version_number(&dcon) >= 50003 &&
 
663
      !my_strcasecmp(&my_charset_utf8_general_ci, database, "information_schema"))
 
664
    return 1;
 
665
  if (drizzle_select_db(&dcon, &result, database, &ret) == NULL ||
 
666
      ret != DRIZZLE_RETURN_OK)
 
667
  {
 
668
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
 
669
    {
 
670
      fprintf(stderr,"Got error: %s when selecting the database",
 
671
              drizzle_result_error(&result));
 
672
      safe_exit(EX_MYSQLERR);
 
673
      drizzle_result_free(&result);
 
674
    }
 
675
    else
 
676
      DBerror(&dcon, "when selecting the database");
 
677
    return 1;
 
678
  }
 
679
  drizzle_result_free(&result);
 
680
  return 0;
 
681
} /* use_db */
 
682
 
 
683
 
 
684
static int handle_request_for_tables(const char *tables, uint32_t length)
 
685
{
 
686
  char *query, *end, options[100], message[100];
 
687
  uint32_t query_length= 0;
 
688
  const char *op = 0;
 
689
  drizzle_result_st result;
 
690
  drizzle_return_t ret;
 
691
 
 
692
  options[0] = 0;
 
693
  end = options;
 
694
  switch (what_to_do) {
 
695
  case DO_CHECK:
 
696
    op = "CHECK";
 
697
    if (opt_quick)              end = strcpy(end, " QUICK")+6;
 
698
    if (opt_fast)               end = strcpy(end, " FAST")+5;
 
699
    if (opt_medium_check)       end = strcpy(end, " MEDIUM")+7; /* Default */
 
700
    if (opt_extended)           end = strcpy(end, " EXTENDED")+9;
 
701
    if (opt_check_only_changed) end = strcpy(end, " CHANGED")+8;
 
702
    if (opt_upgrade)            end = strcpy(end, " FOR UPGRADE")+12;
 
703
    break;
 
704
  case DO_REPAIR:
 
705
    op= (opt_write_binlog) ? "REPAIR" : "REPAIR NO_WRITE_TO_BINLOG";
 
706
    if (opt_quick)              end = strcpy(end, " QUICK")+6;
 
707
    if (opt_extended)           end = strcpy(end, " EXTENDED")+9;
 
708
    if (opt_frm)                end = strcpy(end, " USE_FRM")+8;
 
709
    break;
 
710
  case DO_ANALYZE:
 
711
    op= (opt_write_binlog) ? "ANALYZE" : "ANALYZE NO_WRITE_TO_BINLOG";
 
712
    break;
 
713
  case DO_OPTIMIZE:
 
714
    op= (opt_write_binlog) ? "OPTIMIZE" : "OPTIMIZE NO_WRITE_TO_BINLOG";
 
715
    break;
 
716
  case DO_UPGRADE:
 
717
    return fix_table_storage_name(tables);
 
718
  }
 
719
 
 
720
  if (!(query =(char *) malloc((sizeof(char)*(length+110)))))
 
721
    return 1;
 
722
  if (opt_all_in_1)
 
723
  {
 
724
    /* No backticks here as we added them before */
 
725
    query_length= sprintf(query, "%s TABLE %s %s", op, tables, options);
 
726
  }
 
727
  else
 
728
  {
 
729
    char *ptr;
 
730
    ptr= query;
 
731
    ptr= strcpy(query, op)+strlen(op);
 
732
    ptr= strcpy(ptr, " TABLE ")+7;
 
733
    ptr= fix_table_name(ptr, tables);
 
734
    ptr+= sprintf(ptr," %s",options);
 
735
    query_length= (uint32_t) (ptr - query);
 
736
  }
 
737
  if (drizzle_query(&dcon, &result, query, query_length, &ret) == NULL ||
 
738
      ret != DRIZZLE_RETURN_OK ||
 
739
      drizzle_result_buffer(&result) != DRIZZLE_RETURN_OK)
 
740
  {
 
741
    sprintf(message, "when executing '%s TABLE ... %s'", op, options);
 
742
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
 
743
    {
 
744
      fprintf(stderr,"Got error: %s %s",
 
745
              drizzle_result_error(&result), message);
 
746
      safe_exit(EX_MYSQLERR);
 
747
      drizzle_result_free(&result);
 
748
    }
 
749
    else
 
750
      DBerror(&dcon, message);
 
751
    return 1;
 
752
  }
 
753
  print_result(&result);
 
754
  drizzle_result_free(&result);
 
755
  free(query);
 
756
  return 0;
 
757
}
 
758
 
 
759
 
 
760
static void print_result(drizzle_result_st *result)
 
761
{
 
762
  drizzle_row_t row;
 
763
  char prev[DRIZZLE_MAX_COLUMN_NAME_SIZE*2+2];
 
764
  uint32_t i;
 
765
  bool found_error=0;
 
766
 
 
767
  prev[0] = '\0';
 
768
  for (i = 0; (row = drizzle_row_next(result)); i++)
 
769
  {
 
770
    int changed = strcmp(prev, (char *)row[0]);
 
771
    bool status = !strcmp((char *)row[2], "status");
 
772
 
 
773
    if (status)
 
774
    {
 
775
      /*
 
776
        if there was an error with the table, we have --auto-repair set,
 
777
        and this isn't a repair op, then add the table to the tables4repair
 
778
        list
 
779
      */
 
780
      if (found_error && opt_auto_repair && what_to_do != DO_REPAIR &&
 
781
          strcmp((char *)row[3],"OK"))
 
782
        tables4repair.push_back(string(prev));
 
783
      found_error=0;
 
784
      if (opt_silent)
 
785
        continue;
 
786
    }
 
787
    if (status && changed)
 
788
      printf("%-50s %s", row[0], row[3]);
 
789
    else if (!status && changed)
 
790
    {
 
791
      printf("%s\n%-9s: %s", row[0], row[2], row[3]);
 
792
      if (strcmp((char *)row[2],"note"))
 
793
        found_error=1;
 
794
    }
 
795
    else
 
796
      printf("%-9s: %s", (char *)row[2], (char *)row[3]);
 
797
    strcpy(prev, (char *)row[0]);
 
798
    putchar('\n');
 
799
  }
 
800
  /* add the last table to be repaired to the list */
 
801
  if (found_error && opt_auto_repair && what_to_do != DO_REPAIR)
 
802
    tables4repair.push_back(string(prev));
 
803
}
 
804
 
 
805
 
 
806
static int dbConnect(char *host, char *user, char *passwd)
 
807
{
 
808
 
 
809
  if (verbose)
 
810
  {
 
811
    fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost");
 
812
  }
 
813
  drizzle_create(&drizzle);
 
814
  drizzle_con_create(&drizzle, &dcon);
 
815
  drizzle_con_set_tcp(&dcon, host, opt_drizzle_port);
 
816
  drizzle_con_set_auth(&dcon, user, passwd);
 
817
  if (drizzle_con_connect(&dcon) != DRIZZLE_RETURN_OK)
 
818
  {
 
819
    DBerror(&dcon, "when trying to connect");
 
820
    return 1;
 
821
  }
 
822
  return 0;
 
823
} /* dbConnect */
 
824
 
 
825
 
 
826
static void dbDisconnect(char *host)
 
827
{
 
828
  if (verbose)
 
829
    fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
 
830
  drizzle_free(&drizzle);
 
831
} /* dbDisconnect */
 
832
 
 
833
 
 
834
static void DBerror(drizzle_con_st *con, const char *when)
 
835
{
 
836
  fprintf(stderr,"Got error: %s %s", drizzle_con_error(con), when);
 
837
  safe_exit(EX_MYSQLERR);
 
838
  return;
 
839
} /* DBerror */
 
840
 
 
841
 
 
842
static void safe_exit(int error)
 
843
{
 
844
  if (!first_error)
 
845
    first_error= error;
 
846
  if (ignore_errors)
 
847
    return;
 
848
  drizzle_free(&drizzle);
 
849
  exit(error);
 
850
}
 
851
 
 
852
 
 
853
int main(int argc, char **argv)
 
854
{
 
855
  MY_INIT(argv[0]);
 
856
  /*
 
857
  ** Check out the args
 
858
  */
 
859
  if (get_options(&argc, &argv))
 
860
  {
 
861
    my_end(my_end_arg);
 
862
    exit(EX_USAGE);
 
863
  }
 
864
  if (dbConnect(current_host, current_user, opt_password))
 
865
    exit(EX_MYSQLERR);
 
866
 
 
867
  if (opt_auto_repair)
 
868
  {
 
869
    tables4repair.reserve(64);
 
870
    if (tables4repair.capacity() == 0)
 
871
    {
 
872
      first_error = 1;
 
873
      goto end;
 
874
    }
 
875
  }
 
876
 
 
877
 
 
878
  if (opt_alldbs)
 
879
    process_all_databases();
 
880
  /* Only one database and selected table(s) */
 
881
  else if (argc > 1 && !opt_databases)
 
882
    process_selected_tables(*argv, (argv + 1), (argc - 1));
 
883
  /* One or more databases, all tables */
 
884
  else
 
885
    process_databases(argv);
 
886
  if (opt_auto_repair)
 
887
  {
 
888
 
 
889
    if (!opt_silent && (tables4repair.size() > 0))
 
890
      puts("\nRepairing tables");
 
891
    what_to_do = DO_REPAIR;
 
892
    vector<string>::iterator i;
 
893
    for ( i= tables4repair.begin() ; i < tables4repair.end() ; i++)
 
894
    {
 
895
      const char *name= (*i).c_str();
 
896
      handle_request_for_tables(name, fixed_name_length(name));
 
897
    }
 
898
  }
 
899
 end:
 
900
  dbDisconnect(current_host);
 
901
  free(opt_password);
 
902
  my_end(my_end_arg);
 
903
  return(first_error!=0);
 
904
} /* main */