00001 /* Copyright (C) 2000 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 /* By Jani Tolonen, 2001-04-20, MySQL Development Team */ 00018 00019 #define CHECK_VERSION "2.4.4" 00020 00021 #include "client_priv.h" 00022 #include <m_ctype.h> 00023 #include <mysql_version.h> 00024 #include <mysqld_error.h> 00025 #include <sslopt-vars.h> 00026 00027 /* Exit codes */ 00028 00029 #define EX_USAGE 1 00030 #define EX_MYSQLERR 2 00031 00032 static MYSQL mysql_connection, *sock = 0; 00033 static my_bool opt_alldbs = 0, opt_check_only_changed = 0, opt_extended = 0, 00034 opt_compress = 0, opt_databases = 0, opt_fast = 0, 00035 opt_medium_check = 0, opt_quick = 0, opt_all_in_1 = 0, 00036 opt_silent = 0, opt_auto_repair = 0, ignore_errors = 0, 00037 tty_password = 0, opt_frm = 0, 00038 opt_fix_table_names= 0, opt_fix_db_names= 0, opt_upgrade= 0; 00039 static uint verbose = 0, opt_mysql_port=0; 00040 static my_string opt_mysql_unix_port = 0; 00041 static char *opt_password = 0, *current_user = 0, 00042 *default_charset = (char *)MYSQL_DEFAULT_CHARSET_NAME, 00043 *current_host = 0; 00044 static int first_error = 0; 00045 DYNAMIC_ARRAY tables4repair; 00046 #ifdef HAVE_SMEM 00047 static char *shared_memory_base_name=0; 00048 #endif 00049 static uint opt_protocol=0; 00050 static CHARSET_INFO *charset_info= &my_charset_latin1; 00051 00052 enum operations { DO_CHECK, DO_REPAIR, DO_ANALYZE, DO_OPTIMIZE, DO_UPGRADE }; 00053 00054 static struct my_option my_long_options[] = 00055 { 00056 {"all-databases", 'A', 00057 "Check all the databases. This will be same as --databases with all databases selected.", 00058 (gptr*) &opt_alldbs, (gptr*) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 00059 0, 0}, 00060 {"analyze", 'a', "Analyze given tables.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 00061 0, 0, 0, 0}, 00062 {"all-in-1", '1', 00063 "Instead of issuing one query for each table, use one query per database, naming all tables in the database in a comma-separated list.", 00064 (gptr*) &opt_all_in_1, (gptr*) &opt_all_in_1, 0, GET_BOOL, NO_ARG, 0, 0, 0, 00065 0, 0, 0}, 00066 #ifdef __NETWARE__ 00067 {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 00068 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 00069 #endif 00070 {"auto-repair", OPT_AUTO_REPAIR, 00071 "If a checked table is corrupted, automatically fix it. Repairing will be done after all tables have been checked, if corrupted ones were found.", 00072 (gptr*) &opt_auto_repair, (gptr*) &opt_auto_repair, 0, GET_BOOL, NO_ARG, 0, 00073 0, 0, 0, 0, 0}, 00074 {"character-sets-dir", OPT_CHARSETS_DIR, 00075 "Directory where character sets are.", (gptr*) &charsets_dir, 00076 (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00077 {"check", 'c', "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 00078 0, 0, 0, 0}, 00079 {"check-only-changed", 'C', 00080 "Check only tables that have changed since last check or haven't been closed properly.", 00081 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 00082 {"check-upgrade", 'g', 00083 "Check tables for version-dependent changes. May be used with --auto-repair to correct tables requiring version-dependent updates.", 00084 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 00085 {"compress", OPT_COMPRESS, "Use compression in server/client protocol.", 00086 (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 00087 0, 0, 0}, 00088 {"databases", 'B', 00089 "To check several databases. Note the difference in usage; In this case no tables are given. All name arguments are regarded as databasenames.", 00090 (gptr*) &opt_databases, (gptr*) &opt_databases, 0, GET_BOOL, NO_ARG, 00091 0, 0, 0, 0, 0, 0}, 00092 #ifdef DBUG_OFF 00093 {"debug", '#', "This is a non-debug version. Catch this and exit.", 00094 0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, 00095 #else 00096 {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 00097 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, 00098 #endif 00099 {"default-character-set", OPT_DEFAULT_CHARSET, 00100 "Set the default character set.", (gptr*) &default_charset, 00101 (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00102 {"fast",'F', "Check only tables that haven't been closed properly.", 00103 (gptr*) &opt_fast, (gptr*) &opt_fast, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 00104 0}, 00105 {"fix-db-names", OPT_FIX_DB_NAMES, "Fix database names.", 00106 (gptr*) &opt_fix_db_names, (gptr*) &opt_fix_db_names, 00107 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 00108 {"fix-table-names", OPT_FIX_TABLE_NAMES, "Fix table names.", 00109 (gptr*) &opt_fix_table_names, (gptr*) &opt_fix_table_names, 00110 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 00111 {"force", 'f', "Continue even if we get an sql-error.", 00112 (gptr*) &ignore_errors, (gptr*) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0, 00113 0, 0, 0, 0}, 00114 {"extended", 'e', 00115 "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.", 00116 (gptr*) &opt_extended, (gptr*) &opt_extended, 0, GET_BOOL, NO_ARG, 0, 0, 0, 00117 0, 0, 0}, 00118 {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, 00119 NO_ARG, 0, 0, 0, 0, 0, 0}, 00120 {"host",'h', "Connect to host.", (gptr*) ¤t_host, 00121 (gptr*) ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00122 {"medium-check", 'm', 00123 "Faster than extended-check, but only finds 99.99 percent of all errors. Should be good enough for most cases.", 00124 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 00125 {"optimize", 'o', "Optimize table.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 00126 0, 0}, 00127 {"password", 'p', 00128 "Password to use when connecting to server. If password is not given it's solicited on the tty.", 00129 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, 00130 #ifdef __WIN__ 00131 {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, 00132 NO_ARG, 0, 0, 0, 0, 0, 0}, 00133 #endif 00134 {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, 00135 (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 00136 0}, 00137 {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).", 00138 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00139 {"quick", 'q', 00140 "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.", 00141 (gptr*) &opt_quick, (gptr*) &opt_quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 00142 0}, 00143 {"repair", 'r', 00144 "Can fix almost anything except unique keys that aren't unique.", 00145 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 00146 #ifdef HAVE_SMEM 00147 {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME, 00148 "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name, 00149 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00150 #endif 00151 {"silent", 's', "Print only error messages.", (gptr*) &opt_silent, 00152 (gptr*) &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 00153 {"socket", 'S', "Socket file to use for connection.", 00154 (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR, 00155 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00156 #include <sslopt-longopts.h> 00157 {"tables", OPT_TABLES, "Overrides option --databases (-B).", 0, 0, 0, 00158 GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 00159 {"use-frm", OPT_FRM, 00160 "When used with REPAIR, get table structure from .frm file, so the table can be repaired even if .MYI header is corrupted.", 00161 (gptr*) &opt_frm, (gptr*) &opt_frm, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 00162 0}, 00163 #ifndef DONT_ALLOW_USER_CHANGE 00164 {"user", 'u', "User for login if not current user.", (gptr*) ¤t_user, 00165 (gptr*) ¤t_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00166 #endif 00167 {"verbose", 'v', "Print info about the various stages.", 0, 0, 0, GET_NO_ARG, 00168 NO_ARG, 0, 0, 0, 0, 0, 0}, 00169 {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, 00170 NO_ARG, 0, 0, 0, 0, 0, 0}, 00171 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} 00172 }; 00173 00174 static const char *load_default_groups[] = { "mysqlcheck", "client", 0 }; 00175 00176 00177 static void print_version(void); 00178 static void usage(void); 00179 static int get_options(int *argc, char ***argv); 00180 static int process_all_databases(); 00181 static int process_databases(char **db_names); 00182 static int process_selected_tables(char *db, char **table_names, int tables); 00183 static int process_all_tables_in_db(char *database); 00184 static int process_one_db(char *database); 00185 static int use_db(char *database); 00186 static int handle_request_for_tables(char *tables, uint length); 00187 static int dbConnect(char *host, char *user,char *passwd); 00188 static void dbDisconnect(char *host); 00189 static void DBerror(MYSQL *mysql, const char *when); 00190 static void safe_exit(int error); 00191 static void print_result(); 00192 static char *fix_table_name(char *dest, char *src); 00193 int what_to_do = 0; 00194 00195 #include <help_start.h> 00196 00197 static void print_version(void) 00198 { 00199 printf("%s Ver %s Distrib %s, for %s (%s)\n", my_progname, CHECK_VERSION, 00200 MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); 00201 NETWARE_SET_SCREEN_MODE(1); 00202 } /* print_version */ 00203 00204 00205 static void usage(void) 00206 { 00207 print_version(); 00208 puts("By Jani Tolonen, 2001-04-20, MySQL Development Team\n"); 00209 puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n"); 00210 puts("and you are welcome to modify and redistribute it under the GPL license.\n"); 00211 puts("This program can be used to CHECK (-c,-m,-C), REPAIR (-r), ANALYZE (-a)"); 00212 puts("or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be"); 00213 puts("used at the same time. Not all options are supported by all storage engines."); 00214 puts("Please consult the MySQL manual for latest information about the"); 00215 puts("above. The options -c,-r,-a and -o are exclusive to each other, which"); 00216 puts("means that the last option will be used, if several was specified.\n"); 00217 puts("The option -c will be used by default, if none was specified. You"); 00218 puts("can change the default behavior by making a symbolic link, or"); 00219 puts("copying this file somewhere with another name, the alternatives are:"); 00220 puts("mysqlrepair: The default option will be -r"); 00221 puts("mysqlanalyze: The default option will be -a"); 00222 puts("mysqloptimize: The default option will be -o\n"); 00223 printf("Usage: %s [OPTIONS] database [tables]\n", my_progname); 00224 printf("OR %s [OPTIONS] --databases DB1 [DB2 DB3...]\n", 00225 my_progname); 00226 printf("OR %s [OPTIONS] --all-databases\n", my_progname); 00227 print_defaults("my", load_default_groups); 00228 my_print_help(my_long_options); 00229 my_print_variables(my_long_options); 00230 } /* usage */ 00231 00232 #include <help_end.h> 00233 00234 static my_bool 00235 get_one_option(int optid, const struct my_option *opt __attribute__((unused)), 00236 char *argument) 00237 { 00238 switch(optid) { 00239 #ifdef __NETWARE__ 00240 case OPT_AUTO_CLOSE: 00241 setscreenmode(SCR_AUTOCLOSE_ON_EXIT); 00242 break; 00243 #endif 00244 case 'a': 00245 what_to_do = DO_ANALYZE; 00246 break; 00247 case 'c': 00248 what_to_do = DO_CHECK; 00249 break; 00250 case 'C': 00251 what_to_do = DO_CHECK; 00252 opt_check_only_changed = 1; 00253 break; 00254 case 'I': /* Fall through */ 00255 case '?': 00256 usage(); 00257 exit(0); 00258 case 'm': 00259 what_to_do = DO_CHECK; 00260 opt_medium_check = 1; 00261 break; 00262 case 'o': 00263 what_to_do = DO_OPTIMIZE; 00264 break; 00265 case OPT_FIX_DB_NAMES: 00266 what_to_do= DO_UPGRADE; 00267 default_charset= (char*) "utf8"; 00268 opt_databases= 1; 00269 break; 00270 case OPT_FIX_TABLE_NAMES: 00271 what_to_do= DO_UPGRADE; 00272 default_charset= (char*) "utf8"; 00273 break; 00274 case 'p': 00275 if (argument) 00276 { 00277 char *start = argument; 00278 my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); 00279 opt_password = my_strdup(argument, MYF(MY_FAE)); 00280 while (*argument) *argument++= 'x'; /* Destroy argument */ 00281 if (*start) 00282 start[1] = 0; /* Cut length of argument */ 00283 tty_password= 0; 00284 } 00285 else 00286 tty_password = 1; 00287 break; 00288 case 'r': 00289 what_to_do = DO_REPAIR; 00290 break; 00291 case 'g': 00292 what_to_do= DO_CHECK; 00293 opt_upgrade= 1; 00294 break; 00295 case 'W': 00296 #ifdef __WIN__ 00297 opt_protocol = MYSQL_PROTOCOL_PIPE; 00298 #endif 00299 break; 00300 case '#': 00301 DBUG_PUSH(argument ? argument : "d:t:o"); 00302 break; 00303 #include <sslopt-case.h> 00304 case OPT_TABLES: 00305 opt_databases = 0; 00306 break; 00307 case 'v': 00308 verbose++; 00309 break; 00310 case 'V': print_version(); exit(0); 00311 case OPT_MYSQL_PROTOCOL: 00312 { 00313 if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) 00314 { 00315 fprintf(stderr, "Unknown option to protocol: %s\n", argument); 00316 exit(1); 00317 } 00318 break; 00319 } 00320 } 00321 return 0; 00322 } 00323 00324 00325 static int get_options(int *argc, char ***argv) 00326 { 00327 int ho_error; 00328 00329 if (*argc == 1) 00330 { 00331 usage(); 00332 exit(0); 00333 } 00334 00335 load_defaults("my", load_default_groups, argc, argv); 00336 00337 if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) 00338 exit(ho_error); 00339 00340 if (!what_to_do) 00341 { 00342 int pnlen = strlen(my_progname); 00343 00344 if (pnlen < 6) /* name too short */ 00345 what_to_do = DO_CHECK; 00346 else if (!strcmp("repair", my_progname + pnlen - 6)) 00347 what_to_do = DO_REPAIR; 00348 else if (!strcmp("analyze", my_progname + pnlen - 7)) 00349 what_to_do = DO_ANALYZE; 00350 else if (!strcmp("optimize", my_progname + pnlen - 8)) 00351 what_to_do = DO_OPTIMIZE; 00352 else 00353 what_to_do = DO_CHECK; 00354 } 00355 00356 /* TODO: This variable is not yet used */ 00357 if (strcmp(default_charset, charset_info->csname) && 00358 !(charset_info= get_charset_by_csname(default_charset, 00359 MY_CS_PRIMARY, MYF(MY_WME)))) 00360 exit(1); 00361 if (*argc > 0 && opt_alldbs) 00362 { 00363 printf("You should give only options, no arguments at all, with option\n"); 00364 printf("--all-databases. Please see %s --help for more information.\n", 00365 my_progname); 00366 return 1; 00367 } 00368 if (*argc < 1 && !opt_alldbs) 00369 { 00370 printf("You forgot to give the arguments! Please see %s --help\n", 00371 my_progname); 00372 printf("for more information.\n"); 00373 return 1; 00374 } 00375 if (tty_password) 00376 opt_password = get_tty_password(NullS); 00377 return(0); 00378 } /* get_options */ 00379 00380 00381 static int process_all_databases() 00382 { 00383 MYSQL_ROW row; 00384 MYSQL_RES *tableres; 00385 int result = 0; 00386 00387 if (mysql_query(sock, "SHOW DATABASES") || 00388 !(tableres = mysql_store_result(sock))) 00389 { 00390 my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s", 00391 MYF(0), mysql_error(sock)); 00392 return 1; 00393 } 00394 while ((row = mysql_fetch_row(tableres))) 00395 { 00396 if (process_one_db(row[0])) 00397 result = 1; 00398 } 00399 return result; 00400 } 00401 /* process_all_databases */ 00402 00403 00404 static int process_databases(char **db_names) 00405 { 00406 int result = 0; 00407 for ( ; *db_names ; db_names++) 00408 { 00409 if (process_one_db(*db_names)) 00410 result = 1; 00411 } 00412 return result; 00413 } /* process_databases */ 00414 00415 00416 static int process_selected_tables(char *db, char **table_names, int tables) 00417 { 00418 if (use_db(db)) 00419 return 1; 00420 if (opt_all_in_1) 00421 { 00422 /* 00423 We need table list in form `a`, `b`, `c` 00424 that's why we need 4 more chars added to to each table name 00425 space is for more readable output in logs and in case of error 00426 */ 00427 char *table_names_comma_sep, *end; 00428 int i, tot_length = 0; 00429 00430 for (i = 0; i < tables; i++) 00431 tot_length += strlen(*(table_names + i)) + 4; 00432 00433 if (!(table_names_comma_sep = (char *) 00434 my_malloc((sizeof(char) * tot_length) + 4, MYF(MY_WME)))) 00435 return 1; 00436 00437 for (end = table_names_comma_sep + 1; tables > 0; 00438 tables--, table_names++) 00439 { 00440 end= fix_table_name(end, *table_names); 00441 *end++= ','; 00442 } 00443 *--end = 0; 00444 handle_request_for_tables(table_names_comma_sep + 1, tot_length - 1); 00445 my_free(table_names_comma_sep, MYF(0)); 00446 } 00447 else 00448 for (; tables > 0; tables--, table_names++) 00449 handle_request_for_tables(*table_names, strlen(*table_names)); 00450 return 0; 00451 } /* process_selected_tables */ 00452 00453 00454 static char *fix_table_name(char *dest, char *src) 00455 { 00456 char *db_sep; 00457 00458 *dest++= '`'; 00459 if ((db_sep= strchr(src, '.'))) 00460 { 00461 dest= strmake(dest, src, (uint) (db_sep - src)); 00462 dest= strmov(dest, "`.`"); 00463 src= db_sep + 1; 00464 } 00465 dest= strxmov(dest, src, "`", NullS); 00466 return dest; 00467 } 00468 00469 00470 static int process_all_tables_in_db(char *database) 00471 { 00472 MYSQL_RES *res; 00473 MYSQL_ROW row; 00474 00475 LINT_INIT(res); 00476 if (use_db(database)) 00477 return 1; 00478 if (mysql_query(sock, "SHOW TABLE STATUS") || 00479 !((res= mysql_store_result(sock)))) 00480 return 1; 00481 00482 if (opt_all_in_1) 00483 { 00484 /* 00485 We need table list in form `a`, `b`, `c` 00486 that's why we need 4 more chars added to to each table name 00487 space is for more readable output in logs and in case of error 00488 */ 00489 00490 char *tables, *end; 00491 uint tot_length = 0; 00492 00493 while ((row = mysql_fetch_row(res))) 00494 tot_length += strlen(row[0]) + 4; 00495 mysql_data_seek(res, 0); 00496 00497 if (!(tables=(char *) my_malloc(sizeof(char)*tot_length+4, MYF(MY_WME)))) 00498 { 00499 mysql_free_result(res); 00500 return 1; 00501 } 00502 for (end = tables + 1; (row = mysql_fetch_row(res)) ;) 00503 { 00504 /* Skip tables with an engine of NULL (probably a view). */ 00505 if (row[1]) 00506 { 00507 end= fix_table_name(end, row[0]); 00508 *end++= ','; 00509 } 00510 } 00511 *--end = 0; 00512 if (tot_length) 00513 handle_request_for_tables(tables + 1, tot_length - 1); 00514 my_free(tables, MYF(0)); 00515 } 00516 else 00517 { 00518 while ((row = mysql_fetch_row(res))) 00519 /* Skip tables with an engine of NULL (probably a view). */ 00520 if (row[1]) 00521 { 00522 handle_request_for_tables(row[0], strlen(row[0])); 00523 } 00524 } 00525 mysql_free_result(res); 00526 return 0; 00527 } /* process_all_tables_in_db */ 00528 00529 00530 00531 static int fix_object_name(const char *obj, const char *name) 00532 { 00533 char qbuf[100 + NAME_LEN*4]; 00534 int rc= 0; 00535 if (strncmp(name, "#mysql50#", 9)) 00536 return 1; 00537 sprintf(qbuf, "RENAME %s `%s` TO `%s`", obj, name, name + 9); 00538 if (mysql_query(sock, qbuf)) 00539 { 00540 fprintf(stderr, "Failed to %s\n", qbuf); 00541 fprintf(stderr, "Error: %s\n", mysql_error(sock)); 00542 rc= 1; 00543 } 00544 if (verbose) 00545 printf("%-50s %s\n", name, rc ? "FAILED" : "OK"); 00546 return rc; 00547 } 00548 00549 00550 static int process_one_db(char *database) 00551 { 00552 if (what_to_do == DO_UPGRADE) 00553 { 00554 int rc= 0; 00555 if (opt_fix_db_names && !strncmp(database,"#mysql50#", 9)) 00556 { 00557 rc= fix_object_name("DATABASE", database); 00558 database+= 9; 00559 } 00560 if (rc || !opt_fix_table_names) 00561 return rc; 00562 } 00563 return process_all_tables_in_db(database); 00564 } 00565 00566 00567 static int use_db(char *database) 00568 { 00569 if (mysql_get_server_version(sock) >= 50003 && 00570 !my_strcasecmp(&my_charset_latin1, database, "information_schema")) 00571 return 1; 00572 if (mysql_select_db(sock, database)) 00573 { 00574 DBerror(sock, "when selecting the database"); 00575 return 1; 00576 } 00577 return 0; 00578 } /* use_db */ 00579 00580 00581 static int handle_request_for_tables(char *tables, uint length) 00582 { 00583 char *query, *end, options[100], message[100]; 00584 uint query_length= 0; 00585 const char *op = 0; 00586 00587 options[0] = 0; 00588 end = options; 00589 switch (what_to_do) { 00590 case DO_CHECK: 00591 op = "CHECK"; 00592 if (opt_quick) end = strmov(end, " QUICK"); 00593 if (opt_fast) end = strmov(end, " FAST"); 00594 if (opt_medium_check) end = strmov(end, " MEDIUM"); /* Default */ 00595 if (opt_extended) end = strmov(end, " EXTENDED"); 00596 if (opt_check_only_changed) end = strmov(end, " CHANGED"); 00597 if (opt_upgrade) end = strmov(end, " FOR UPGRADE"); 00598 break; 00599 case DO_REPAIR: 00600 op = "REPAIR"; 00601 if (opt_quick) end = strmov(end, " QUICK"); 00602 if (opt_extended) end = strmov(end, " EXTENDED"); 00603 if (opt_frm) end = strmov(end, " USE_FRM"); 00604 break; 00605 case DO_ANALYZE: 00606 op = "ANALYZE"; 00607 break; 00608 case DO_OPTIMIZE: 00609 op = "OPTIMIZE"; 00610 break; 00611 case DO_UPGRADE: 00612 return fix_object_name("TABLE", tables); 00613 } 00614 00615 if (!(query =(char *) my_malloc((sizeof(char)*(length+110)), MYF(MY_WME)))) 00616 return 1; 00617 if (opt_all_in_1) 00618 { 00619 /* No backticks here as we added them before */ 00620 query_length= my_sprintf(query, 00621 (query, "%s TABLE %s %s", op, tables, options)); 00622 } 00623 else 00624 { 00625 char *ptr; 00626 00627 ptr= strmov(strmov(query, op), " TABLE "); 00628 ptr= fix_table_name(ptr, tables); 00629 ptr= strxmov(ptr, " ", options, NullS); 00630 query_length= (uint) (ptr - query); 00631 } 00632 if (mysql_real_query(sock, query, query_length)) 00633 { 00634 sprintf(message, "when executing '%s TABLE ... %s'", op, options); 00635 DBerror(sock, message); 00636 return 1; 00637 } 00638 print_result(); 00639 my_free(query, MYF(0)); 00640 return 0; 00641 } 00642 00643 00644 static void print_result() 00645 { 00646 MYSQL_RES *res; 00647 MYSQL_ROW row; 00648 char prev[NAME_LEN*2+2]; 00649 uint i; 00650 my_bool found_error=0; 00651 00652 res = mysql_use_result(sock); 00653 00654 prev[0] = '\0'; 00655 for (i = 0; (row = mysql_fetch_row(res)); i++) 00656 { 00657 int changed = strcmp(prev, row[0]); 00658 my_bool status = !strcmp(row[2], "status"); 00659 00660 if (status) 00661 { 00662 /* 00663 if there was an error with the table, we have --auto-repair set, 00664 and this isn't a repair op, then add the table to the tables4repair 00665 list 00666 */ 00667 if (found_error && opt_auto_repair && what_to_do != DO_REPAIR && 00668 strcmp(row[3],"OK")) 00669 insert_dynamic(&tables4repair, prev); 00670 found_error=0; 00671 if (opt_silent) 00672 continue; 00673 } 00674 if (status && changed) 00675 printf("%-50s %s", row[0], row[3]); 00676 else if (!status && changed) 00677 { 00678 printf("%s\n%-9s: %s", row[0], row[2], row[3]); 00679 if (strcmp(row[2],"note")) 00680 found_error=1; 00681 } 00682 else 00683 printf("%-9s: %s", row[2], row[3]); 00684 strmov(prev, row[0]); 00685 putchar('\n'); 00686 } 00687 /* add the last table to be repaired to the list */ 00688 if (found_error && opt_auto_repair && what_to_do != DO_REPAIR) 00689 insert_dynamic(&tables4repair, prev); 00690 mysql_free_result(res); 00691 } 00692 00693 00694 static int dbConnect(char *host, char *user, char *passwd) 00695 { 00696 DBUG_ENTER("dbConnect"); 00697 if (verbose) 00698 { 00699 fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost"); 00700 } 00701 mysql_init(&mysql_connection); 00702 if (opt_compress) 00703 mysql_options(&mysql_connection, MYSQL_OPT_COMPRESS, NullS); 00704 #ifdef HAVE_OPENSSL 00705 if (opt_use_ssl) 00706 mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, 00707 opt_ssl_capath, opt_ssl_cipher); 00708 #endif 00709 if (opt_protocol) 00710 mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); 00711 #ifdef HAVE_SMEM 00712 if (shared_memory_base_name) 00713 mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); 00714 #endif 00715 if (!(sock = mysql_real_connect(&mysql_connection, host, user, passwd, 00716 NULL, opt_mysql_port, opt_mysql_unix_port, 0))) 00717 { 00718 DBerror(&mysql_connection, "when trying to connect"); 00719 return 1; 00720 } 00721 mysql_connection.reconnect= 1; 00722 return 0; 00723 } /* dbConnect */ 00724 00725 00726 static void dbDisconnect(char *host) 00727 { 00728 if (verbose) 00729 fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost"); 00730 mysql_close(sock); 00731 } /* dbDisconnect */ 00732 00733 00734 static void DBerror(MYSQL *mysql, const char *when) 00735 { 00736 DBUG_ENTER("DBerror"); 00737 my_printf_error(0,"Got error: %d: %s %s", MYF(0), 00738 mysql_errno(mysql), mysql_error(mysql), when); 00739 safe_exit(EX_MYSQLERR); 00740 DBUG_VOID_RETURN; 00741 } /* DBerror */ 00742 00743 00744 static void safe_exit(int error) 00745 { 00746 if (!first_error) 00747 first_error= error; 00748 if (ignore_errors) 00749 return; 00750 if (sock) 00751 mysql_close(sock); 00752 exit(error); 00753 } 00754 00755 00756 int main(int argc, char **argv) 00757 { 00758 MY_INIT(argv[0]); 00759 /* 00760 ** Check out the args 00761 */ 00762 if (get_options(&argc, &argv)) 00763 { 00764 my_end(0); 00765 exit(EX_USAGE); 00766 } 00767 if (dbConnect(current_host, current_user, opt_password)) 00768 exit(EX_MYSQLERR); 00769 00770 if (opt_auto_repair && 00771 my_init_dynamic_array(&tables4repair, sizeof(char)*(NAME_LEN*2+2),16,64)) 00772 { 00773 first_error = 1; 00774 goto end; 00775 } 00776 00777 if (opt_alldbs) 00778 process_all_databases(); 00779 /* Only one database and selected table(s) */ 00780 else if (argc > 1 && !opt_databases) 00781 process_selected_tables(*argv, (argv + 1), (argc - 1)); 00782 /* One or more databases, all tables */ 00783 else 00784 process_databases(argv); 00785 if (opt_auto_repair) 00786 { 00787 uint i; 00788 00789 if (!opt_silent && tables4repair.elements) 00790 puts("\nRepairing tables"); 00791 what_to_do = DO_REPAIR; 00792 for (i = 0; i < tables4repair.elements ; i++) 00793 { 00794 char *name= (char*) dynamic_array_ptr(&tables4repair, i); 00795 handle_request_for_tables(name, strlen(name)); 00796 } 00797 } 00798 end: 00799 dbDisconnect(current_host); 00800 if (opt_auto_repair) 00801 delete_dynamic(&tables4repair); 00802 my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); 00803 #ifdef HAVE_SMEM 00804 my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); 00805 #endif 00806 my_end(0); 00807 return(first_error!=0); 00808 } /* main */
1.4.7

