Commit b5afca05 authored by holyfoot@deer.(none)'s avatar holyfoot@deer.(none)

WL#2645 (mysql_upgrade tool)

parent a5d18bc8
...@@ -14,49 +14,92 @@ ...@@ -14,49 +14,92 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <stdlib.h>
#include "client_priv.h" #include "client_priv.h"
#include <my_dir.h> #include <my_dir.h>
static my_bool opt_force=0, opt_verbose=0; static my_bool opt_force= 0, opt_verbose= 0, tty_password= 0;
static char *user= (char*)"root", *basedir=0, *datadir=0; static char *user= (char*) "root", *basedir= 0, *datadir= 0, *opt_password= 0;
static my_bool upgrade_defaults_created= 0;
static my_string opt_mysql_port, opt_mysql_unix_port= 0;
static char *default_dbug_option= (char*) "d:t:O,/tmp/comp_err.trace";
static my_bool info_flag= 0;
static struct my_option my_long_options[] = static struct my_option my_long_options[]=
{ {
{"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0}, NO_ARG, 0, 0, 0, 0, 0, 0},
{"basedir", 'b', "Specifies the directory where MySQL is installed", (gptr*) &basedir, {"basedir", 'b', "Specifies the directory where MySQL is installed",
(gptr*) &basedir,
(gptr*) &basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, (gptr*) &basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"datadir", 'd', "Specifies the data directory", (gptr*) &datadir, {"datadir", 'd', "Specifies the data directory", (gptr*) &datadir,
(gptr*) &datadir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, (gptr*) &datadir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifdef DBUG_OFF
{"debug", '#', "This is a non-debug version. Catch this and exit",
0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
#else
{"debug", '#', "Output debug log", (gptr *) & default_dbug_option,
(gptr *) & default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"debug-info", 'T', "Print some debug info at exit.", (gptr *) & info_flag,
(gptr *) & info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"force", 'f', "Continue even if we get an sql-error.", {"force", 'f', "Continue even if we get an sql-error.",
(gptr*) &opt_force, (gptr*) &opt_force, 0, GET_BOOL, NO_ARG, 0, 0, (gptr*) &opt_force, (gptr*) &opt_force, 0, GET_BOOL, NO_ARG, 0, 0,
0, 0, 0, 0}, 0, 0, 0, 0},
{"password", 'p',
"Password to use when connecting to server. If password is not given it's solicited on the tty.",
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
(gptr*) &opt_mysql_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0,
0},
{"protocol", OPT_MYSQL_PROTOCOL,
"The protocol of connection (tcp,socket,pipe,memory).",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"socket", 'S', "Socket file to use for connection.",
(gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"user", 'u', "User for login if not current user.", (gptr*) &user, {"user", 'u', "User for login if not current user.", (gptr*) &user,
(gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"verbose", 'v', "Display more output about the process", 0, 0, 0, GET_NO_ARG, {"verbose", 'v', "Display more output about the process", (gptr*) &opt_verbose,
NO_ARG, 0, 0, 0, 0, 0, 0}, (gptr *) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
}; };
static const char *load_default_groups[] = { "mysql_upgrade", "client", 0 }; static const char *load_default_groups[]=
{
"mysql_upgrade", "client", 0
};
#include <help_end.h> #include <help_end.h>
static my_bool static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)), get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)),
char *argument __attribute__((unused))) char *argument)
{ {
switch(optid) { switch (optid) {
case '?': case '?':
puts("MySQL utility script to upgrade database to the current server version\n"); puts
puts("\n"); ("MySQL utility script to upgrade database to the current server version");
puts("");
my_print_help(my_long_options); my_print_help(my_long_options);
exit(0); exit(0);
case '#':
DBUG_PUSH(argument ? argument : default_dbug_option);
break;
case 'f': case 'f':
opt_force= TRUE; opt_force= TRUE;
break; break;
case 'v': case 'p':
opt_verbose= TRUE; tty_password= 1;
if (argument)
{
char *start= argument;
my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
opt_password= my_strdup(argument, MYF(MY_FAE));
while (*argument)
*argument++= 'x'; /* Destroy argument */
if (*start)
start[1]= 0; /* Cut length of argument */
tty_password= 0;
}
break; break;
default:; default:;
}; };
...@@ -64,35 +107,104 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), ...@@ -64,35 +107,104 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
} }
static my_bool test_file_exists_res(const char *dir, const char *fname, char *buffer) /* buffer should be not smaller than FN_REFLEN */
static my_bool test_file_exists_res(const char *dir, const char *fname,
char *buffer, char **buf_end)
{ {
MY_STAT stat_info; MY_STAT stat_info;
if (fname) *buf_end= strxnmov(buffer, FN_REFLEN-1, dir, "/", fname, NullS);
sprintf(buffer, "%s/%s", dir, fname); unpack_filename(buffer, buffer);
else
strcpy(buffer, dir);
return my_stat(buffer, &stat_info, MYF(0)) != 0; return my_stat(buffer, &stat_info, MYF(0)) != 0;
} }
static my_bool test_file_exists(const char *dir, const char *fname) static my_bool test_file_exists(const char *dir, const char *fname)
{ {
char path[1024]; char path[FN_REFLEN];
return test_file_exists_res(dir, fname, path); char *path_end;
return test_file_exists_res(dir, fname, path, &path_end);
}
static int create_check_file(const char *path)
{
File check_file= my_open(path, O_CREAT | O_WRONLY, MYF(MY_FAE | MY_WME));
int error;
if (check_file < 0)
return 1;
error= my_write(check_file, VERSION, strlen(VERSION), MYF(MY_WME | MY_FNABP));
error= my_close(check_file, MYF(MY_FAE | MY_WME)) || error;
return error;
}
static int create_defaults_file(const char *path, const char *our_defaults_path)
{
uint b_read;
File our_defaults_file;
char buffer[512];
char *buffer_end;
int error;
/* check if the defaults file is needed at all */
if (!opt_password)
return 0;
File defaults_file= my_open(path, O_BINARY | O_CREAT | O_WRONLY,
MYF(MY_FAE | MY_WME));
if (defaults_file < 0)
return 1;
upgrade_defaults_created= 1;
if (our_defaults_path)
{
our_defaults_file= my_open(our_defaults_path, O_RDONLY,
MYF(MY_FAE | MY_WME));
if (our_defaults_file < 0)
return 1;
do
{
if (((b_read= my_read(our_defaults_file, buffer,
sizeof(buffer), MYF(MY_WME))) == MY_FILE_ERROR) ||
my_write(defaults_file, buffer, b_read, MYF(MY_FNABP | MY_WME)))
{
error= 1;
goto close_return;
}
} while (b_read == sizeof(buffer));
}
buffer_end= strnmov(buffer, "\n[client]", sizeof(buffer));
if (opt_password)
buffer_end= strxnmov(buffer, sizeof(buffer),
"\npassword=", opt_password, NullS);
error= my_write(defaults_file, buffer, (int) (buffer_end - buffer),
MYF(MY_WME | MY_FNABP));
close_return:
return my_close(defaults_file, MYF(MY_WME)) || error;
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
char bindir[1024]; char bindir[FN_REFLEN];
char datadir_buf[1024]; char *bindir_end, *buf_end;
char mysqlcheck_line[1024]; char datadir_buf[FN_REFLEN];
char check_file_name[1024]; char mysqlcheck_line[FN_REFLEN], *mysqlcheck_end;
char check_file_name[FN_REFLEN];
int check_file; int check_file;
char fix_priv_tables_cmd[1024]; char fix_priv_tables_cmd[FN_REFLEN], *fix_cmd_end;
char script_line[1024]; char script_line[FN_REFLEN];
int error; int error;
char *forced_defaults_file;
char *forced_extra_defaults;
char *defaults_group_suffix;
char upgrade_defaults_path[FN_REFLEN], *defaults_to_use= 0;
char port_socket[100], *port_socket_end;
MY_INIT(argv[0]);
#ifdef __NETWARE__ #ifdef __NETWARE__
setscreenmode(SCR_AUTOCLOSE_ON_EXIT); setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
#endif #endif
...@@ -102,107 +214,187 @@ int main(int argc, char **argv) ...@@ -102,107 +214,187 @@ int main(int argc, char **argv)
if ((error= handle_options(&argc, &argv, my_long_options, get_one_option))) if ((error= handle_options(&argc, &argv, my_long_options, get_one_option)))
exit(error); exit(error);
if (!basedir) if (tty_password)
opt_password= get_tty_password(NullS);
/* Check if we want to force the use a specific default file */
get_defaults_options(argc, argv,
&forced_defaults_file, &forced_extra_defaults,
&defaults_group_suffix);
port_socket_end= port_socket;
if (opt_mysql_port)
port_socket_end= strxnmov(port_socket, sizeof(port_socket) - 1, " --port=",
opt_mysql_port, NullS);
if (opt_mysql_unix_port)
port_socket_end= strxnmov(port_socket_end,
sizeof(port_socket) -
(int)(port_socket_end - port_socket) - 1,
" --socket=", opt_mysql_unix_port, NullS);
*port_socket_end= 0;
if (basedir)
{
bindir_end= strmake(bindir, basedir, sizeof(bindir)-1);
}
else
{ {
if (test_file_exists("./share/mysql/english", "errmsg.sys") if (test_file_exists("./share/mysql/english", "errmsg.sys")
&& (test_file_exists("./bin", "mysqld") || && (test_file_exists("./bin", "mysqld") ||
test_file_exists("./libexec", "mysqld"))) test_file_exists("./libexec", "mysqld")))
{ {
getcwd(bindir, sizeof(bindir)); getcwd(bindir, sizeof(bindir));
bindir_end= bindir + strlen(bindir);
} }
else else
{ {
strcpy(bindir, DEFAULT_MYSQL_HOME); bindir_end= strmake(bindir, DEFAULT_MYSQL_HOME, sizeof(bindir)-1);
} }
} }
else
{
strcpy(bindir, basedir);
}
if (!datadir) if (!datadir)
{ {
datadir= datadir_buf; datadir= datadir_buf;
if (test_file_exists(bindir,"data/mysql")) if (test_file_exists(bindir, "data/mysql"))
{ {
sprintf(datadir, "%s/data", bindir); *strxnmov(datadir_buf, sizeof(datadir_buf)-1, bindir, "/data", NullS)= 0;
} }
else if (test_file_exists(bindir, "var/mysql")) else if (test_file_exists(bindir, "var/mysql"))
{ {
sprintf(datadir, "%s/var", bindir); *strxnmov(datadir_buf, sizeof(datadir_buf)-1, bindir, "/var", NullS)= 0;
} }
else else
strcpy(datadir, DATADIR); datadir= (char*) DATADIR;
} }
strcat(bindir, "/bin"); strmake(bindir_end, "/bin", sizeof(bindir) - (int) (bindir_end - bindir)-1);
if (!test_file_exists(bindir, "mysqlcheck")) if (!test_file_exists_res
(bindir, "mysqlcheck", mysqlcheck_line, &mysqlcheck_end))
{ {
printf("Can't find program '%s/mysqlcheck'\n", bindir); printf("Can't find program '%s'\n", mysqlcheck_line);
puts("Please restart with --basedir=mysql-install-directory\n"); puts("Please restart with --basedir=mysql-install-directory");
exit(1); exit(1);
} }
if (!test_file_exists(datadir, "mysql/user.frm")) if (!test_file_exists(datadir, "mysql/user.frm"))
{ {
puts("Can't find data directory. Please restart with --datadir=path-to-data-dir\n"); puts
("Can't find data directory. Please restart with --datadir=path-to-data-dir");
exit(1); exit(1);
} }
if (test_file_exists_res(datadir, "mysql_upgrade_info", check_file_name) && !opt_force) /* create the modified defaults file to be used by mysqlcheck */
/* and mysql tools */
*strxnmov(upgrade_defaults_path, sizeof(upgrade_defaults_path)-1,
datadir, "/upgrade_defaults", NullS)= 0;
unpack_filename(upgrade_defaults_path, upgrade_defaults_path);
if ((error=
create_defaults_file(upgrade_defaults_path, forced_extra_defaults)))
goto err_exit;
defaults_to_use= upgrade_defaults_created ?
upgrade_defaults_path : forced_extra_defaults;
if (test_file_exists_res(datadir, "mysql_upgrade_info", check_file_name,
&buf_end) && !opt_force)
{ {
char chf_buffer[10]; char chf_buffer[50];
int b_read; int b_read;
check_file= open(check_file_name, O_RDONLY); check_file= my_open(check_file_name, O_RDONLY, MYF(0));
b_read= read(check_file, chf_buffer, sizeof(chf_buffer)); b_read= my_read(check_file, chf_buffer, sizeof(chf_buffer)-1, MYF(0));
chf_buffer[b_read]= 0; chf_buffer[b_read]= 0;
if (strcmp(chf_buffer, VERSION)) my_close(check_file, MYF(0));
if (!strcmp(chf_buffer, VERSION))
{ {
if (opt_verbose) if (opt_verbose)
puts("mysql_upgrade already done for this version\n"); puts("mysql_upgrade already done for this version");
goto fix_priv_tables; goto fix_priv_tables;
} }
close(check_file);
} }
sprintf(mysqlcheck_line, if (defaults_to_use)
"%s/mysqlcheck --check-upgrade --all-databases --auto-repair --user=%s", {
bindir, user); mysqlcheck_end= strxnmov(mysqlcheck_end,
sizeof(mysqlcheck_line) - (int) (mysqlcheck_end -
mysqlcheck_line),
" --defaults-extra-file=", defaults_to_use,NullS);
}
mysqlcheck_end= strxnmov(mysqlcheck_end,
sizeof(mysqlcheck_line) -
(int) (mysqlcheck_end - mysqlcheck_line - 1),
" --check-upgrade --all-databases --auto-repair --user=",
user, port_socket, NullS);
*mysqlcheck_end= 0;
if (opt_verbose) if (opt_verbose)
printf("Running %s\n", mysqlcheck_line); printf("Running %s\n", mysqlcheck_line);
system(mysqlcheck_line); if ((error= system(mysqlcheck_line)))
{
printf("Error executing '%s'\n", mysqlcheck_line);
goto err_exit;
}
check_file= open(check_file_name, O_CREAT | O_WRONLY); if ((error= create_check_file(check_file_name)))
write(check_file, VERSION, strlen(VERSION)); goto err_exit;
close(check_file);
fix_priv_tables: fix_priv_tables:
if (!test_file_exists(bindir, "mysql")) if (!test_file_exists_res(bindir, "mysql", fix_priv_tables_cmd, &fix_cmd_end))
{ {
puts("Could not find MySQL command-line client (mysql).\n"); puts("Could not find MySQL command-line client (mysql).");
puts("Please use --basedir to specify the directory where MySQL is installed.\n"); puts
exit(1); ("Please use --basedir to specify the directory where MySQL is installed.");
error= 1;
goto err_exit;
} }
if (!test_file_exists_res(basedir, if (!test_file_exists_res(basedir,
"support_files/mysql_fix_privilege_tables.sql", script_line) && "support_files/mysql_fix_privilege_tables.sql",
!test_file_exists_res(basedir, script_line, &buf_end)
"share/mysql_fix_privileges_tables.sql", script_line) && && !test_file_exists_res(basedir, "share/mysql_fix_privilege_tables.sql",
!test_file_exists_res(basedir, script_line, &buf_end)
"share/mysql/mysql_fix_privilege_tables.sql", script_line) && && !test_file_exists_res(basedir,
!test_file_exists_res(basedir, "share/mysql/mysql_fix_privilege_tables.sql",
"scripts/mysql_fix_privilege_tables.sql", script_line) && script_line, &buf_end)
!test_file_exists_res("/usr/local/mysql/share/mysql", && !test_file_exists_res(basedir,
"mysql_fix_privilege_tables.sql", script_line)) "scripts/mysql_fix_privilege_tables.sql",
{ script_line, &buf_end)
puts("Could not find file mysql_fix_privilege_tables.sql\n"); && !test_file_exists_res("/usr/local/mysql/share/mysql",
puts("Please use --basedir to specify the directory where MySQL is installed\n"); "mysql_fix_privilege_tables.sql", script_line,
exit(1); &buf_end))
{
puts("Could not find file mysql_fix_privilege_tables.sql");
puts
("Please use --basedir to specify the directory where MySQL is installed");
error= 1;
goto err_exit;
} }
sprintf(fix_priv_tables_cmd, "%s/mysql < %s", bindir, script_line); if (defaults_to_use)
system(fix_priv_tables_cmd); {
fix_cmd_end= strxnmov(fix_cmd_end,
sizeof(fix_priv_tables_cmd) -
(int) (fix_cmd_end - fix_priv_tables_cmd - 1),
" --defaults-extra-file=", defaults_to_use, NullS);
}
fix_cmd_end= strxnmov(fix_cmd_end,
sizeof(fix_priv_tables_cmd) - (int) (fix_cmd_end -
fix_priv_tables_cmd),
" --user=", user, port_socket, " mysql < ", script_line, NullS);
*fix_cmd_end= 0;
if ((error= system(fix_priv_tables_cmd)))
{
/* Problem is that the 'Duplicate column' error */
/* which is not a bug for the script makes 'mysql' return */
/* an error */
/* printf("Error executing '%s'\n", fix_priv_tables_cmd); */
}
err_exit:
if (upgrade_defaults_created)
my_delete(upgrade_defaults_path, MYF(0));
my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
return error; return error;
} /* main */ } /* main */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment