1/*
2 Copyright (c) 2001, 2013, Oracle and/or its affiliates.
3 Copyright (c) 2010, 2017, MariaDB
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19/* By Jani Tolonen, 2001-04-20, MySQL Development Team */
20
21#define CHECK_VERSION "2.7.4-MariaDB"
22
23#include "client_priv.h"
24#include <m_ctype.h>
25#include <mysql_version.h>
26#include <mysqld_error.h>
27#include <sslopt-vars.h>
28#include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
29
30/* Exit codes */
31
32#define EX_USAGE 1
33#define EX_MYSQLERR 2
34
35/* ALTER instead of repair. */
36#define MAX_ALTER_STR_SIZE 128 * 1024
37#define KEY_PARTITIONING_CHANGED_STR "KEY () partitioning changed"
38
39static MYSQL mysql_connection, *sock = 0;
40static my_bool opt_alldbs = 0, opt_check_only_changed = 0, opt_extended = 0,
41 opt_compress = 0, opt_databases = 0, opt_fast = 0,
42 opt_medium_check = 0, opt_quick = 0, opt_all_in_1 = 0,
43 opt_silent = 0, opt_auto_repair = 0, ignore_errors = 0,
44 tty_password= 0, opt_frm= 0, debug_info_flag= 0, debug_check_flag= 0,
45 opt_fix_table_names= 0, opt_fix_db_names= 0, opt_upgrade= 0,
46 opt_persistent_all= 0, opt_do_tables= 1;
47static my_bool opt_write_binlog= 1, opt_flush_tables= 0;
48static uint verbose = 0, opt_mysql_port=0;
49static int my_end_arg;
50static char * opt_mysql_unix_port = 0;
51static char *opt_password = 0, *current_user = 0,
52 *default_charset= 0, *current_host= 0;
53static char *opt_plugin_dir= 0, *opt_default_auth= 0;
54static int first_error = 0;
55static char *opt_skip_database;
56DYNAMIC_ARRAY tables4repair, tables4rebuild, alter_table_cmds;
57DYNAMIC_ARRAY views4repair;
58static char *shared_memory_base_name=0;
59static uint opt_protocol=0;
60
61enum operations { DO_CHECK=1, DO_REPAIR, DO_ANALYZE, DO_OPTIMIZE, DO_FIX_NAMES };
62const char *operation_name[]=
63{
64 "???", "check", "repair", "analyze", "optimize", "fix names"
65};
66
67typedef enum { DO_VIEWS_NO, DO_VIEWS_YES, DO_VIEWS_FROM_MYSQL } enum_do_views;
68const char *do_views_opts[]= {"NO", "YES", "UPGRADE_FROM_MYSQL", NullS};
69TYPELIB do_views_typelib= { array_elements(do_views_opts) - 1, "",
70 do_views_opts, NULL };
71static ulong opt_do_views= DO_VIEWS_NO;
72
73static struct my_option my_long_options[] =
74{
75 {"all-databases", 'A',
76 "Check all the databases. This is the same as --databases with all databases selected.",
77 &opt_alldbs, &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
78 0, 0},
79 {"analyze", 'a', "Analyze given tables.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
80 0, 0, 0, 0},
81 {"all-in-1", '1',
82 "Instead of issuing one query for each table, use one query per database, naming all tables in the database in a comma-separated list.",
83 &opt_all_in_1, &opt_all_in_1, 0, GET_BOOL, NO_ARG, 0, 0, 0,
84 0, 0, 0},
85 {"auto-repair", OPT_AUTO_REPAIR,
86 "If a checked table is corrupted, automatically fix it. Repairing will be done after all tables have been checked, if corrupted ones were found.",
87 &opt_auto_repair, &opt_auto_repair, 0, GET_BOOL, NO_ARG, 0,
88 0, 0, 0, 0, 0},
89 {"character-sets-dir", OPT_CHARSETS_DIR,
90 "Directory for character set files.", (char**) &charsets_dir,
91 (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
92 {"check", 'c', "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
93 0, 0, 0, 0},
94 {"check-only-changed", 'C',
95 "Check only tables that have changed since last check or haven't been closed properly.",
96 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
97 {"check-upgrade", 'g',
98 "Check tables for version-dependent changes. May be used with --auto-repair to correct tables requiring version-dependent updates.",
99 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
100 {"compress", OPT_COMPRESS, "Use compression in server/client protocol.",
101 &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
102 0, 0, 0},
103 {"databases", 'B',
104 "Check several databases. Note the difference in usage; in this case no tables are given. All name arguments are regarded as database names.",
105 &opt_databases, &opt_databases, 0, GET_BOOL, NO_ARG,
106 0, 0, 0, 0, 0, 0},
107#ifdef DBUG_OFF
108 {"debug", '#', "This is a non-debug version. Catch this and exit.",
109 0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
110#else
111 {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
112 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
113#endif
114 {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
115 &debug_check_flag, &debug_check_flag, 0,
116 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
117 {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
118 &debug_info_flag, &debug_info_flag,
119 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
120 {"default-character-set", OPT_DEFAULT_CHARSET,
121 "Set the default character set.", &default_charset,
122 &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
123 {"default_auth", OPT_DEFAULT_AUTH,
124 "Default authentication client-side plugin to use.",
125 &opt_default_auth, &opt_default_auth, 0,
126 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
127 {"fast",'F', "Check only tables that haven't been closed properly.",
128 &opt_fast, &opt_fast, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
129 0},
130 {"fix-db-names", OPT_FIX_DB_NAMES, "Fix database names.",
131 &opt_fix_db_names, &opt_fix_db_names,
132 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
133 {"fix-table-names", OPT_FIX_TABLE_NAMES, "Fix table names.",
134 &opt_fix_table_names, &opt_fix_table_names,
135 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
136 {"force", 'f', "Continue even if we get an SQL error.",
137 &ignore_errors, &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
138 0, 0, 0, 0},
139 {"extended", 'e',
140 "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.",
141 &opt_extended, &opt_extended, 0, GET_BOOL, NO_ARG, 0, 0, 0,
142 0, 0, 0},
143 {"flush", OPT_FLUSH_TABLES, "Flush each table after check. This is useful if you don't want to have the checked tables take up space in the caches after the check",
144 &opt_flush_tables, &opt_flush_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
145 0, 0 },
146 {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
147 NO_ARG, 0, 0, 0, 0, 0, 0},
148 {"host",'h', "Connect to host.", &current_host,
149 &current_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
150 {"medium-check", 'm',
151 "Faster than extended-check, but only finds 99.99 percent of all errors. Should be good enough for most cases.",
152 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
153 {"write-binlog", OPT_WRITE_BINLOG,
154 "Log ANALYZE, OPTIMIZE and REPAIR TABLE commands. Use --skip-write-binlog "
155 "when commands should not be sent to replication slaves.",
156 &opt_write_binlog, &opt_write_binlog, 0, GET_BOOL, NO_ARG,
157 1, 0, 0, 0, 0, 0},
158 {"optimize", 'o', "Optimize table.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0,
159 0, 0},
160 {"password", 'p',
161 "Password to use when connecting to server. If password is not given, it's solicited on the tty.",
162 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
163 {"persistent", 'Z',
164 "When using ANALYZE TABLE use the PERSISTENT FOR ALL option.",
165 &opt_persistent_all, &opt_persistent_all, 0, GET_BOOL, NO_ARG,
166 0, 0, 0, 0, 0, 0},
167#ifdef __WIN__
168 {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
169 NO_ARG, 0, 0, 0, 0, 0, 0},
170#endif
171 {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
172 &opt_plugin_dir, &opt_plugin_dir, 0,
173 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
174 {"port", 'P', "Port number to use for connection or 0 for default to, in "
175 "order of preference, my.cnf, $MYSQL_TCP_PORT, "
176#if MYSQL_PORT_DEFAULT == 0
177 "/etc/services, "
178#endif
179 "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
180 &opt_mysql_port, &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
181 0},
182 {"protocol", OPT_MYSQL_PROTOCOL, "The protocol to use for connection (tcp, socket, pipe, memory).",
183 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
184 {"quick", 'q',
185 "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.",
186 &opt_quick, &opt_quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
187 0},
188 {"repair", 'r',
189 "Can fix almost anything except unique keys that aren't unique.",
190 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
191#ifdef HAVE_SMEM
192 {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
193 "Base name of shared memory.", &shared_memory_base_name, &shared_memory_base_name,
194 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
195#endif
196 {"silent", 's', "Print only error messages.", &opt_silent,
197 &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
198 {"skip_database", 0, "Don't process the database specified as argument",
199 &opt_skip_database, &opt_skip_database, 0, GET_STR, REQUIRED_ARG,
200 0, 0, 0, 0, 0, 0},
201 {"socket", 'S', "The socket file to use for connection.",
202 &opt_mysql_unix_port, &opt_mysql_unix_port, 0, GET_STR,
203 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
204#include <sslopt-longopts.h>
205 {"tables", OPT_TABLES, "Overrides option --databases (-B).", 0, 0, 0,
206 GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
207 {"use-frm", OPT_FRM,
208 "When used with REPAIR, get table structure from .frm file, so the table can be repaired even if .MYI header is corrupted.",
209 &opt_frm, &opt_frm, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
210 0},
211#ifndef DONT_ALLOW_USER_CHANGE
212 {"user", 'u', "User for login if not current user.", &current_user,
213 &current_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
214#endif
215 {"verbose", 'v', "Print info about the various stages; Using it 3 times will print out all CHECK, RENAME and ALTER TABLE during the check phase.",
216 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
217 {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
218 NO_ARG, 0, 0, 0, 0, 0, 0},
219 {"process-views", 0,
220 "Perform the requested operation (check or repair) on views. "
221 "One of: NO, YES (correct the checksum, if necessary, add the "
222 "mariadb-version field), UPGRADE_FROM_MYSQL (same as YES and toggle "
223 "the algorithm MERGE<->TEMPTABLE.", &opt_do_views, &opt_do_views,
224 &do_views_typelib, GET_ENUM, OPT_ARG, 0, 0, 0, 0, 0, 0},
225 {"process-tables", 0, "Perform the requested operation on tables.",
226 &opt_do_tables, &opt_do_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
227 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
228};
229
230static const char *load_default_groups[]=
231{ "mysqlcheck", "client", "client-server", "client-mariadb", 0 };
232
233
234static void print_version(void);
235static void usage(void);
236static int get_options(int *argc, char ***argv);
237static int process_all_databases();
238static int process_databases(char **db_names);
239static int process_selected_tables(char *db, char **table_names, int tables);
240static int process_all_tables_in_db(char *database);
241static int process_one_db(char *database);
242static int use_db(char *database);
243static int handle_request_for_tables(char *, size_t, my_bool, my_bool);
244static int dbConnect(char *host, char *user,char *passwd);
245static void dbDisconnect(char *host);
246static void DBerror(MYSQL *mysql, const char *when);
247static void safe_exit(int error);
248static void print_result();
249static size_t fixed_name_length(const char *name);
250static char *fix_table_name(char *dest, char *src);
251int what_to_do = 0;
252
253
254static void print_version(void)
255{
256 printf("%s Ver %s Distrib %s, for %s (%s)\n", my_progname, CHECK_VERSION,
257 MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
258} /* print_version */
259
260
261static void usage(void)
262{
263 DBUG_ENTER("usage");
264 print_version();
265 puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
266 puts("This program can be used to CHECK (-c, -m, -C), REPAIR (-r), ANALYZE (-a),");
267 puts("or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be");
268 puts("used at the same time. Not all options are supported by all storage engines.");
269 puts("The options -c, -r, -a, and -o are exclusive to each other, which");
270 puts("means that the last option will be used, if several was specified.\n");
271 puts("The option -c (--check) will be used by default, if none was specified.");
272 puts("You can change the default behavior by making a symbolic link, or");
273 puts("copying this file somewhere with another name, the alternatives are:");
274 puts("mysqlrepair: The default option will be -r");
275 puts("mysqlanalyze: The default option will be -a");
276 puts("mysqloptimize: The default option will be -o\n");
277 printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
278 printf("OR %s [OPTIONS] --databases DB1 [DB2 DB3...]\n",
279 my_progname);
280 puts("Please consult the MariaDB Knowledge Base at");
281 puts("https://mariadb.com/kb/en/mysqlcheck for latest information about");
282 puts("this program.");
283 print_defaults("my", load_default_groups);
284 puts("");
285 my_print_help(my_long_options);
286 my_print_variables(my_long_options);
287 DBUG_VOID_RETURN;
288} /* usage */
289
290
291static my_bool
292get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
293 char *argument)
294{
295 int orig_what_to_do= what_to_do;
296 DBUG_ENTER("get_one_option");
297
298 switch(optid) {
299 case 'a':
300 what_to_do = DO_ANALYZE;
301 break;
302 case 'c':
303 what_to_do = DO_CHECK;
304 break;
305 case 'C':
306 what_to_do = DO_CHECK;
307 opt_check_only_changed = 1;
308 break;
309 case 'I': /* Fall through */
310 case '?':
311 usage();
312 exit(0);
313 case 'm':
314 what_to_do = DO_CHECK;
315 opt_medium_check = 1;
316 break;
317 case 'o':
318 what_to_do = DO_OPTIMIZE;
319 break;
320 case OPT_FIX_DB_NAMES:
321 what_to_do= DO_FIX_NAMES;
322 opt_databases= 1;
323 break;
324 case OPT_FIX_TABLE_NAMES:
325 what_to_do= DO_FIX_NAMES;
326 break;
327 case 'p':
328 if (argument == disabled_my_option)
329 argument= (char*) ""; /* Don't require password */
330 if (argument)
331 {
332 char *start = argument;
333 my_free(opt_password);
334 opt_password = my_strdup(argument, MYF(MY_FAE));
335 while (*argument) *argument++= 'x'; /* Destroy argument */
336 if (*start)
337 start[1] = 0; /* Cut length of argument */
338 tty_password= 0;
339 }
340 else
341 tty_password = 1;
342 break;
343 case 'r':
344 what_to_do = DO_REPAIR;
345 break;
346 case 'g':
347 what_to_do= DO_CHECK;
348 opt_upgrade= 1;
349 break;
350 case 'W':
351#ifdef __WIN__
352 opt_protocol = MYSQL_PROTOCOL_PIPE;
353#endif
354 break;
355 case '#':
356 DBUG_PUSH(argument ? argument : "d:t:o");
357 debug_check_flag= 1;
358 break;
359#include <sslopt-case.h>
360 case OPT_TABLES:
361 opt_databases = 0;
362 break;
363 case 'v':
364 verbose++;
365 break;
366 case 'V':
367 print_version(); exit(0);
368 break;
369 case OPT_MYSQL_PROTOCOL:
370 if ((opt_protocol= find_type_with_warning(argument, &sql_protocol_typelib,
371 opt->name)) <= 0)
372 {
373 sf_leaking_memory= 1; /* no memory leak reports here */
374 exit(1);
375 }
376 break;
377 }
378
379 if (orig_what_to_do && (what_to_do != orig_what_to_do))
380 {
381 fprintf(stderr, "Error: %s doesn't support multiple contradicting commands.\n",
382 my_progname);
383 DBUG_RETURN(1);
384 }
385 DBUG_RETURN(0);
386}
387
388
389static int get_options(int *argc, char ***argv)
390{
391 int ho_error;
392 DBUG_ENTER("get_options");
393
394 if (*argc == 1)
395 {
396 usage();
397 exit(0);
398 }
399
400 if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
401 exit(ho_error);
402
403 if (what_to_do == DO_REPAIR && !opt_do_views && !opt_do_tables)
404 {
405 fprintf(stderr, "Error: Nothing to repair when both "
406 "--process-tables=NO and --process-views=NO\n");
407 exit(1);
408 }
409 if (!what_to_do)
410 {
411 size_t pnlen= strlen(my_progname);
412
413 if (pnlen < 6) /* name too short */
414 what_to_do = DO_CHECK;
415 else if (!strcmp("repair", my_progname + pnlen - 6))
416 what_to_do = DO_REPAIR;
417 else if (!strcmp("analyze", my_progname + pnlen - 7))
418 what_to_do = DO_ANALYZE;
419 else if (!strcmp("optimize", my_progname + pnlen - 8))
420 what_to_do = DO_OPTIMIZE;
421 else
422 what_to_do = DO_CHECK;
423 }
424
425 if (opt_do_views && what_to_do != DO_REPAIR && what_to_do != DO_CHECK)
426 {
427 fprintf(stderr, "Error: %s doesn't support %s for views.\n",
428 my_progname, operation_name[what_to_do]);
429 exit(1);
430 }
431
432 /*
433 If there's no --default-character-set option given with
434 --fix-table-name or --fix-db-name set the default character set to "utf8".
435 */
436 if (!default_charset)
437 {
438 if (opt_fix_db_names || opt_fix_table_names)
439 default_charset= (char*) "utf8";
440 else
441 default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME;
442 }
443 if (strcmp(default_charset, MYSQL_AUTODETECT_CHARSET_NAME) &&
444 !get_charset_by_csname(default_charset, MY_CS_PRIMARY, MYF(MY_WME)))
445 {
446 printf("Unsupported character set: %s\n", default_charset);
447 DBUG_RETURN(1);
448 }
449 if (*argc > 0 && opt_alldbs)
450 {
451 printf("You should give only options, no arguments at all, with option\n");
452 printf("--all-databases. Please see %s --help for more information.\n",
453 my_progname);
454 DBUG_RETURN(1);
455 }
456 if (*argc < 1 && !opt_alldbs)
457 {
458 printf("You forgot to give the arguments! Please see %s --help\n",
459 my_progname);
460 printf("for more information.\n");
461 DBUG_RETURN(1);
462 }
463 if (tty_password)
464 opt_password = get_tty_password(NullS);
465 if (debug_info_flag)
466 my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
467 if (debug_check_flag)
468 my_end_arg= MY_CHECK_ERROR;
469 DBUG_RETURN((0));
470} /* get_options */
471
472
473static int process_all_databases()
474{
475 MYSQL_ROW row;
476 MYSQL_RES *tableres;
477 int result = 0;
478 DBUG_ENTER("process_all_databases");
479
480 if (mysql_query(sock, "SHOW DATABASES") ||
481 !(tableres = mysql_store_result(sock)))
482 {
483 my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
484 MYF(0), mysql_error(sock));
485 DBUG_RETURN(1);
486 }
487 if (verbose)
488 printf("Processing databases\n");
489 while ((row = mysql_fetch_row(tableres)))
490 {
491 if (process_one_db(row[0]))
492 result = 1;
493 }
494 mysql_free_result(tableres);
495 DBUG_RETURN(result);
496}
497/* process_all_databases */
498
499
500static int process_databases(char **db_names)
501{
502 int result = 0;
503 DBUG_ENTER("process_databases");
504
505 if (verbose)
506 printf("Processing databases\n");
507 for ( ; *db_names ; db_names++)
508 {
509 if (process_one_db(*db_names))
510 result = 1;
511 }
512 DBUG_RETURN(result);
513} /* process_databases */
514
515
516/* returns: -1 for error, 1 for view, 0 for table */
517static int is_view(const char *table)
518{
519 char query[1024];
520 MYSQL_RES *res;
521 MYSQL_FIELD *field;
522 int view;
523 DBUG_ENTER("is_view");
524
525 my_snprintf(query, sizeof(query), "SHOW CREATE TABLE %`s", table);
526 if (mysql_query(sock, query))
527 {
528 fprintf(stderr, "Failed to %s\n", query);
529 fprintf(stderr, "Error: %s\n", mysql_error(sock));
530 DBUG_RETURN(-1);
531 }
532 res= mysql_store_result(sock);
533 field= mysql_fetch_field(res);
534 view= (strcmp(field->name,"View") == 0) ? 1 : 0;
535 mysql_free_result(res);
536
537 DBUG_RETURN(view);
538}
539
540static int process_selected_tables(char *db, char **table_names, int tables)
541{
542 int view;
543 char *table;
544 size_t table_len;
545 DBUG_ENTER("process_selected_tables");
546
547 if (use_db(db))
548 DBUG_RETURN(1);
549 if (opt_all_in_1 && what_to_do != DO_FIX_NAMES)
550 {
551 /*
552 We need table list in form `a`, `b`, `c`
553 that's why we need 2 more chars added to to each table name
554 space is for more readable output in logs and in case of error
555 */
556 char *table_names_comma_sep, *end;
557 size_t tot_length= 0;
558 int i= 0;
559
560 if (opt_do_tables && opt_do_views)
561 {
562 fprintf(stderr, "Error: %s cannot process both tables and views "
563 "in one command (--process-tables=YES "
564 "--process-views=YES --all-in-1).\n",
565 my_progname);
566 DBUG_RETURN(1);
567 }
568
569 for (i = 0; i < tables; i++)
570 tot_length+= fixed_name_length(*(table_names + i)) + 2;
571
572 if (!(table_names_comma_sep = (char *)
573 my_malloc((sizeof(char) * tot_length) + 4, MYF(MY_WME))))
574 DBUG_RETURN(1);
575
576 for (end = table_names_comma_sep + 1; tables > 0;
577 tables--, table_names++)
578 {
579 end= fix_table_name(end, *table_names);
580 *end++= ',';
581 }
582 *--end = 0;
583 handle_request_for_tables(table_names_comma_sep + 1, tot_length - 1,
584 opt_do_views != 0, opt_all_in_1);
585 my_free(table_names_comma_sep);
586 }
587 else
588 {
589 for (; tables > 0; tables--, table_names++)
590 {
591 table= *table_names;
592 table_len= fixed_name_length(*table_names);
593 view= is_view(table);
594 if (view < 0)
595 continue;
596 handle_request_for_tables(table, table_len, view == 1, opt_all_in_1);
597 }
598 }
599 DBUG_RETURN(0);
600} /* process_selected_tables */
601
602
603static size_t fixed_name_length(const char *name)
604{
605 const char *p;
606 size_t extra_length= 2; /* count the first/last backticks */
607 DBUG_ENTER("fixed_name_length");
608
609 for (p= name; *p; p++)
610 {
611 if (*p == '`')
612 extra_length++;
613 }
614 DBUG_RETURN((size_t) ((p - name) + extra_length));
615}
616
617
618static char *fix_table_name(char *dest, char *src)
619{
620 DBUG_ENTER("fix_table_name");
621
622 *dest++= '`';
623 for (; *src; src++)
624 {
625 if (*src == '`')
626 *dest++= '`';
627 *dest++= *src;
628 }
629 *dest++= '`';
630
631 DBUG_RETURN(dest);
632}
633
634
635static int process_all_tables_in_db(char *database)
636{
637 MYSQL_RES *UNINIT_VAR(res);
638 MYSQL_ROW row;
639 uint num_columns;
640 my_bool system_database= 0;
641 my_bool view= FALSE;
642 DBUG_ENTER("process_all_tables_in_db");
643
644 if (use_db(database))
645 DBUG_RETURN(1);
646 if ((mysql_query(sock, "SHOW /*!50002 FULL*/ TABLES") &&
647 mysql_query(sock, "SHOW TABLES")) ||
648 !(res= mysql_store_result(sock)))
649 {
650 my_printf_error(0, "Error: Couldn't get table list for database %s: %s",
651 MYF(0), database, mysql_error(sock));
652 DBUG_RETURN(1);
653 }
654
655 if (!strcmp(database, "mysql") || !strcmp(database, "MYSQL"))
656 system_database= 1;
657
658 num_columns= mysql_num_fields(res);
659
660 if (opt_all_in_1 && what_to_do != DO_FIX_NAMES)
661 {
662 /*
663 We need table list in form `a`, `b`, `c`
664 that's why we need 2 more chars added to to each table name
665 space is for more readable output in logs and in case of error
666 */
667
668 char *tables, *end;
669 size_t tot_length = 0;
670
671 char *views, *views_end;
672 size_t tot_views_length = 0;
673
674 while ((row = mysql_fetch_row(res)))
675 {
676 if ((num_columns == 2) && (strcmp(row[1], "VIEW") == 0) &&
677 opt_do_views)
678 tot_views_length+= fixed_name_length(row[0]) + 2;
679 else if (opt_do_tables)
680 tot_length+= fixed_name_length(row[0]) + 2;
681 }
682 mysql_data_seek(res, 0);
683
684 if (!(tables=(char *) my_malloc(sizeof(char)*tot_length+4, MYF(MY_WME))))
685 {
686 mysql_free_result(res);
687 DBUG_RETURN(1);
688 }
689 if (!(views=(char *) my_malloc(sizeof(char)*tot_views_length+4, MYF(MY_WME))))
690 {
691 my_free(tables);
692 mysql_free_result(res);
693 DBUG_RETURN(1);
694 }
695
696 for (end = tables + 1, views_end= views + 1; (row = mysql_fetch_row(res)) ;)
697 {
698 if ((num_columns == 2) && (strcmp(row[1], "VIEW") == 0))
699 {
700 if (!opt_do_views)
701 continue;
702 views_end= fix_table_name(views_end, row[0]);
703 *views_end++= ',';
704 }
705 else
706 {
707 if (!opt_do_tables)
708 continue;
709 end= fix_table_name(end, row[0]);
710 *end++= ',';
711 }
712 }
713 *--end = 0;
714 *--views_end = 0;
715 if (tot_length)
716 handle_request_for_tables(tables + 1, tot_length - 1, FALSE, opt_all_in_1);
717 if (tot_views_length)
718 handle_request_for_tables(views + 1, tot_views_length - 1, TRUE, opt_all_in_1);
719 my_free(tables);
720 my_free(views);
721 }
722 else
723 {
724 while ((row = mysql_fetch_row(res)))
725 {
726 /* Skip views if we don't perform renaming. */
727 if ((what_to_do != DO_FIX_NAMES) && (num_columns == 2) && (strcmp(row[1], "VIEW") == 0))
728 {
729 if (!opt_do_views)
730 continue;
731 view= TRUE;
732 }
733 else
734 {
735 if (!opt_do_tables)
736 continue;
737 view= FALSE;
738 }
739 if (system_database &&
740 (!strcmp(row[0], "general_log") ||
741 !strcmp(row[0], "slow_log")))
742 continue; /* Skip logging tables */
743
744 handle_request_for_tables(row[0], fixed_name_length(row[0]), view, opt_all_in_1);
745 }
746 }
747 mysql_free_result(res);
748 DBUG_RETURN(0);
749} /* process_all_tables_in_db */
750
751
752static int run_query(const char *query, my_bool log_query)
753{
754 if (verbose >=3 && log_query)
755 puts(query);
756 if (mysql_query(sock, query))
757 {
758 fprintf(stderr, "Failed to %s\n", query);
759 fprintf(stderr, "Error: %s\n", mysql_error(sock));
760 return 1;
761 }
762 return 0;
763}
764
765
766static int fix_table_storage_name(const char *name)
767{
768 char qbuf[100 + NAME_LEN*4];
769 int rc= 0;
770 DBUG_ENTER("fix_table_storage_name");
771
772 if (strncmp(name, "#mysql50#", 9))
773 DBUG_RETURN(1);
774 my_snprintf(qbuf, sizeof(qbuf), "RENAME TABLE %`s TO %`s",
775 name, name + 9);
776
777 rc= run_query(qbuf, 1);
778 if (verbose)
779 printf("%-50s %s\n", name, rc ? "FAILED" : "OK");
780 DBUG_RETURN(rc);
781}
782
783static int fix_database_storage_name(const char *name)
784{
785 char qbuf[100 + NAME_LEN*4];
786 int rc= 0;
787 DBUG_ENTER("fix_database_storage_name");
788
789 if (strncmp(name, "#mysql50#", 9))
790 DBUG_RETURN(1);
791 my_snprintf(qbuf, sizeof(qbuf), "ALTER DATABASE %`s UPGRADE DATA DIRECTORY "
792 "NAME", name);
793 rc= run_query(qbuf, 1);
794 if (verbose)
795 printf("%-50s %s\n", name, rc ? "FAILED" : "OK");
796 DBUG_RETURN(rc);
797}
798
799static int rebuild_table(char *name)
800{
801 char *query, *ptr;
802 int rc= 0;
803 DBUG_ENTER("rebuild_table");
804
805 query= (char*)my_malloc(sizeof(char) * (12 + strlen(name) + 6 + 1),
806 MYF(MY_WME));
807 if (!query)
808 DBUG_RETURN(1);
809 ptr= strxmov(query, "ALTER TABLE ", name, " FORCE", NullS);
810 if (verbose >= 3)
811 puts(query);
812 if (mysql_real_query(sock, query, (ulong)(ptr - query)))
813 {
814 fprintf(stderr, "Failed to %s\n", query);
815 fprintf(stderr, "Error: %s\n", mysql_error(sock));
816 rc= 1;
817 }
818 if (verbose)
819 printf("%-50s %s\n", name, rc ? "FAILED" : "FIXED");
820 my_free(query);
821 DBUG_RETURN(rc);
822}
823
824static int process_one_db(char *database)
825{
826 DBUG_ENTER("process_one_db");
827
828 if (opt_skip_database && !strcmp(database, opt_skip_database))
829 DBUG_RETURN(0);
830
831 if (verbose)
832 puts(database);
833 if (what_to_do == DO_FIX_NAMES)
834 {
835 int rc= 0;
836 if (opt_fix_db_names && !strncmp(database,"#mysql50#", 9))
837 {
838 rc= fix_database_storage_name(database);
839 database+= 9;
840 }
841 if (rc || !opt_fix_table_names)
842 DBUG_RETURN(rc);
843 }
844 DBUG_RETURN(process_all_tables_in_db(database));
845}
846
847
848static int use_db(char *database)
849{
850 DBUG_ENTER("use_db");
851
852 if (mysql_get_server_version(sock) >= FIRST_INFORMATION_SCHEMA_VERSION &&
853 !my_strcasecmp(&my_charset_latin1, database, INFORMATION_SCHEMA_DB_NAME))
854 DBUG_RETURN(1);
855 if (mysql_get_server_version(sock) >= FIRST_PERFORMANCE_SCHEMA_VERSION &&
856 !my_strcasecmp(&my_charset_latin1, database, PERFORMANCE_SCHEMA_DB_NAME))
857 DBUG_RETURN(1);
858 if (mysql_select_db(sock, database))
859 {
860 DBerror(sock, "when selecting the database");
861 DBUG_RETURN(1);
862 }
863 DBUG_RETURN(0);
864} /* use_db */
865
866/* Do not send commands to replication slaves. */
867static int disable_binlog()
868{
869 mysql_query(sock, "SET WSREP_ON=0"); /* ignore the error, if any */
870 return run_query("SET SQL_LOG_BIN=0", 0);
871}
872
873static int handle_request_for_tables(char *tables, size_t length,
874 my_bool view, my_bool dont_quote)
875{
876 char *query, *end, options[100], message[100];
877 char table_name_buff[NAME_CHAR_LEN*2*2+1], *table_name;
878 size_t query_length= 0, query_size= sizeof(char)*(length+110);
879 const char *op = 0;
880 const char *tab_view;
881 DBUG_ENTER("handle_request_for_tables");
882
883 options[0] = 0;
884 tab_view= view ? " VIEW " : " TABLE ";
885 end = options;
886 switch (what_to_do) {
887 case DO_CHECK:
888 op = "CHECK";
889 if (view)
890 {
891 if (opt_fast || opt_check_only_changed)
892 DBUG_RETURN(0);
893 }
894 else
895 {
896 if (opt_quick) end = strmov(end, " QUICK");
897 if (opt_fast) end = strmov(end, " FAST");
898 if (opt_extended) end = strmov(end, " EXTENDED");
899 if (opt_medium_check) end = strmov(end, " MEDIUM"); /* Default */
900 if (opt_check_only_changed) end = strmov(end, " CHANGED");
901 }
902 if (opt_upgrade) end = strmov(end, " FOR UPGRADE");
903 break;
904 case DO_REPAIR:
905 op= opt_write_binlog ? "REPAIR" : "REPAIR NO_WRITE_TO_BINLOG";
906 if (view)
907 {
908 if (opt_do_views == DO_VIEWS_FROM_MYSQL) end = strmov(end, " FROM MYSQL");
909 }
910 else
911 {
912 if (opt_quick) end = strmov(end, " QUICK");
913 if (opt_extended) end = strmov(end, " EXTENDED");
914 if (opt_frm) end = strmov(end, " USE_FRM");
915 }
916 break;
917 case DO_ANALYZE:
918 if (view)
919 {
920 printf("%-50s %s\n", tables, "Can't run anaylyze on a view");
921 DBUG_RETURN(1);
922 }
923 DBUG_ASSERT(!view);
924 op= (opt_write_binlog) ? "ANALYZE" : "ANALYZE NO_WRITE_TO_BINLOG";
925 if (opt_persistent_all) end = strmov(end, " PERSISTENT FOR ALL");
926 break;
927 case DO_OPTIMIZE:
928 if (view)
929 {
930 printf("%-50s %s\n", tables, "Can't run optimize on a view");
931 DBUG_RETURN(1);
932 }
933 op= (opt_write_binlog) ? "OPTIMIZE" : "OPTIMIZE NO_WRITE_TO_BINLOG";
934 break;
935 case DO_FIX_NAMES:
936 if (view)
937 {
938 printf("%-50s %s\n", tables, "Can't run fix names on a view");
939 DBUG_RETURN(1);
940 }
941 DBUG_RETURN(fix_table_storage_name(tables));
942 }
943
944 if (!(query =(char *) my_malloc(query_size, MYF(MY_WME))))
945 DBUG_RETURN(1);
946 if (dont_quote)
947 {
948 DBUG_ASSERT(strlen(op)+strlen(tables)+strlen(options)+8+1 <= query_size);
949
950 /* No backticks here as we added them before */
951 query_length= sprintf(query, "%s%s%s %s", op,
952 tab_view, tables, options);
953 table_name= tables;
954 }
955 else
956 {
957 char *ptr, *org;
958
959 org= ptr= strmov(strmov(query, op), tab_view);
960 ptr= fix_table_name(ptr, tables);
961 strmake(table_name_buff, org, MY_MIN((int) sizeof(table_name_buff)-1,
962 (int) (ptr - org)));
963 table_name= table_name_buff;
964 ptr= strxmov(ptr, " ", options, NullS);
965 query_length= (size_t) (ptr - query);
966 }
967 if (verbose >= 3)
968 puts(query);
969 if (mysql_real_query(sock, query, (ulong)query_length))
970 {
971 sprintf(message, "when executing '%s%s... %s'", op, tab_view, options);
972 DBerror(sock, message);
973 my_free(query);
974 DBUG_RETURN(1);
975 }
976 print_result();
977 if (opt_flush_tables)
978 {
979 query_length= sprintf(query, "FLUSH TABLES %s", table_name);
980 if (mysql_real_query(sock, query, (ulong)query_length))
981 {
982 DBerror(sock, query);
983 my_free(query);
984 DBUG_RETURN(1);
985 }
986 }
987 my_free(query);
988 DBUG_RETURN(0);
989}
990
991static void insert_table_name(DYNAMIC_ARRAY *arr, char *in, size_t dblen)
992{
993 char buf[NAME_LEN*2+2];
994 in[dblen]= 0;
995 my_snprintf(buf, sizeof(buf), "%`s.%`s", in, in + dblen + 1);
996 insert_dynamic(arr, (uchar*) buf);
997}
998
999static void print_result()
1000{
1001 MYSQL_RES *res;
1002 MYSQL_ROW row;
1003 char prev[(NAME_LEN+9)*3+2];
1004 char prev_alter[MAX_ALTER_STR_SIZE];
1005 size_t length_of_db= strlen(sock->db);
1006 uint i;
1007 my_bool found_error=0, table_rebuild=0;
1008 DYNAMIC_ARRAY *array4repair= &tables4repair;
1009 DBUG_ENTER("print_result");
1010
1011 res = mysql_use_result(sock);
1012
1013 prev[0] = '\0';
1014 prev_alter[0]= 0;
1015 for (i = 0; (row = mysql_fetch_row(res)); i++)
1016 {
1017 int changed = strcmp(prev, row[0]);
1018 my_bool status = !strcmp(row[2], "status");
1019
1020 if (status)
1021 {
1022 /*
1023 if there was an error with the table, we have --auto-repair set,
1024 and this isn't a repair op, then add the table to the tables4repair
1025 list
1026 */
1027 if (found_error && opt_auto_repair && what_to_do != DO_REPAIR &&
1028 strcmp(row[3],"OK"))
1029 {
1030 if (table_rebuild)
1031 {
1032 if (prev_alter[0])
1033 insert_dynamic(&alter_table_cmds, (uchar*) prev_alter);
1034 else
1035 insert_table_name(&tables4rebuild, prev, length_of_db);
1036 }
1037 else
1038 insert_table_name(array4repair, prev, length_of_db);
1039 }
1040 array4repair= &tables4repair;
1041 found_error=0;
1042 table_rebuild=0;
1043 prev_alter[0]= 0;
1044 if (opt_silent)
1045 continue;
1046 }
1047 if (status && changed)
1048 printf("%-50s %s", row[0], row[3]);
1049 else if (!status && changed)
1050 {
1051 /*
1052 If the error message includes REPAIR TABLE, we assume it means
1053 we have to run upgrade on it. In this case we write a nicer message
1054 than "Please do "REPAIR TABLE""...
1055 */
1056 if (!strcmp(row[2],"error") && strstr(row[3],"REPAIR "))
1057 {
1058 printf("%-50s %s", row[0], "Needs upgrade");
1059 array4repair= strstr(row[3], "VIEW") ? &views4repair : &tables4repair;
1060 }
1061 else
1062 printf("%s\n%-9s: %s", row[0], row[2], row[3]);
1063 if (opt_auto_repair && strcmp(row[2],"note"))
1064 {
1065 found_error=1;
1066 if (opt_auto_repair && strstr(row[3], "ALTER TABLE") != NULL)
1067 table_rebuild=1;
1068 }
1069 }
1070 else
1071 printf("%-9s: %s", row[2], row[3]);
1072 strmov(prev, row[0]);
1073 putchar('\n');
1074 }
1075 /* add the last table to be repaired to the list */
1076 if (found_error && opt_auto_repair && what_to_do != DO_REPAIR)
1077 {
1078 if (table_rebuild)
1079 {
1080 if (prev_alter[0])
1081 insert_dynamic(&alter_table_cmds, prev_alter);
1082 else
1083 insert_table_name(&tables4rebuild, prev, length_of_db);
1084 }
1085 else
1086 insert_table_name(array4repair, prev, length_of_db);
1087 }
1088 mysql_free_result(res);
1089 DBUG_VOID_RETURN;
1090}
1091
1092
1093static int dbConnect(char *host, char *user, char *passwd)
1094{
1095 my_bool reconnect= 1;
1096 DBUG_ENTER("dbConnect");
1097 if (verbose > 1)
1098 {
1099 fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost");
1100 }
1101 mysql_init(&mysql_connection);
1102 if (opt_compress)
1103 mysql_options(&mysql_connection, MYSQL_OPT_COMPRESS, NullS);
1104#ifdef HAVE_OPENSSL
1105 if (opt_use_ssl)
1106 {
1107 mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
1108 opt_ssl_capath, opt_ssl_cipher);
1109 mysql_options(&mysql_connection, MYSQL_OPT_SSL_CRL, opt_ssl_crl);
1110 mysql_options(&mysql_connection, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath);
1111 }
1112#endif
1113 if (opt_protocol)
1114 mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
1115 if (shared_memory_base_name)
1116 mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
1117
1118 if (opt_plugin_dir && *opt_plugin_dir)
1119 mysql_options(&mysql_connection, MYSQL_PLUGIN_DIR, opt_plugin_dir);
1120
1121 if (opt_default_auth && *opt_default_auth)
1122 mysql_options(&mysql_connection, MYSQL_DEFAULT_AUTH, opt_default_auth);
1123
1124 mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
1125 mysql_options(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
1126 mysql_options4(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_ADD,
1127 "program_name", "mysqlcheck");
1128 if (!(sock = mysql_real_connect(&mysql_connection, host, user, passwd,
1129 NULL, opt_mysql_port, opt_mysql_unix_port, 0)))
1130 {
1131 DBerror(&mysql_connection, "when trying to connect");
1132 DBUG_RETURN(1);
1133 }
1134 mysql_options(&mysql_connection, MYSQL_OPT_RECONNECT, &reconnect);
1135 DBUG_RETURN(0);
1136} /* dbConnect */
1137
1138
1139static void dbDisconnect(char *host)
1140{
1141 DBUG_ENTER("dbDisconnect");
1142 if (verbose > 1)
1143 fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
1144 mysql_close(sock);
1145 DBUG_VOID_RETURN;
1146} /* dbDisconnect */
1147
1148
1149static void DBerror(MYSQL *mysql, const char *when)
1150{
1151 DBUG_ENTER("DBerror");
1152 my_printf_error(0,"Got error: %d: %s %s", MYF(0),
1153 mysql_errno(mysql), mysql_error(mysql), when);
1154 safe_exit(EX_MYSQLERR);
1155 DBUG_VOID_RETURN;
1156} /* DBerror */
1157
1158
1159static void safe_exit(int error)
1160{
1161 DBUG_ENTER("safe_exit");
1162 if (!first_error)
1163 first_error= error;
1164 if (ignore_errors)
1165 DBUG_VOID_RETURN;
1166 if (sock)
1167 mysql_close(sock);
1168 sf_leaking_memory= 1; /* don't check for memory leaks */
1169 exit(error);
1170 DBUG_VOID_RETURN;
1171}
1172
1173
1174int main(int argc, char **argv)
1175{
1176 int ret= EX_USAGE;
1177 char **defaults_argv;
1178
1179 MY_INIT(argv[0]);
1180 sf_leaking_memory=1; /* don't report memory leaks on early exits */
1181 /*
1182 ** Check out the args
1183 */
1184 load_defaults_or_exit("my", load_default_groups, &argc, &argv);
1185 defaults_argv= argv;
1186 if (get_options(&argc, &argv))
1187 goto end1;
1188 sf_leaking_memory=0; /* from now on we cleanup properly */
1189
1190 ret= EX_MYSQLERR;
1191 if (dbConnect(current_host, current_user, opt_password))
1192 goto end1;
1193
1194 ret= 1;
1195 if (!opt_write_binlog)
1196 {
1197 if (disable_binlog())
1198 goto end;
1199 }
1200
1201 if (opt_auto_repair &&
1202 (my_init_dynamic_array(&tables4repair, sizeof(char)*(NAME_LEN*2+2),16,
1203 64, MYF(0)) ||
1204 my_init_dynamic_array(&views4repair, sizeof(char)*(NAME_LEN*2+2),16,
1205 64, MYF(0)) ||
1206 my_init_dynamic_array(&tables4rebuild, sizeof(char)*(NAME_LEN*2+2),16,
1207 64, MYF(0)) ||
1208 my_init_dynamic_array(&alter_table_cmds, MAX_ALTER_STR_SIZE, 0, 1,
1209 MYF(0))))
1210 goto end;
1211
1212 if (opt_alldbs)
1213 process_all_databases();
1214 /* Only one database and selected table(s) */
1215 else if (argc > 1 && !opt_databases)
1216 process_selected_tables(*argv, (argv + 1), (argc - 1));
1217 /* One or more databases, all tables */
1218 else
1219 process_databases(argv);
1220 if (opt_auto_repair)
1221 {
1222 size_t i;
1223
1224 if (!opt_silent && (tables4repair.elements || tables4rebuild.elements))
1225 puts("\nRepairing tables");
1226 what_to_do = DO_REPAIR;
1227 for (i = 0; i < tables4repair.elements ; i++)
1228 {
1229 char *name= (char*) dynamic_array_ptr(&tables4repair, i);
1230 handle_request_for_tables(name, fixed_name_length(name), FALSE, TRUE);
1231 }
1232 for (i = 0; i < tables4rebuild.elements ; i++)
1233 rebuild_table((char*) dynamic_array_ptr(&tables4rebuild, i));
1234 for (i = 0; i < alter_table_cmds.elements ; i++)
1235 run_query((char*) dynamic_array_ptr(&alter_table_cmds, i), 1);
1236 if (!opt_silent && views4repair.elements)
1237 puts("\nRepairing views");
1238 for (i = 0; i < views4repair.elements ; i++)
1239 {
1240 char *name= (char*) dynamic_array_ptr(&views4repair, i);
1241 handle_request_for_tables(name, fixed_name_length(name), TRUE, TRUE);
1242 }
1243 }
1244 ret= MY_TEST(first_error);
1245
1246 end:
1247 dbDisconnect(current_host);
1248 if (opt_auto_repair)
1249 {
1250 delete_dynamic(&views4repair);
1251 delete_dynamic(&tables4repair);
1252 delete_dynamic(&tables4rebuild);
1253 delete_dynamic(&alter_table_cmds);
1254 }
1255 end1:
1256 my_free(opt_password);
1257 my_free(shared_memory_base_name);
1258 mysql_library_end();
1259 free_defaults(defaults_argv);
1260 my_end(my_end_arg);
1261 return ret;
1262} /* main */
1263