18 #include "client_priv.h"
19 #include "my_default.h"
20 #include <sslopt-vars.h>
21 #include "../scripts/mysql_fix_privilege_tables_sql.c"
23 #include <welcome_copyright_notice.h>
27 #ifdef HAVE_SYS_WAIT_H
33 # define WEXITSTATUS(stat_val) (stat_val)
35 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
39 static char mysql_path[FN_REFLEN];
40 static char mysqlcheck_path[FN_REFLEN];
42 static my_bool opt_force, opt_verbose, debug_info_flag, debug_check_flag,
43 opt_systables_only, opt_version_check;
44 static uint my_end_arg= 0;
45 static char *opt_user= (
char*)
"root";
50 static char *opt_password= 0;
51 static char *opt_plugin_dir= 0, *opt_default_auth= 0;
53 static my_bool tty_password= 0;
55 static char opt_tmpdir[FN_REFLEN] =
"";
58 static char *default_dbug_option= (
char*)
"d:t:O,/tmp/mysql_upgrade.trace";
61 static char **defaults_argv;
63 static my_bool not_used;
65 static my_bool opt_write_binlog;
67 static struct my_option my_long_options[]=
69 {
"help",
'?',
"Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
70 NO_ARG, 0, 0, 0, 0, 0, 0},
71 {
"basedir",
'b',
"Not used by mysql_upgrade. Only for backward compatibility.",
72 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
73 {
"character-sets-dir", OPT_CHARSETS_DIR,
74 "Directory for character set files.", 0,
75 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
76 {
"compress", OPT_COMPRESS,
"Use compression in server/client protocol.",
77 ¬_used, ¬_used, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
79 "Not used by mysql_upgrade. Only for backward compatibility.",
80 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
82 {
"debug",
'#',
"This is a non-debug version. Catch this and exit.",
83 0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
85 {
"debug",
'#',
"Output debug log.", &default_dbug_option,
86 &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
88 {
"debug-check", OPT_DEBUG_CHECK,
"Check memory and open file usage at exit.",
89 &debug_check_flag, &debug_check_flag, 0,
90 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
91 {
"debug-info",
'T',
"Print some debug info at exit.", &debug_info_flag,
92 &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
93 {
"default-character-set", OPT_DEFAULT_CHARSET,
94 "Set the default character set.", 0,
95 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
96 {
"default_auth", OPT_DEFAULT_AUTH,
97 "Default authentication client-side plugin to use.",
98 &opt_default_auth, &opt_default_auth, 0,
99 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
100 {
"force",
'f',
"Force execution of mysqlcheck even if mysql_upgrade "
101 "has already been executed for the current version of MySQL.",
102 &opt_force, &opt_force, 0,
103 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
104 {
"host",
'h',
"Connect to host.", 0,
105 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
107 "Password to use when connecting to server. If password is not given,"
108 " it's solicited on the tty.", &opt_password,&opt_password,
109 0, GET_PASSWORD, OPT_ARG, 0, 0, 0, 0, 0, 0},
111 {
"pipe",
'W',
"Use named pipes to connect to server.", 0, 0, 0,
112 GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
114 {
"plugin_dir", OPT_PLUGIN_DIR,
"Directory for client-side plugins.",
115 &opt_plugin_dir, &opt_plugin_dir, 0,
116 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
117 {
"port",
'P',
"Port number to use for connection or 0 for default to, in "
118 "order of preference, my.cnf, $MYSQL_TCP_PORT, "
119 #if MYSQL_PORT_DEFAULT == 0
122 "built-in default (" STRINGIFY_ARG(MYSQL_PORT)
").",
123 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
124 {
"protocol", OPT_MYSQL_PROTOCOL,
125 "The protocol to use for connection (tcp, socket, pipe, memory).",
126 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
128 {
"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
129 "Base name of shared memory.", 0,
130 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
132 {
"version-check",
'k',
"Run this program only if its \'server version\' "
133 "matches the version of the server to which it's connecting, (enabled by "
134 "default); use --skip-version-check to avoid this check. Note: the \'server "
135 "version\' of the program is the version of the MySQL server with which it "
136 "was built/distributed.", &opt_version_check, &opt_version_check, 0,
137 GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
138 {
"socket",
'S',
"The socket file to use for connection.",
139 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
140 #include <sslopt-longopts.h>
141 {
"tmpdir",
't',
"Directory for temporary files.",
142 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
143 {
"upgrade-system-tables",
's',
"Only upgrade the system tables "
144 "do not try to upgrade the data.",
145 &opt_systables_only, &opt_systables_only, 0,
146 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
147 {
"user",
'u',
"User for login if not current user.", &opt_user,
148 &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
149 {
"verbose",
'v',
"Display more output about the process.",
150 &opt_verbose, &opt_verbose, 0,
151 GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
152 {
"write-binlog", OPT_WRITE_BINLOG,
153 "All commands including mysqlcheck are binlogged. Disabled by default; "
154 "use when commands should be sent to replication slaves.",
155 &opt_write_binlog, &opt_write_binlog, 0, GET_BOOL, NO_ARG,
157 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
161 static void free_used_memory(
void)
164 free_defaults(defaults_argv);
166 dynstr_free(&ds_args);
167 dynstr_free(&conn_args);
171 static void die(
const char *
fmt, ...)
180 fprintf(stderr,
"FATAL ERROR: ");
181 vfprintf(stderr, fmt, args);
182 fprintf(stderr,
"\n");
194 static void verbose(
const char *fmt, ...)
205 vfprintf(stdout, fmt, args);
206 fprintf(stdout,
"\n");
221 const char* argument)
224 const char* eq= NullS;
225 const char* arg= NullS;
229 switch (opt->
var_type & GET_TYPE_MASK) {
235 arg= (*(my_bool *)opt->
value) ?
"1" :
"0";
238 die(
"internal error at %s: %d",__FILE__, __LINE__);
241 dynstr_append_os_quoted(ds,
"--", opt->
name, eq, arg, NullS);
242 dynstr_append(ds,
" ");
247 get_one_option(
int optid,
const struct my_option *opt,
250 my_bool add_option= TRUE;
255 printf(
"%s Ver %s Distrib %s, for %s (%s)\n",
256 my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
257 puts(ORACLE_WELCOME_COPYRIGHT_NOTICE(
"2000"));
258 puts(
"MySQL utility for upgrading databases to new MySQL versions.\n");
259 my_print_help(my_long_options);
264 DBUG_PUSH(argument ? argument : default_dbug_option);
270 if (argument == disabled_my_option)
271 argument= (
char*)
"";
277 add_one_option(&ds_args, opt, argument);
285 strnmov(opt_tmpdir, argument,
sizeof(opt_tmpdir));
291 fprintf(stderr,
"%s: the '--%s' option is always ignored\n",
292 my_progname, optid ==
'b' ?
"basedir" :
"datadir");
299 case OPT_WRITE_BINLOG:
307 case OPT_MYSQL_PROTOCOL:
308 case OPT_SHARED_MEMORY_BASE_NAME:
310 case OPT_DEFAULT_AUTH:
311 add_one_option(&conn_args, opt, argument);
322 add_one_option(&ds_args, opt, argument);
332 static int run_command(
char* cmd,
344 if (!(res_file= popen(cmd,
"r")))
345 die(
"popen(\"%s\", \"r\") failed", cmd);
347 while (fgets(buf,
sizeof(buf), res_file))
349 DBUG_PRINT(
"info", (
"buf: %s", buf));
353 dynstr_append(ds_res, buf);
358 fprintf(stdout,
"%s", buf);
368 error= pclose(res_file);
369 return WEXITSTATUS(error);
380 DBUG_ENTER(
"run_tool");
381 DBUG_PRINT(
"enter", (
"tool_path: %s", tool_path));
383 if (init_dynamic_string(&ds_cmdline, IF_WIN(
"\"",
""), FN_REFLEN, FN_REFLEN))
384 die(
"Out of memory");
386 dynstr_append_os_quoted(&ds_cmdline, tool_path, NullS);
387 dynstr_append(&ds_cmdline,
" ");
389 va_start(args, ds_res);
391 while ((arg= va_arg(args,
char *)))
394 if (strncmp(arg,
"--", 2) == 0)
395 dynstr_append_os_quoted(&ds_cmdline, arg, NullS);
397 dynstr_append(&ds_cmdline, arg);
398 dynstr_append(&ds_cmdline,
" ");
404 dynstr_append(&ds_cmdline,
"\"");
407 DBUG_PRINT(
"info", (
"Running: %s", ds_cmdline.str));
408 ret= run_command(ds_cmdline.str, ds_res);
409 DBUG_PRINT(
"exit", (
"ret: %d", ret));
410 dynstr_free(&ds_cmdline);
420 static void find_tool(
char *tool_executable_name,
const char *tool_name,
421 const char *self_name)
423 char *last_fn_libchar;
425 DBUG_ENTER(
"find_tool");
426 DBUG_PRINT(
"enter", (
"progname: %s", my_progname));
428 if (init_dynamic_string(&ds_tmp,
"", 32, 32))
429 die(
"Out of memory");
431 last_fn_libchar= strrchr(self_name, FN_LIBCHAR);
433 if (last_fn_libchar == NULL)
439 strncpy(tool_executable_name, tool_name, FN_REFLEN);
458 if (((last_fn_libchar - 6) >= self_name) &&
459 (strncmp(last_fn_libchar - 5,
".libs", 5) == 0) &&
460 (*(last_fn_libchar - 6) == FN_LIBCHAR))
462 DBUG_PRINT(
"info", (
"Chopping off \".libs\" from end of path"));
463 last_fn_libchar -= 6;
466 len= last_fn_libchar - self_name;
468 my_snprintf(tool_executable_name, FN_REFLEN,
"%.*s%c%s",
469 len, self_name, FN_LIBCHAR, tool_name);
472 verbose(
"Looking for '%s' as: %s", tool_name, tool_executable_name);
477 if (run_tool(tool_executable_name,
481 IF_WIN(
"> NUL",
"> /dev/null"),
483 die(
"Can't execute '%s'", tool_executable_name);
485 dynstr_free(&ds_tmp);
500 char query_file_path[FN_REFLEN];
501 const uchar sql_log_bin[]=
"SET SQL_LOG_BIN=0;";
503 DBUG_ENTER(
"run_query");
504 DBUG_PRINT(
"enter", (
"query: %s", query));
505 if ((fd= create_temp_file(query_file_path,
506 opt_tmpdir[0] ? opt_tmpdir : NULL,
507 "sql", O_CREAT | O_SHARE | O_RDWR,
509 die(
"Failed to create temporary file for defaults");
516 if (!opt_write_binlog)
518 if (my_write(fd, sql_log_bin,
sizeof(sql_log_bin)-1,
519 MYF(MY_FNABP | MY_WME)))
521 my_close(fd, MYF(0));
522 my_delete(query_file_path, MYF(0));
523 die(
"Failed to write to '%s'", query_file_path);
527 if (my_write(fd, (uchar*) query, strlen(query),
528 MYF(MY_FNABP | MY_WME)))
530 my_close(fd, MYF(0));
531 my_delete(query_file_path, MYF(0));
532 die(
"Failed to write to '%s'", query_file_path);
535 ret= run_tool(mysql_path,
541 force ?
"--force":
"--skip-force",
542 ds_res ?
"--silent":
"",
548 my_close(fd, MYF(0));
549 my_delete(query_file_path, MYF(0));
561 char *value_start, *value_end;
568 if ((value_start= strchr(ds->str,
'\t')) == NULL)
573 if ((value_end= strchr(value_start,
'\n')) == NULL)
576 len= (size_t) MY_MIN(FN_REFLEN, value_end-value_start);
577 strncpy(value, value_start, len);
583 static int get_upgrade_info_file_name(
char*
name)
586 DBUG_ENTER(
"get_upgrade_info_file_name");
588 if (init_dynamic_string(&ds_datadir, NULL, 32, 32))
589 die(
"Out of memory");
591 if (run_query(
"show variables like 'datadir'",
592 &ds_datadir, FALSE) ||
593 extract_variable_from_show(&ds_datadir, name))
595 dynstr_free(&ds_datadir);
599 dynstr_free(&ds_datadir);
601 fn_format(name,
"mysql_upgrade_info", name,
"", MYF(0));
602 DBUG_PRINT(
"exit", (
"name: %s", name));
623 static int upgrade_already_done(
void)
626 char upgrade_info_file[FN_REFLEN]= {0};
627 char buf[
sizeof(MYSQL_SERVER_VERSION)+1];
630 if (get_upgrade_info_file_name(upgrade_info_file))
633 if (!(in= my_fopen(upgrade_info_file, O_RDONLY, MYF(0))))
640 memset(buf, 0,
sizeof(buf));
641 res= fgets(buf,
sizeof(buf), in);
643 my_fclose(in, MYF(0));
648 return (strncmp(res, MYSQL_SERVER_VERSION,
649 sizeof(MYSQL_SERVER_VERSION)-1)==0);
664 static void create_mysql_upgrade_info_file(
void)
667 char upgrade_info_file[FN_REFLEN]= {0};
669 if (get_upgrade_info_file_name(upgrade_info_file))
672 if (!(out= my_fopen(upgrade_info_file, O_TRUNC | O_WRONLY, MYF(0))))
675 "Could not create the upgrade info file '%s' in "
676 "the MySQL Servers datadir, errno: %d\n",
677 upgrade_info_file, errno);
682 fputs(MYSQL_SERVER_VERSION, out);
683 my_fclose(out, MYF(0));
689 if (!upgrade_already_done())
691 "Could not write to the upgrade info file '%s' in "
692 "the MySQL Servers datadir, errno: %d\n",
693 upgrade_info_file, errno);
702 static void print_conn_args(
const char *tool_name)
704 if (conn_args.str[0])
705 verbose(
"Running '%s' with connection arguments: %s", tool_name,
708 verbose(
"Running '%s with default connection arguments", tool_name);
717 static int run_mysqlcheck_upgrade(
void)
719 print_conn_args(
"mysqlcheck");
720 return run_tool(mysqlcheck_path,
726 "--skip-database=mysql",
728 opt_write_binlog ?
"--write-binlog" :
"--skip-write-binlog",
733 static int run_mysqlcheck_fixnames(
void)
735 print_conn_args(
"mysqlcheck");
736 return run_tool(mysqlcheck_path,
741 "--skip-database=mysql",
744 opt_write_binlog ?
"--write-binlog" :
"--skip-write-binlog",
749 static int run_mysqlcheck_mysql_db_upgrade(
void)
751 print_conn_args(
"mysqlcheck");
752 return run_tool(mysqlcheck_path,
759 opt_write_binlog ?
"--write-binlog" :
"--skip-write-binlog",
766 static int run_mysqlcheck_mysql_db_fixnames(
void)
768 print_conn_args(
"mysqlcheck");
769 return run_tool(mysqlcheck_path,
776 opt_write_binlog ?
"--write-binlog" :
"--skip-write-binlog",
780 static const char *expected_errors[]=
789 static my_bool is_expected_error(
const char* line)
791 const char** error= expected_errors;
798 if (strncmp(line,
"ERROR", 5) != 0 ||
799 strncmp(line, *error, strlen(*error)) == 0)
807 static char* get_line(
char* line)
809 while (*line && *line !=
'\n')
818 static void print_line(
char* line)
820 while (*line && *line !=
'\n')
822 fputc(*line, stderr);
835 static int run_sql_fix_privilege_tables(
void)
837 int found_real_errors= 0;
838 const char **query_ptr;
841 DBUG_ENTER(
"run_sql_fix_privilege_tables");
843 if (init_dynamic_string(&ds_script,
"", 65536, 1024))
844 die(
"Out of memory");
846 if (init_dynamic_string(&ds_result,
"", 512, 512))
847 die(
"Out of memory");
849 verbose(
"Running 'mysql_fix_privilege_tables'...");
856 for ( query_ptr= &mysql_fix_privilege_tables[0];
861 dynstr_append(&ds_script, *query_ptr);
864 run_query(ds_script.str,
874 char *line= ds_result.str;
877 if (!is_expected_error(line))
883 else if ((strncmp(line,
"WARNING", 7) == 0) ||
884 (strncmp(line,
"Warning", 7) == 0))
888 }
while ((line= get_line(line)) && *line);
891 dynstr_free(&ds_result);
892 dynstr_free(&ds_script);
893 DBUG_RETURN(found_real_errors);
897 static const char *load_default_groups[]=
906 static ulong STDCALL calc_server_version(
char *some_version)
908 uint major, minor, version;
909 char *point= some_version, *end_point;
910 major= (uint) strtoul(point, &end_point, 10); point=end_point+1;
911 minor= (uint) strtoul(point, &end_point, 10); point=end_point+1;
912 version= (uint) strtoul(point, &end_point, 10);
913 return (ulong) major * 10000L + (ulong)(minor * 100 + version);
923 static int check_version_match(
void)
926 char version_str[NAME_CHAR_LEN + 1];
928 if (init_dynamic_string(&ds_version, NULL, NAME_CHAR_LEN, NAME_CHAR_LEN))
929 die(
"Out of memory");
931 if (run_query(
"show variables like 'version'",
932 &ds_version, FALSE) ||
933 extract_variable_from_show(&ds_version, version_str))
935 dynstr_free(&ds_version);
939 dynstr_free(&ds_version);
941 if (calc_server_version((
char *) version_str) != MYSQL_VERSION_ID)
943 fprintf(stderr,
"Error: Server version (%s) does not match with the "
944 "version of\nthe server (%s) with which this program was built/"
945 "distributed. You can\nuse --skip-version-check to skip this "
946 "check.\n", version_str, MYSQL_SERVER_VERSION);
954 int main(
int argc,
char **argv)
956 char self_name[FN_REFLEN];
961 if (GetModuleFileName(NULL, self_name, FN_REFLEN) == 0)
964 strncpy(self_name, argv[0], FN_REFLEN);
967 if (init_dynamic_string(&ds_args,
"", 512, 256) ||
968 init_dynamic_string(&conn_args,
"", 512, 256))
969 die(
"Out of memory");
971 my_getopt_use_args_separator= TRUE;
972 if (load_defaults(
"my", load_default_groups, &argc, &argv))
974 my_getopt_use_args_separator= FALSE;
977 if (handle_options(&argc, &argv, my_long_options, get_one_option))
980 my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
981 if (debug_check_flag)
982 my_end_arg= MY_CHECK_ERROR;
986 opt_password= get_tty_password(NullS);
988 dynstr_append_os_quoted(&ds_args,
"--password=", opt_password, NullS);
989 dynstr_append(&ds_args,
" ");
992 dynstr_append_os_quoted(&ds_args,
"--user=", opt_user, NullS);
993 dynstr_append(&ds_args,
" ");
996 find_tool(mysql_path, IF_WIN(
"mysql.exe",
"mysql"), self_name);
998 if (!opt_systables_only)
1001 find_tool(mysqlcheck_path, IF_WIN(
"mysqlcheck.exe",
"mysqlcheck"), self_name);
1005 printf(
"The --upgrade-system-tables option was used, databases won't be touched.\n");
1012 if (!opt_force && upgrade_already_done())
1014 printf(
"This installation of MySQL is already upgraded to %s, "
1015 "use --force if you still need to run mysql_upgrade\n",
1016 MYSQL_SERVER_VERSION);
1020 if (opt_version_check && check_version_match())
1021 die(
"Upgrade failed");
1029 if ((!opt_systables_only &&
1030 (run_mysqlcheck_mysql_db_fixnames() || run_mysqlcheck_mysql_db_upgrade())) ||
1031 run_sql_fix_privilege_tables() ||
1032 (!opt_systables_only &&
1033 (run_mysqlcheck_fixnames() || run_mysqlcheck_upgrade())))
1039 die(
"Upgrade failed" );
1044 create_mysql_upgrade_info_file();