summaryrefslogtreecommitdiff
path: root/client/mysql_upgrade.c
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2022-02-01 20:33:04 +0100
committerOleksandr Byelkin <sanja@mariadb.com>2022-02-01 20:33:04 +0100
commitcf63eecef44f189ce2d221612dee9dfc1885ba4e (patch)
tree93b4e6645a1d371bd8012a0aa8e6e3a3d541b2a6 /client/mysql_upgrade.c
parentfb40a2fabf8d8cf765c83a0b8e609dd893c75ec3 (diff)
parentc04a203a10e282e1f33fd04d8a1b7ff0b076bce5 (diff)
downloadmariadb-git-cf63eecef44f189ce2d221612dee9dfc1885ba4e.tar.gz
Merge branch '10.4' into 10.5
Diffstat (limited to 'client/mysql_upgrade.c')
-rw-r--r--client/mysql_upgrade.c318
1 files changed, 222 insertions, 96 deletions
diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c
index e49b0fd0dc0..d778450c915 100644
--- a/client/mysql_upgrade.c
+++ b/client/mysql_upgrade.c
@@ -22,7 +22,7 @@
#include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
-#define VER "1.4"
+#define VER "2.0"
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
@@ -37,13 +37,15 @@
#endif
static int phase = 0;
+static int info_file= -1;
static const int phases_total = 7;
static char mysql_path[FN_REFLEN];
static char mysqlcheck_path[FN_REFLEN];
-static my_bool opt_force, opt_verbose, debug_info_flag, debug_check_flag,
+static my_bool debug_info_flag, debug_check_flag,
opt_systables_only, opt_version_check;
-static my_bool opt_not_used, opt_silent;
+static my_bool opt_not_used, opt_silent, opt_check_upgrade;
+static uint opt_force, opt_verbose;
static uint my_end_arg= 0;
static char *opt_user= (char*)"root";
@@ -70,7 +72,7 @@ static char **defaults_argv;
static my_bool not_used; /* Can't use GET_BOOL without a value pointer */
-char upgrade_from_version[sizeof("10.20.456-MariaDB")+1];
+char upgrade_from_version[sizeof("10.20.456-MariaDB")+30];
static my_bool opt_write_binlog;
@@ -96,8 +98,8 @@ static struct my_option my_long_options[]=
{"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.", &default_dbug_option,
- &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"debug", '#', "Output debug log.",
+ 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
&debug_check_flag, &debug_check_flag,
@@ -111,9 +113,13 @@ static struct my_option my_long_options[]=
"Default authentication client-side plugin to use.",
&opt_default_auth, &opt_default_auth, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"check-if-upgrade-is-needed", OPT_CHECK_IF_UPGRADE_NEEDED,
+ "Exits with status 0 if an upgrades is required, 1 otherwise.",
+ &opt_check_upgrade, &opt_check_upgrade,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"force", 'f', "Force execution of mysqlcheck even if mysql_upgrade "
"has already been executed for the current version of MariaDB.",
- &opt_force, &opt_force, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ &opt_not_used, &opt_not_used, 0 , GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"host", 'h', "Connect to host.", 0,
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#define PASSWORD_OPT 12
@@ -191,6 +197,12 @@ static void free_used_memory(void)
dynstr_free(&ds_plugin_data_types);
if (cnf_file_path)
my_delete(cnf_file_path, MYF(MY_WME));
+ if (info_file >= 0)
+ {
+ (void) my_lock(info_file, F_UNLCK, 0, 1, MYF(0));
+ my_close(info_file, MYF(MY_WME));
+ info_file= -1;
+ }
}
@@ -236,6 +248,13 @@ static void verbose(const char *fmt, ...)
}
+static void print_error(const char *error_msg, DYNAMIC_STRING *output)
+{
+ fprintf(stderr, "%s\n", error_msg);
+ fprintf(stderr, "%s", output->str);
+}
+
+
/*
Add one option - passed to mysql_upgrade on command line
or by defaults file(my.cnf) - to a dynamic string, in
@@ -269,6 +288,7 @@ static void add_one_option_cnf_file(DYNAMIC_STRING *ds,
dynstr_append(ds, "\n");
}
+
static my_bool
get_one_option(const struct my_option *opt, const char *argument,
const char *filename __attribute__((unused)))
@@ -344,11 +364,17 @@ get_one_option(const struct my_option *opt, const char *argument,
my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
die(0);
break;
+ case 'f': /* --force */
+ opt_force++;
+ if (argument == disabled_my_option)
+ opt_force= 0;
+ add_option= 0;
+ break;
case OPT_SILENT:
opt_verbose= 0;
add_option= 0;
break;
- case 'f': /* --force */
+ case OPT_CHECK_IF_UPGRADE_NEEDED: /* --check-if-upgrade-needed */
case 's': /* --upgrade-system-tables */
case OPT_WRITE_BINLOG: /* --write-binlog */
add_option= FALSE;
@@ -378,6 +404,18 @@ get_one_option(const struct my_option *opt, const char *argument,
}
+/* Convert the specified version string into the numeric format. */
+
+static ulong STDCALL calc_server_version(char *some_version)
+{
+ uint major, minor, version;
+ char *point= some_version, *end_point;
+ major= (uint) strtoul(point, &end_point, 10); point=end_point+1;
+ minor= (uint) strtoul(point, &end_point, 10); point=end_point+1;
+ version= (uint) strtoul(point, &end_point, 10);
+ return (ulong) major * 10000L + (ulong)(minor * 100 + version);
+}
+
/**
Run a command using the shell, storing its output in the supplied dynamic
string.
@@ -584,7 +622,7 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res,
if (my_write(fd, sql_log_bin, sizeof(sql_log_bin)-1,
MYF(MY_FNABP | MY_WME)))
{
- my_close(fd, MYF(0));
+ my_close(fd, MYF(MY_WME));
my_delete(query_file_path, MYF(0));
die("Failed to write to '%s'", query_file_path);
}
@@ -593,7 +631,7 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res,
if (my_write(fd, (uchar*) query, strlen(query),
MYF(MY_FNABP | MY_WME)))
{
- my_close(fd, MYF(0));
+ my_close(fd, MYF(MY_WME));
my_delete(query_file_path, MYF(0));
die("Failed to write to '%s'", query_file_path);
}
@@ -610,7 +648,7 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res,
"2>&1",
NULL);
- my_close(fd, MYF(0));
+ my_close(fd, MYF(MY_WME));
my_delete(query_file_path, MYF(0));
DBUG_RETURN(ret);
@@ -657,6 +695,9 @@ static int get_upgrade_info_file_name(char* name)
&ds_datadir, FALSE) ||
extract_variable_from_show(&ds_datadir, name))
{
+ print_error("Reading datadir from the MariaDB server failed. Got the "
+ "following error when executing the 'mysql' command line client",
+ &ds_datadir);
dynstr_free(&ds_datadir);
DBUG_RETURN(1); /* Query failed */
}
@@ -668,6 +709,83 @@ static int get_upgrade_info_file_name(char* name)
DBUG_RETURN(0);
}
+static char upgrade_info_file[FN_REFLEN]= {0};
+
+
+/*
+ Open or create mysql_upgrade_info file in servers data dir.
+
+ Take a lock to ensure there cannot be any other mysql_upgrades
+ runninc concurrently
+*/
+
+const char *create_error_message=
+ "%sCould not open or create the upgrade info file '%s' in "
+ "the MariaDB Servers data directory, errno: %d (%s)\n";
+
+
+
+static void open_mysql_upgrade_file()
+{
+ char errbuff[80];
+ if (get_upgrade_info_file_name(upgrade_info_file))
+ {
+ die("Upgrade failed");
+ }
+ if ((info_file= my_create(upgrade_info_file, 0,
+ O_RDWR | O_NOFOLLOW,
+ MYF(0))) < 0)
+ {
+ if (opt_force >= 2)
+ {
+ fprintf(stdout, create_error_message,
+ "", upgrade_info_file, errno,
+ my_strerror(errbuff, sizeof(errbuff)-1, errno));
+ fprintf(stdout,
+ "--force --force used, continuing without using the %s file.\n"
+ "Note that this means that there is no protection against "
+ "concurrent mysql_upgrade executions and next mysql_upgrade run "
+ "will do a full upgrade again!\n",
+ upgrade_info_file);
+ return;
+ }
+ fprintf(stdout, create_error_message,
+ "FATAL ERROR: ",
+ upgrade_info_file, errno,
+ my_strerror(errbuff, sizeof(errbuff)-1, errno));
+ if (errno == EACCES)
+ {
+ fprintf(stderr,
+ "Note that mysql_upgrade should be run as the same user as the "
+ "MariaDB server binary, normally 'mysql' or 'root'.\n"
+ "Alternatively you can use mysql_upgrade --force --force. "
+ "Please check the documentation if you decide to use the force "
+ "option!\n");
+ }
+ fflush(stderr);
+ die(0);
+ }
+ if (my_lock(info_file, F_WRLCK, 0, 1, MYF(0)))
+ {
+ die("Could not exclusively lock on file '%s'. Error %d: %s\n",
+ upgrade_info_file, my_errno,
+ my_strerror(errbuff, sizeof(errbuff)-1, my_errno));
+ }
+}
+
+
+/**
+ Place holder for versions that require a major upgrade
+
+ @return 0 upgrade has alredy been run on this version
+ @return 1 upgrade has to be run
+
+*/
+
+static int faulty_server_versions(const char *version)
+{
+ return 0;
+}
/*
Read the content of mysql_upgrade_info file and
@@ -677,86 +795,111 @@ static int get_upgrade_info_file_name(char* name)
NOTE
This is an optimization to avoid running mysql_upgrade
when it's already been performed for the particular
- version of MySQL.
+ version of MariaDB.
- In case the MySQL server can't return the upgrade info
+ In case the MariaDBL server can't return the upgrade info
file it's always better to report that the upgrade hasn't
been performed.
+ @return 0 Upgrade has alredy been run on this version
+ @return > 0 Upgrade has to be run
*/
-static int upgrade_already_done(myf flags)
+static int upgrade_already_done(int silent)
{
- FILE *in;
- char upgrade_info_file[FN_REFLEN]= {0};
-
- if (get_upgrade_info_file_name(upgrade_info_file))
- return 0; /* Could not get filename => not sure */
-
- if (!(in= my_fopen(upgrade_info_file, O_RDONLY, flags)))
- return 0; /* Could not open file => not sure */
+ const char *version = MYSQL_SERVER_VERSION;
+ const char *s;
+ char *pos;
+ my_off_t length;
- bzero(upgrade_from_version, sizeof(upgrade_from_version));
- if (!fgets(upgrade_from_version, sizeof(upgrade_from_version), in))
+ if (info_file < 0)
{
- /* Preserve errno for caller */
- int save_errno= errno;
- (void) my_fclose(in, flags);
- errno= save_errno;
- return 0;
+ DBUG_ASSERT(opt_force > 1);
+ return 1; /* No info file and --force */
}
- if (my_fclose(in, flags))
- return 0;
-
- errno= 0;
- return (strncmp(upgrade_from_version, MYSQL_SERVER_VERSION,
- sizeof(MYSQL_SERVER_VERSION)-1)==0);
-}
+ bzero(upgrade_from_version, sizeof(upgrade_from_version));
+ (void) my_seek(info_file, 0, SEEK_SET, MYF(0));
+ /* We have -3 here to make calc_server_version() safe */
+ length= my_read(info_file, (uchar*) upgrade_from_version,
+ sizeof(upgrade_from_version)-3,
+ MYF(MY_WME));
-/*
- Write mysql_upgrade_info file in servers data dir indicating that
- upgrade has been done for this version
+ if (!length)
+ {
+ if (opt_verbose)
+ verbose("Empty or non existent %s. Assuming mysql_upgrade has to be run!",
+ upgrade_info_file);
+ return 1;
+ }
- NOTE
- This might very well fail but since it's just an optimization
- to run mysql_upgrade only when necessary the error can be
- ignored.
+ /* Remove possible \ŋ that may end in output */
+ if ((pos= strchr(upgrade_from_version, '\n')))
+ *pos= 0;
-*/
-
-static void create_mysql_upgrade_info_file(void)
-{
- FILE *out;
- char upgrade_info_file[FN_REFLEN]= {0};
+ if (faulty_server_versions(upgrade_from_version))
+ {
+ if (opt_verbose)
+ verbose("Upgrading from version %s requires mysql_upgrade to be run!",
+ upgrade_from_version);
+ return 2;
+ }
- if (get_upgrade_info_file_name(upgrade_info_file))
- return; /* Could not get filename => skip */
+ s= strchr(version, '.');
+ s= strchr(s + 1, '.');
- if (!(out= my_fopen(upgrade_info_file, O_TRUNC | O_WRONLY, MYF(0))))
+ if (strncmp(upgrade_from_version, version,
+ (size_t)(s - version + 1)))
{
- fprintf(stderr,
- "Could not create the upgrade info file '%s' in "
- "the MariaDB Servers datadir, errno: %d\n",
- upgrade_info_file, errno);
- return;
+ if (calc_server_version(upgrade_from_version) <= MYSQL_VERSION_ID)
+ {
+ verbose("Major version upgrade detected from %s to %s. Check required!",
+ upgrade_from_version, version);
+ return 3;
+ }
+ die("Version mismatch (%s -> %s): Trying to downgrade from a higher to "
+ "lower version is not supported!",
+ upgrade_from_version, version);
}
+ if (!silent)
+ {
+ verbose("This installation of MariaDB is already upgraded to %s.\n"
+ "There is no need to run mysql_upgrade again for %s.",
+ upgrade_from_version, version);
+ if (!opt_check_upgrade)
+ verbose("You can use --force if you still want to run mysql_upgrade",
+ upgrade_from_version, version);
+ }
+ return 0;
+}
+
+static void finish_mysql_upgrade_info_file(void)
+{
+ if (info_file < 0)
+ return;
/* Write new version to file */
- my_fwrite(out, (uchar*) MYSQL_SERVER_VERSION,
- sizeof(MYSQL_SERVER_VERSION), MY_WME);
- my_fclose(out, MYF(MY_WME));
+ (void) my_seek(info_file, 0, SEEK_CUR, MYF(0));
+ (void) my_chsize(info_file, 0, 0, MYF(0));
+ (void) my_seek(info_file, 0, 0, MYF(0));
+ (void) my_write(info_file, (uchar*) MYSQL_SERVER_VERSION,
+ sizeof(MYSQL_SERVER_VERSION)-1, MYF(MY_WME));
+ (void) my_write(info_file, (uchar*) "\n", 1, MYF(MY_WME));
+ (void) my_lock(info_file, F_UNLCK, 0, 1, MYF(0));
/*
- Check if the upgrad_info_file was properly created/updated
+ Check if the upgrade_info_file was properly created/updated
It's not a fatal error -> just print a message if it fails
*/
- if (!upgrade_already_done(MY_WME))
+ if (upgrade_already_done(1))
fprintf(stderr,
- "Upgrade file '%s' was not properly created. "
- "Got error errno while checking file content: %d\n",
+ "Could not write to the upgrade info file '%s' in "
+ "the MariaDB Servers datadir, errno: %d\n",
upgrade_info_file, errno);
+
+ my_close(info_file, MYF(MY_WME));
+ info_file= -1;
return;
}
@@ -1151,7 +1294,7 @@ static int check_slave_repositories(void)
}
/*
- Update all system tables in MySQL Server to current
+ Update all system tables in MariaDB Server to current
version using "mysql" to execute all the SQL commands
compiled into the mysql_fix_privilege_tables array
*/
@@ -1220,24 +1363,6 @@ static int run_sql_fix_privilege_tables(void)
}
-static void print_error(const char *error_msg, DYNAMIC_STRING *output)
-{
- fprintf(stderr, "%s\n", error_msg);
- fprintf(stderr, "%s", output->str);
-}
-
-
-/* Convert the specified version string into the numeric format. */
-static ulong STDCALL calc_server_version(char *some_version)
-{
- uint major, minor, version;
- char *point= some_version, *end_point;
- major= (uint) strtoul(point, &end_point, 10); point=end_point+1;
- minor= (uint) strtoul(point, &end_point, 10); point=end_point+1;
- version= (uint) strtoul(point, &end_point, 10);
- return (ulong) major * 10000L + (ulong)(minor * 100 + version);
-}
-
/**
Check if the server version matches with the server version mysql_upgrade
was compiled with.
@@ -1273,8 +1398,7 @@ static int check_version_match(void)
"check.\n", version_str, MYSQL_SERVER_VERSION);
return 1;
}
- else
- return 0;
+ return 0;
}
@@ -1283,6 +1407,8 @@ int main(int argc, char **argv)
char self_name[FN_REFLEN + 1];
MY_INIT(argv[0]);
+ DBUG_PROCESS(argv[0]);
+
load_defaults_or_exit("my", load_default_groups, &argc, &argv);
defaults_argv= argv; /* Must be freed by 'free_defaults' */
@@ -1324,12 +1450,17 @@ int main(int argc, char **argv)
die(NULL);
my_write(fd, USTRING_WITH_LEN( "[client]\n"), MYF(MY_FAE));
my_write(fd, (uchar*)ds_args.str, ds_args.length, MYF(MY_FAE));
- my_close(fd, MYF(0));
+ my_close(fd, MYF(MY_WME));
}
/* Find mysql */
find_tool(mysql_path, IF_WIN("mysql.exe", "mysql"), self_name);
+ open_mysql_upgrade_file();
+
+ if (opt_check_upgrade)
+ exit(upgrade_already_done(0) == 0);
+
/* Find mysqlcheck */
find_tool(mysqlcheck_path, IF_WIN("mysqlcheck.exe", "mysqlcheck"), self_name);
@@ -1338,15 +1469,10 @@ int main(int argc, char **argv)
/*
Read the mysql_upgrade_info file to check if mysql_upgrade
- already has been run for this installation of MySQL
+ already has been run for this installation of MariaDB
*/
- if (!opt_force && upgrade_already_done(0))
- {
- printf("This installation of MariaDB is already upgraded to %s, "
- "use --force if you still need to run mysql_upgrade\n",
- MYSQL_SERVER_VERSION);
- goto end;
- }
+ if (!opt_force && !upgrade_already_done(0))
+ goto end; /* Upgrade already done */
if (opt_version_check && check_version_match())
die("Upgrade failed");
@@ -1373,8 +1499,8 @@ int main(int argc, char **argv)
verbose("OK");
- /* Create a file indicating upgrade has been performed */
- create_mysql_upgrade_info_file();
+ /* Finish writing indicating upgrade has been performed */
+ finish_mysql_upgrade_info_file();
DBUG_ASSERT(phase == phases_total);