~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzlecheck.cc

  • Committer: Brian Aker
  • Date: 2009-02-05 09:11:16 UTC
  • Revision ID: brian@tangent.org-20090205091116-iy0ersp6bhyzt1ad
Removed dead variables.

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