summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore2
-rwxr-xr-xCMakeLists.txt1
-rw-r--r--Makefile.am4
-rw-r--r--client/mysql_upgrade.c1188
-rw-r--r--include/my_global.h8
-rw-r--r--mysql-test/r/bdb_notembedded.result35
-rw-r--r--mysql-test/r/mysql_upgrade.result87
-rw-r--r--mysql-test/t/bdb_notembedded.test38
-rw-r--r--mysql-test/t/mysql_upgrade.test48
-rwxr-xr-xscripts/CMakeLists.txt28
-rw-r--r--scripts/Makefile.am14
-rw-r--r--scripts/comp_sql.c119
-rw-r--r--sql/mysql_priv.h2
13 files changed, 963 insertions, 611 deletions
diff --git a/.bzrignore b/.bzrignore
index 8e65ec6d6b8..8f8fa4031a9 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1337,3 +1337,5 @@ win/vs71cache.txt
win/vs8cache.txt
zlib/*.ds?
zlib/*.vcproj
+scripts/comp_sql
+scripts/mysql_fix_privilege_tables_sql.c
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b458864c410..6615599cd4a 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -128,6 +128,7 @@ ADD_SUBDIRECTORY(dbug)
ADD_SUBDIRECTORY(strings)
ADD_SUBDIRECTORY(regex)
ADD_SUBDIRECTORY(mysys)
+ADD_SUBDIRECTORY(scripts)
ADD_SUBDIRECTORY(extra/yassl)
ADD_SUBDIRECTORY(extra/yassl/taocrypt)
ADD_SUBDIRECTORY(extra)
diff --git a/Makefile.am b/Makefile.am
index 04d50ccfbaf..92b8428e40e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -21,9 +21,9 @@ AUTOMAKE_OPTIONS = foreign
EXTRA_DIST = INSTALL-SOURCE INSTALL-WIN-SOURCE \
README COPYING EXCEPTIONS-CLIENT CMakeLists.txt
SUBDIRS = . include @docs_dirs@ @zlib_dir@ @yassl_dir@ \
- @readline_topdir@ sql-common \
+ @readline_topdir@ sql-common scripts \
@thread_dirs@ pstack \
- @sql_union_dirs@ scripts @man_dirs@ tests \
+ @sql_union_dirs@ @man_dirs@ tests \
netware @libmysqld_dirs@ \
@bench_dirs@ support-files @tools_dirs@
diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c
index 0c921c8e0d8..371857816b6 100644
--- a/client/mysql_upgrade.c
+++ b/client/mysql_upgrade.c
@@ -14,57 +14,42 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "client_priv.h"
-#include <my_dir.h>
-#include <my_list.h>
#include <sslopt-vars.h>
+#include "../scripts/mysql_fix_privilege_tables_sql.c"
-#define UPGRADE_DEFAULTS_NAME "mysql_upgrade_defaults"
-#define MYSQL_UPGRADE_INFO_NAME "mysql_upgrade_info"
-#define MYSQL_FIX_PRIV_TABLES_NAME "mysql_fix_privilege_tables.sql"
+static char mysql_path[FN_REFLEN];
+static char mysqlcheck_path[FN_REFLEN];
+static char defaults_file_option[32+FN_REFLEN];
-#define MY_PARENT (1 << 0)
-#define MY_ISDIR (1 << 1)
-#define MY_SEARCH_SELF (1 << 2)
+static my_bool opt_force, opt_verbose;
+static char *opt_user= (char*)"root";
+
+static DYNAMIC_STRING ds_options;
+
+static char *opt_password= 0;
+static my_bool tty_password= 0;
-#ifdef __WIN__
-const char *mysqlcheck_name= "mysqlcheck.exe";
-const char *mysql_name= "mysql.exe";
-const char *mysqld_name= "mysqld.exe";
-#define EXTRA_CLIENT_PATHS "client/release", "client/debug"
-#else
-const char *mysqlcheck_name= "mysqlcheck";
-const char *mysql_name= "mysql";
-const char *mysqld_name= "mysqld";
-#define EXTRA_CLIENT_PATHS "client"
-#endif /*__WIN__*/
-
-extern TYPELIB sql_protocol_typelib;
-
-static my_bool opt_force= 0, opt_verbose= 0, opt_compress= 0;
-static char *user= (char*) "root", *basedir= 0, *datadir= 0, *opt_password= 0;
-static char *current_host= 0;
-static char *opt_default_charset= 0, *opt_charsets_dir= 0;
-#ifdef HAVE_SMEM
-static char *shared_memory_base_name= 0;
-#endif
-static char *opt_protocol= 0;
-static my_string opt_mysql_port= 0, opt_mysql_unix_port= 0;
#ifndef DBUG_OFF
static char *default_dbug_option= (char*) "d:t:O,/tmp/mysql_upgrade.trace";
#endif
-static my_bool info_flag= 0, tty_password= 0;
static char **defaults_argv;
+static File defaults_fd= -1;
+
+static my_bool not_used; /* Can't use GET_BOOL without a value pointer */
+
+#include <help_start.h>
+
static struct my_option my_long_options[]=
{
{"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
- {"basedir", 'b', "Specifies the directory where MySQL is installed",
- (gptr*) &basedir,
- (gptr*) &basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"datadir", 'd', "Specifies the data directory", (gptr*) &datadir,
- (gptr*) &datadir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"basedir", 'b', "Not used by mysql_upgrade. Only for backward compatibilty",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"datadir", 'd',
+ "Not used by mysql_upgrade. Only for backward compatibilty",
+ 0, 0, 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},
@@ -72,638 +57,759 @@ static struct my_option my_long_options[]=
{"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},
{"default-character-set", OPT_DEFAULT_CHARSET,
- "Set the default character set.", (gptr*) &opt_default_charset,
- (gptr*) &opt_default_charset, 0, GET_STR, REQUIRED_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 MySQL.",
- (gptr*) &opt_force, (gptr*) &opt_force, 0, GET_BOOL, NO_ARG, 0, 0,
- 0, 0, 0, 0},
+ "Set the default character set.", 0,
+ 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"character-sets-dir", OPT_CHARSETS_DIR,
- "Directory where character sets are.", (gptr*) &opt_charsets_dir,
- (gptr*) &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ "Directory where character sets are.", 0,
+ 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"compress", OPT_COMPRESS, "Use compression in server/client protocol.",
- (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
- 0, 0, 0},
- {"host",'h', "Connect to host.", (gptr*) &current_host,
- (gptr*) &current_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ (gptr*)&not_used, (gptr*)&not_used, 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 MySQL.",
+ (gptr*)&opt_force, (gptr*)&opt_force, 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},
{"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},
+ " it's solicited on the tty.", (gptr*) &opt_password,(gptr*) &opt_password,
+ 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#ifdef __WIN__
- {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0,
+ {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
- {"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},
+ {"port", 'P', "Port number to use for connection.", 0,
+ 0, 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},
#ifdef HAVE_SMEM
{"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
- "Base name of shared memory.", (gptr*) &shared_memory_base_name,
- (gptr*) &shared_memory_base_name, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ "Base name of shared memory.", 0,
+ 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"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,
- (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"user", 'u', "User for login if not current user.", (gptr*) &opt_user,
+ (gptr*) &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#include <sslopt-longopts.h>
- {"verbose", 'v', "Display more output about the process",
- (gptr*) &opt_verbose, (gptr*) &opt_verbose, 0,
- GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"verbose", 'v', "Display more output about the process",
+ (gptr*) &opt_verbose, (gptr*) &opt_verbose, 0,
+ GET_BOOL, NO_ARG, 1, 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[]=
+#include <help_end.h>
+
+
+static void free_used_memory(void)
{
- "mysql_upgrade", 0
-};
+ /* Close the defaults file */
+ if (defaults_fd != -1)
+ my_close(defaults_fd, MYF(0));
-#include <help_end.h>
+ /* Free memory allocated by 'load_defaults' */
+ free_defaults(defaults_argv);
+
+ dynstr_free(&ds_options);
+}
-static LIST *extra_defaults= NULL;
-typedef struct _extra_default
+static void die(const char *fmt, ...)
{
- int id;
- const char *name;
- int n_len;
- const char *value;
- int v_len;
-} extra_default_t;
-
-static inline
-void set_extra_default(int id, const struct my_option *opt)
+ va_list args;
+ DBUG_ENTER("die");
+
+ /* Print the error message */
+ va_start(args, fmt);
+ if (fmt)
+ {
+ fprintf(stderr, "FATAL ERROR: ");
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+ va_end(args);
+
+ free_used_memory();
+ my_end(MY_CHECK_ERROR);
+ exit(1);
+}
+
+
+static void verbose(const char *fmt, ...)
{
- switch (id) {
- case 'b': case 'd': /* these are ours */
- case 'f': /* --force is ours */
- case 'u': /* --user passed on cmdline */
- case 'T': /* --debug-info is not accepted by mysqlcheck */
- case 'p': /* --password may change yet */
- /* so, do nothing */
- break;
- default:
- {
- LIST *l;
- extra_default_t *d;
-
- /*
- Remove any earlier duplicates: they can
- refer to invalid memory addresses (stale pointers)
- */
- l= extra_defaults;
- while (l)
- {
- LIST *n= l->next;
-
- d= l->data;
- if (d->id == id)
- {
- extra_defaults= list_delete(extra_defaults, l);
- my_free((gptr)l, MYF(0));
- my_free((gptr)d, MYF(0));
- }
- l= n;
- }
+ va_list args;
+
+ if (!opt_verbose)
+ return;
+
+ /* Print the verbose message */
+ va_start(args, fmt);
+ if (fmt)
+ {
+ vfprintf(stdout, fmt, args);
+ fprintf(stdout, "\n");
+ fflush(stdout);
+ }
+ va_end(args);
+}
+
+
+/*
+ Add one option - passed to mysql_upgrade on command line
+ or by defaults file(my.cnf) - to a dynamic string that later
+ can be written to a temporary file. In this way we pass the
+ same arguments on to mysql and mysql_check
+*/
+
+static void add_one_option(DYNAMIC_STRING* ds,
+ const struct my_option *opt,
+ const char* argument)
+{
+ dynstr_append(ds, opt->name);
- d= (extra_default_t *)my_malloc(sizeof(extra_default_t),
- MYF(MY_FAE | MY_ZEROFILL));
- d->id= id;
- d->name= opt->name;
- d->n_len= strlen(opt->name);
- if (opt->arg_type != NO_ARG && opt->value)
- switch (opt->var_type & GET_TYPE_MASK) {
- case GET_BOOL:
- if (*((int *)opt->value))
- {
- d->value= "true";
- d->v_len= 4;
- }
- break;
- case GET_STR:
- case GET_STR_ALLOC:
- d->value= *opt->value;
- d->v_len= strlen(d->value);
- break;
- default:
- my_printf_error(0, "Error: internal error at %s:%d", MYF(0),
- __FILE__, __LINE__);
- exit(1);
- }
- list_push(extra_defaults, d);
+ if (opt->arg_type != NO_ARG)
+ {
+ dynstr_append(ds, "=");
+ switch (opt->var_type & GET_TYPE_MASK) {
+ case GET_STR:
+ case GET_STR_ALLOC:
+ dynstr_append(ds, argument);
+ break;
+ default:
+ die("internal error at %s: %d",__FILE__, __LINE__);
}
}
+ dynstr_append(ds, "\n");
}
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,
char *argument)
{
+ my_bool add_option= TRUE;
+
switch (optid) {
+
case '?':
- puts
- ("MySQL utility to upgrade database to the current server version");
- puts("");
+ printf("MySQL utility for upgrading database to MySQL version %s\n",
+ MYSQL_SERVER_VERSION);
my_print_help(my_long_options);
exit(0);
+ break;
+
case '#':
DBUG_PUSH(argument ? argument : default_dbug_option);
+ add_option= FALSE;
break;
+
case 'p':
tty_password= 1;
+ add_option= FALSE;
if (argument)
{
- char *start= argument;
- my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
- opt_password= my_strdup(argument, MYF(MY_FAE));
+ /* Add password to ds_options before overwriting the arg with x's */
+ add_one_option(&ds_options, opt, argument);
while (*argument)
*argument++= 'x'; /* Destroy argument */
- if (*start)
- start[1]= 0; /* Cut length of argument */
tty_password= 0;
}
break;
-#ifdef __WIN__
- case 'W':
- my_free(opt_protocol, MYF(MY_ALLOW_ZERO_PTR));
- opt_protocol= my_strdup("pipe", MYF(MY_FAE));
+
+ case 'b': /* --basedir */
+ case 'v': /* --verbose */
+ case 'd': /* --datadir */
+ case 'f': /* --force */
+ add_option= FALSE;
break;
-#endif
- case OPT_MYSQL_PROTOCOL:
- if (find_type(argument, &sql_protocol_typelib, 0) > 0)
+ }
+
+ if (add_option)
+ {
+ /*
+ This is an option that is accpted by mysql_upgrade just so
+ it can be passed on to "mysql" and "mysqlcheck"
+ Save it in the ds_options string
+ */
+ add_one_option(&ds_options, opt, argument);
+ }
+ return 0;
+}
+
+
+/*
+ Write the options that should be passed on to
+ mysql and mysqlcheck to a temporary file
+*/
+
+static void create_defaults_file(void)
+{
+ static char defaults_file_path[FN_REFLEN];
+ DBUG_ENTER("create_defaults_file");
+
+ if ((defaults_fd= create_temp_file(defaults_file_path, NULL,
+ "cnf", O_CREAT | O_SHARE,
+ MYF(MY_WME))) < 0)
+ die("Failed to create temporary file for defaults");
+
+ DBUG_PRINT("info", ("Writing options: %s", ds_options.str));
+ if (my_write(defaults_fd, ds_options.str, ds_options.length,
+ MYF(MY_FNABP | MY_WME)))
+ die("Failed to write to '%s'", defaults_file_path);
+
+ /*
+ Dont close the temporary file yet, it will be used
+ by mysql and mysqlcheck
+ */
+
+ /*
+ Create the option that should be added to
+ tools in order to use this file
+ */
+ snprintf(defaults_file_option, sizeof(defaults_file_option),
+ "--defaults-file=%s", defaults_file_path);
+ DBUG_PRINT("info", ("defaults_file_option: %s", defaults_file_option));
+
+ DBUG_VOID_RETURN;
+}
+
+
+static int run_command(char* cmd,
+ DYNAMIC_STRING *ds_res)
+{
+ char buf[512]= {0};
+ FILE *res_file;
+
+ if (!(res_file= popen(cmd, "r")))
+ die("popen(\"%s\", \"r\") failed", cmd);
+
+ while (fgets(buf, sizeof(buf), res_file))
+ {
+ DBUG_PRINT("info", ("buf: %s", buf));
+ if(ds_res)
{
- my_free(opt_protocol, MYF(MY_ALLOW_ZERO_PTR));
- opt_protocol= my_strdup(argument, MYF(MY_FAE));
+ /* Save the output of this command in the supplied string */
+ dynstr_append(ds_res, buf);
}
- else
+ else
{
- fprintf(stderr, "Unknown option to protocol: %s\n", argument);
- exit(1);
+ /* Print it directly on screen */
+ fprintf(stdout, "%s", buf);
}
- break;
-#include <sslopt-case.h>
- default:;
}
- set_extra_default(opt->id, opt);
- return 0;
+
+ return WEXITSTATUS(pclose(res_file));
}
-static int create_check_file(const char *path)
+static int run_tool(char *tool_path, DYNAMIC_STRING *ds_res, ...)
{
int ret;
- File fd;
-
- fd= my_open(path, O_CREAT | O_WRONLY, MYF(MY_FAE | MY_WME));
- if (fd < 0) {
- ret= 1;
- goto error;
+ const char* arg;
+ va_list args;
+ DYNAMIC_STRING ds_cmdline;
+
+ DBUG_ENTER("run_tool");
+ DBUG_PRINT("enter", ("tool_path: %s", tool_path));
+
+ if (init_dynamic_string(&ds_cmdline, IF_WIN("\"", ""), FN_REFLEN, FN_REFLEN))
+ die("Out of memory");
+
+ dynstr_append_os_quoted(&ds_cmdline, tool_path, NullS);
+ dynstr_append(&ds_cmdline, " ");
+
+ va_start(args, ds_res);
+
+ while ((arg= va_arg(args, char *)))
+ {
+ /* Options should be os quoted */
+ if (strncmp(arg, "--", 2) == 0)
+ dynstr_append_os_quoted(&ds_cmdline, arg, NullS);
+ else
+ dynstr_append(&ds_cmdline, arg);
+ dynstr_append(&ds_cmdline, " ");
}
- ret= my_write(fd, MYSQL_SERVER_VERSION,
- sizeof(MYSQL_SERVER_VERSION) - 1,
- MYF(MY_WME | MY_FNABP));
- ret|= my_close(fd, MYF(MY_FAE | MY_WME));
-error:
- return ret;
+
+ va_end(args);
+
+ DBUG_PRINT("info", ("Running: %s", ds_cmdline.str));
+ ret= run_command(ds_cmdline.str, ds_res);
+ DBUG_PRINT("exit", ("ret: %d", ret));
+ dynstr_free(&ds_cmdline);
+ DBUG_RETURN(ret);
}
-static int create_defaults_file(const char *path, const char *forced_path)
+/*
+ Try to get the full path to this exceutable
+
+ Return 0 if path found
+
+*/
+
+static my_bool get_full_path_to_executable(char* path)
{
- int ret;
- uint cnt;
- File forced_file, defaults_file;
-
- DYNAMIC_STRING buf;
- extra_default_t *d;
+ my_bool ret;
+ DBUG_ENTER("get_full_path_to_executable");
+#ifdef WIN
+ ret= GetModuleFileName(NULL, path, FN_REFLEN) != 0;
+#else
+ /* my_readlink returns 0 if a symlink was read */
+ ret= my_readlink(path, "/proc/self/exe", MYF(0)) != 0;
+ /* Might also want to try with /proc/$$/exe if the above fails */
+#endif
+ DBUG_PRINT("exit", ("path: %s", path));
+ DBUG_RETURN(ret);
+}
- DBUG_ENTER("create_defaults_file");
- DBUG_PRINT("enter", ("path: %s, forced_path: %s", path, forced_path));
-
- /* Delete any previous defaults file generated by mysql_upgrade */
- my_delete(path, MYF(0));
-
- defaults_file= my_open(path, O_BINARY | O_CREAT | O_WRONLY | O_EXCL,
- MYF(MY_FAE | MY_WME));
- if (defaults_file < 0)
- {
- ret= 1;
- goto out;
- }
- if (init_dynamic_string(&buf, NULL, my_getpagesize(), FN_REFLEN))
- {
- ret= 1;
- goto error;
- }
+/*
+ Look for the tool in the same directory as mysql_upgrade.
- /* Copy forced_path file into the defaults_file being generated */
- if (forced_path)
- {
- forced_file= my_open(forced_path, O_RDONLY, MYF(MY_FAE | MY_WME));
- if (forced_file < 0)
- {
- ret= 1;
- goto error;
- }
- DBUG_PRINT("info", ("Copying from %s to %s", forced_path, path));
- do
- {
- cnt= my_read(forced_file, buf.str, buf.max_length, MYF(MY_WME));
- if ((cnt == MY_FILE_ERROR)
- || my_write(defaults_file, buf.str, cnt, MYF(MY_FNABP | MY_WME)))
- {
- ret= 1;
- my_close(forced_file, MYF(0));
- goto error;
- }
- DBUG_PRINT("info", ("%s", buf.str));
- } while (cnt == buf.max_length);
- my_close(forced_file, MYF(0));
- }
+ When running in a not yet installed build the the program
+ will exist but it need to be invoked via it's libtool wrapper.
+ Check if the found tool can executed and if not look in the
+ directory one step higher up where the libtool wrapper normally
+ is found
+*/
+
+static void find_tool(char *tool_path, const char *tool_name)
+{
+ char path[FN_REFLEN];
+ DYNAMIC_STRING ds_tmp;
+ DBUG_ENTER("find_tool");
+ DBUG_PRINT("enter", ("progname: %s", my_progname));
+
+ if (init_dynamic_string(&ds_tmp, "", 32, 32))
+ die("Out of memory");
- /* Write all extra_default options into the [client] section */
- dynstr_set(&buf, "\n[client]");
- if (opt_password)
+ /* Initialize path with the full path to this program */
+ if (get_full_path_to_executable(path))
{
- if (dynstr_append(&buf, "\npassword=")
- || dynstr_append(&buf, opt_password))
+ /*
+ Easy way to get full executable path failed, try
+ other methods
+ */
+ if (my_progname[0] == FN_LIBCHAR)
{
- ret = 1;
- goto error;
+ /* 1. my_progname contains full path */
+ strmake(path, my_progname, FN_REFLEN);
}
- }
- DBUG_PRINT("info", ("Writing extra_defaults to file"));
- while (extra_defaults)
- {
- int len;
-
- d= extra_defaults->data;
- len= d->n_len + d->v_len + 1;
- if (buf.length + len >= buf.max_length) /* to avoid realloc() */
+ else if (my_progname[0] == '.')
{
-
- if (my_write(defaults_file, buf.str, buf.length, MYF(MY_FNABP | MY_WME)))
- {
- ret= 1;
- goto error;
- }
- dynstr_set(&buf, NULL);
+ /* 2. my_progname contains relative path, prepend wd */
+ char buf[FN_REFLEN];
+ my_getwd(buf, FN_REFLEN, MYF(0));
+ snprintf(path, FN_REFLEN, "%s%s", buf, my_progname);
}
- if (dynstr_append_mem(&buf, "\n", 1) ||
- dynstr_append_mem(&buf, d->name, d->n_len) ||
- (d->v_len && (dynstr_append_mem(&buf, "=", 1) ||
- dynstr_append_mem(&buf, d->value, d->v_len))))
+ else
{
- ret= 1;
- goto error;
+ /* 3. Just go for it and hope tool is in path */
+ path[0]= 0;
}
- DBUG_PRINT("info", ("%s", buf.str));
- my_free((gptr)d, MYF(0));
- list_pop(extra_defaults); /* pop off the head */
}
- if (my_write(defaults_file, buf.str, buf.length, MYF(MY_FNABP | MY_WME)))
+ do
{
- ret= 1;
- goto error;
+ DBUG_PRINT("enter", ("path: %s", path));
+
+ /* Chop off last char(since it might be a /) */
+ size_t pos= max((strlen(path)-1), 0);
+ path[pos]= 0;
+
+ /* Chop off last dir part */
+ dirname_part(path, path);
+
+ /* Format name of the tool to search for */
+ fn_format(tool_path, tool_name,
+ path, "", MYF(MY_REPLACE_DIR));
+
+ verbose("Looking for '%s' in: %s", tool_name, tool_path);
+
+ /* Make sure the tool exists */
+ if (my_access(tool_path, F_OK) != 0)
+ die("Can't find '%s'", tool_path);
+
+ /*
+ Make sure it can be executed, otherwise try again
+ in higher level directory
+ */
}
- /* everything's all right */
- ret= 0;
-error:
- dynstr_free(&buf);
-
- if (defaults_file >= 0)
- ret|= my_close(defaults_file, MYF(MY_WME));
-
- if (ret)
- my_delete(path, MYF(0));
-
-out:
+ while(run_tool(tool_path,
+ &ds_tmp, /* Get output from command, discard*/
+ "--help",
+ "2>&1",
+ IF_WIN("> NUL", "> /dev/null"),
+ NULL));
+
+ dynstr_free(&ds_tmp);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Run query using "mysql"
+*/
+
+static int run_query(const char *query, DYNAMIC_STRING *ds_res,
+ my_bool force)
+{
+ int ret;
+ File fd;
+ char query_file_path[FN_REFLEN];
+ DBUG_ENTER("run_query");
+ DBUG_PRINT("enter", ("query: %s", query));
+ if ((fd= create_temp_file(query_file_path, NULL,
+ "sql", O_CREAT | O_SHARE,
+ MYF(MY_WME))) < 0)
+ die("Failed to create temporary file for defaults");
+
+ if (my_write(fd, query, strlen(query),
+ MYF(MY_FNABP | MY_WME)))
+ die("Failed to write to '%s'", query_file_path);
+
+ ret= run_tool(mysql_path,
+ ds_res,
+ defaults_file_option,
+ "--database=mysql",
+ "--batch", /* Turns off pager etc. */
+ force ? "--force": "--skip-force",
+ ds_res ? "--silent": "",
+ "<",
+ query_file_path,
+ "2>&1",
+ NULL);
+
+ my_close(fd, MYF(0));
+
DBUG_RETURN(ret);
}
-/* Compare filenames */
-static int comp_names(struct fileinfo *a, struct fileinfo *b)
+/*
+ Extract the value returned from result of "show variable like ..."
+*/
+
+static int extract_variable_from_show(DYNAMIC_STRING* ds, char* value)
{
- return (strcmp(a->name,b->name));
+ char *value_start, *value_end;
+ /*
+ The query returns "datadir\t<datadir>\n", skip past
+ the tab
+ */
+ if ((value_start= strchr(ds->str, '\t')) == NULL)
+ return 1; /* Unexpected result */
+ value_start++;
+
+ /* Don't copy the ending newline */
+ if (value_start && (value_end= strchr(value_start, '\n')) == NULL)
+ return 1; /* Unexpected result */
+
+ strncpy(value, value_start, min(FN_REFLEN, value_end-value_start));
+ return 0;
}
-static int find_file(const char *name, const char *root,
- uint flags, char *result, size_t len, ...)
+static int get_upgrade_info_file_name(char* name)
{
- int ret= 1;
- va_list va;
- const char *subdir;
- char *cp;
- FILEINFO key;
-
- /* Init key with name of the file to look for */
- key.name= (char*)name;
-
- DBUG_ASSERT(root != NULL);
-
- cp= strmake(result, root, len);
- if (cp[-1] != FN_LIBCHAR)
- *cp++= FN_LIBCHAR;
-
- va_start(va, len);
- subdir= (!(flags & MY_SEARCH_SELF)) ? va_arg(va, char *) : "";
- while (subdir)
+ DYNAMIC_STRING ds_datadir;
+ DBUG_ENTER("get_upgrade_info_file_name");
+
+ if (init_dynamic_string(&ds_datadir, NULL, 32, 32))
+ die("Out of memory");
+
+ if (run_query("show variables like 'datadir'",
+ &ds_datadir, FALSE) ||
+ extract_variable_from_show(&ds_datadir, name))
{
- MY_DIR *dir;
- FILEINFO *match;
- char *cp1;
-
- cp1= strnmov(cp, subdir, len - (cp - result) - 1);
-
- dir= my_dir(result, (flags & MY_ISDIR) ? MY_WANT_STAT : MYF(0));
- if (dir)
- {
- match= bsearch(&key, dir->dir_entry, dir->number_off_files,
- sizeof(FILEINFO), (qsort_cmp)comp_names);
- if (match)
- {
- ret= (flags & MY_ISDIR) ? !MY_S_ISDIR(match->mystat->st_mode) : 0;
- if (!ret)
- {
- if (cp1[-1] != FN_LIBCHAR)
- *cp1++= FN_LIBCHAR;
-
- if (!(flags & MY_PARENT))
- strnmov(cp1, name, len - (cp1 - result));
- else
- *cp1= '\0';
-
- my_dirend(dir);
- break;
- }
- }
- my_dirend(dir);
- }
- subdir= va_arg(va, char *);
+ dynstr_free(&ds_datadir);
+ DBUG_RETURN(1); /* Query failed */
}
- va_end(va);
- return ret;
+
+ dynstr_free(&ds_datadir);
+
+ fn_format(name, "mysql_upgrade_info", name, "", MYF(0));
+ DBUG_PRINT("exit", ("name: %s", name));
+ DBUG_RETURN(0);
}
-int main(int argc, char **argv)
+/*
+ Read the content of mysql_upgrade_info file and
+ compare the version number form file against
+ version number wich mysql_upgrade was compiled for
+
+ NOTE
+ This is an optimization to avoid running mysql_upgrade
+ when it's already been performed for the particular
+ version of MySQL.
+
+ In case the MySQL server can't return the upgrade info
+ file it's always better to report that the upgrade hasn't
+ been performed.
+
+*/
+
+static int upgrade_already_done(void)
{
- int ret;
-
- char *forced_defaults_file;
- char *forced_extra_defaults;
- char *local_defaults_group_suffix;
- int no_defaults;
- char path[FN_REFLEN], upgrade_defaults_path[FN_REFLEN];
+ FILE *in;
+ char upgrade_info_file[FN_REFLEN]= {0};
+ char buf[sizeof(MYSQL_SERVER_VERSION)+1];
- DYNAMIC_STRING cmdline;
+ if (get_upgrade_info_file_name(upgrade_info_file))
+ return 0; /* Could not get filename => not sure */
- MY_INIT(argv[0]);
-#ifdef __NETWARE__
- setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
-#endif
+ if (!(in= my_fopen(upgrade_info_file, O_RDONLY, MYF(0))))
+ return 0; /* Could not open file => not sure */
- /* Check if we are forced to use specific defaults */
- no_defaults= 0;
- if (argc >= 2 && !strcmp(argv[1],"--no-defaults"))
- no_defaults= 1;
+ /*
+ Read from file, don't care if it fails since it
+ will be detected by the strncmp
+ */
+ bzero(buf, sizeof(buf));
+ fgets(buf, sizeof(buf), in);
- get_defaults_options(argc, argv,
- &forced_defaults_file, &forced_extra_defaults,
- &local_defaults_group_suffix);
-
- load_defaults("my", load_default_groups, &argc, &argv);
- defaults_argv= argv;
+ my_fclose(in, MYF(0));
- /*
- Must init_dynamic_string before handle_options because string is freed
- at error label.
- */
- if (init_dynamic_string(&cmdline, NULL, 2 * FN_REFLEN + 128, FN_REFLEN) ||
- handle_options(&argc, &argv, my_long_options, get_one_option))
- {
- ret= 1;
- goto error;
- }
- if (tty_password)
- opt_password= get_tty_password(NullS);
+ return (strncmp(buf, MYSQL_SERVER_VERSION,
+ sizeof(MYSQL_SERVER_VERSION)-1)==0);
+}
- if (!basedir)
- {
- my_getwd(path, sizeof(path), MYF(0));
- basedir= my_strdup(path, MYF(0));
- if (find_file("errmsg.sys", basedir, MYF(0), path, sizeof(path),
- "share/mysql/english", NullS)
- || find_file(mysqld_name, basedir, MYF(0), path, sizeof(path),
- "bin", "libexec", NullS))
- {
- my_free((gptr)basedir, MYF(0));
- basedir= (char *)DEFAULT_MYSQL_HOME;
- }
- }
- if (!datadir)
- {
- if (!find_file("mysql", basedir, MYF(MY_ISDIR|MY_PARENT),
- path, sizeof(path),
- "data", "var", NullS))
- datadir= my_strdup(path, MYF(0));
- else
- datadir= (char *)DATADIR;
- }
- if (find_file("user.frm", datadir, MYF(0), path, sizeof(path),
- "mysql", NullS))
+/*
+ Write mysql_upgrade_info file in servers data dir indicating that
+ upgrade has been done for this version
+
+ 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.
+
+*/
+
+static void create_mysql_upgrade_info_file(void)
+{
+ FILE *out;
+ char upgrade_info_file[FN_REFLEN]= {0};
+
+ if (get_upgrade_info_file_name(upgrade_info_file))
+ return; /* Could not get filename => skip */
+
+ if (!(out= my_fopen(upgrade_info_file, O_TRUNC | O_WRONLY, MYF(0))))
{
- ret= 1;
fprintf(stderr,
- "Can't find data directory. Please restart with"
- " --datadir=path-to-writable-data-dir");
- goto error;
+ "Could not create the upgrade info file '%s' in "
+ "the MySQL Servers datadir, errno: %d\n",
+ upgrade_info_file, errno);
+ return;
}
- /*
- Create the modified defaults file to be used by mysqlcheck
- and mysql command line client
- */
- fn_format(upgrade_defaults_path, UPGRADE_DEFAULTS_NAME, datadir, "", MYF(0));
- create_defaults_file(upgrade_defaults_path, forced_extra_defaults);
+ /* Write new version to file, just print a message if it fails */
+ if (!fputs(MYSQL_SERVER_VERSION, out))
+ fprintf(stderr,
+ "Could not write to the upgrade info file '%s' in "
+ "the MySQL Servers datadir, errno: %d\n",
+ upgrade_info_file, errno);
+
+ my_fclose(out, MYF(0));
+}
- /*
- Read the mysql_upgrade_info file to check if mysql_upgrade
- already has been done
- Maybe this could be done a little earlier?
- */
- if (!find_file(MYSQL_UPGRADE_INFO_NAME, datadir, MY_SEARCH_SELF,
- path, sizeof(path), NULL, NullS)
- && !opt_force)
- {
- char buf[sizeof(MYSQL_SERVER_VERSION)];
- int fd, cnt;
-
- fd= my_open(path, O_RDONLY, MYF(0));
- cnt= my_read(fd, buf, sizeof(buf) - 1, MYF(0));
- my_close(fd, MYF(0));
- buf[cnt]= 0;
- if (!strcmp(buf, MYSQL_SERVER_VERSION))
- {
- if (opt_verbose)
- puts("mysql_upgrade has already been done for this version");
- goto fix_priv_tables;
- }
- }
+/*
+ Check and upgrade(if neccessary) all tables
+ in the server using "mysqlcheck --check-upgrade .."
+*/
+static int run_mysqlcheck_upgrade(void)
+{
+ verbose("Running 'mysqlcheck'...");
+ return run_tool(mysqlcheck_path,
+ NULL, /* Send output from mysqlcheck directly to screen */
+ defaults_file_option,
+ "--check-upgrade",
+ "--all-databases",
+ "--auto-repair",
+ NULL);
+}
- /* Find mysqlcheck */
- if (find_file(mysqlcheck_name, basedir, MYF(0), path, sizeof(path),
- "bin", EXTRA_CLIENT_PATHS, NullS))
- {
- ret= 1;
- fprintf(stderr,
- "Can't find program '%s'\n"
- "Please restart with --basedir=mysql-install-directory",
- mysqlcheck_name);
- goto error;
- }
- else
+
+static const char *expected_errors[]=
+{
+ "ERROR 1060", /* Duplicate column name */
+ "ERROR 1061", /* Duplicate key name */
+ "ERROR 1054", /* Unknown column */
+ 0
+};
+
+
+static my_bool is_expected_error(const char* line)
+{
+ const char** error= expected_errors;
+ while (*error)
{
-#ifdef __WIN__
- /* Windows requires an extra pair of quotes around the entire string. */
- dynstr_set(&cmdline, "\"");
-#else
- dynstr_set(&cmdline, "");
-#endif /* __WIN__ */
- dynstr_append_os_quoted(&cmdline, path, NullS);
+ /*
+ Check if lines starting with ERROR
+ are in the list of expected errors
+ */
+ if (strncmp(line, "ERROR", 5) != 0 ||
+ strncmp(line, *error, strlen(*error)) == 0)
+ return 1; /* Found expected error */
+ error++;
}
+ return 0;
+}
- /*
- All settings have been written to the "upgrade_defaults_path"
- instruct mysqlcheck to only read options from that file
- */
- dynstr_append(&cmdline, " ");
- dynstr_append_os_quoted(&cmdline,
- (no_defaults ? "--defaults-file=" :
- "--defaults-extra-file="),
- upgrade_defaults_path, NullS);
- dynstr_append(&cmdline, " ");
- dynstr_append_os_quoted(&cmdline, "--check-upgrade", NullS);
- dynstr_append(&cmdline, " ");
- dynstr_append_os_quoted(&cmdline, "--all-databases", NullS);
- dynstr_append(&cmdline, " ");
- dynstr_append_os_quoted(&cmdline, "--auto-repair", NullS);
- dynstr_append(&cmdline, " ");
- dynstr_append_os_quoted(&cmdline, "--user=", user, NullS);
-#ifdef __WIN__
- dynstr_append(&cmdline, "\"");
-#endif /* __WIN__ */
-
- /* Execute mysqlcheck */
- if (opt_verbose)
- printf("Running %s\n", cmdline.str);
- DBUG_PRINT("info", ("Running: %s", cmdline.str));
- ret= system(cmdline.str);
- if (ret)
+
+static char* get_line(char* line)
+{
+ while (*line && *line != '\n')
+ line++;
+ if (*line)
+ line++;
+ return line;
+}
+
+
+/* Print the current line to stderr */
+static void print_line(char* line)
+{
+ while (*line && *line != '\n')
{
- fprintf(stderr, "Error executing '%s'\n", cmdline.str);
- goto error;
+ fputc(*line, stderr);
+ line++;
}
+ fputc('\n', stderr);
+}
- fn_format(path, MYSQL_UPGRADE_INFO_NAME, datadir, "", MYF(0));
- ret= create_check_file(path);
- if (ret)
- goto error;
-fix_priv_tables:
- /* Find mysql */
- if (find_file(mysql_name, basedir, MYF(0), path, sizeof(path),
- "bin", EXTRA_CLIENT_PATHS, NullS))
+/*
+ Update all system tables in MySQL Server to current
+ version using "mysql" to execute all the SQL commands
+ compiled into the mysql_fix_privilege_tables array
+*/
+
+static int run_sql_fix_privilege_tables(void)
+{
+ int found_real_errors= 0;
+ DYNAMIC_STRING ds_result;
+ DBUG_ENTER("run_sql_fix_privilege_tables");
+
+ if (init_dynamic_string(&ds_result, "", 512, 512))
+ die("Out of memory");
+
+ verbose("Running 'mysql_fix_privilege_tables'...");
+ run_query(mysql_fix_privilege_tables,
+ &ds_result, /* Collect result */
+ TRUE);
+
{
- ret= 1;
- fprintf(stderr,
- "Could not find MySQL command-line client (mysql).\n"
- "Please use --basedir to specify the directory"
- " where MySQL is installed.");
- goto error;
+ /*
+ Scan each line of the result for real errors
+ and ignore the expected one(s) like "Duplicate column name",
+ "Unknown column" and "Duplicate key name" since they just
+ indicate the system tables are already up to date
+ */
+ char *line= ds_result.str;
+ do
+ {
+ if (!is_expected_error(line))
+ {
+ /* Something unexpected failed, dump error line to screen */
+ found_real_errors++;
+ print_line(line);
+ }
+ } while ((line= get_line(line)) && *line);
}
- else
+
+ dynstr_free(&ds_result);
+ return found_real_errors;
+}
+
+
+static const char *load_default_groups[]=
+{
+ "client", /* Read settings how to connect to server */
+ "mysql_upgrade", /* Read special settings for mysql_upgrade*/
+ 0
+};
+
+
+int main(int argc, char **argv)
+{
+ MY_INIT(argv[0]);
+#ifdef __NETWARE__
+ setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
+#endif
+
+ if (init_dynamic_string(&ds_options, "[client]\n", 512, 256))
+ die("Out of memory");
+
+ load_defaults("my", load_default_groups, &argc, &argv);
+ defaults_argv= argv; /* Must be freed by 'free_defaults' */
+
+ if (handle_options(&argc, &argv, my_long_options, get_one_option))
+ die(NULL);
+
+ if (tty_password)
{
-#ifdef __WIN__
- /* Windows requires an extra pair of quotes around the entire string. */
- dynstr_set(&cmdline, "\"");
-#else
- dynstr_set(&cmdline, "");
-#endif /* __WIN__ */
- dynstr_append_os_quoted(&cmdline, path, NullS);
+ opt_password= get_tty_password(NullS);
+ /* add password to defaults file */
+ dynstr_append(&ds_options, "password=");
+ dynstr_append(&ds_options, opt_password);
+ dynstr_append(&ds_options, "\n");
}
+ /* add user to defaults file */
+ dynstr_append(&ds_options, "user=");
+ dynstr_append(&ds_options, opt_user);
+ dynstr_append(&ds_options, "\n");
+
+ /* Find mysql */
+ find_tool(mysql_path, IF_WIN("mysql.exe", "mysql"));
+
+ /* Find mysqlcheck */
+ find_tool(mysqlcheck_path, IF_WIN("mysqlcheck.exe", "mysqlcheck"));
- /* Find mysql_fix_privililege_tables.sql */
- if (find_file(MYSQL_FIX_PRIV_TABLES_NAME, basedir, MYF(0),
- path, sizeof(path),
- "support_files", "share", "share/mysql", "scripts",
- NullS)
- && find_file(MYSQL_FIX_PRIV_TABLES_NAME, "/usr/local/mysql", MYF(0),
- path, sizeof(path),
- "share/mysql", NullS))
+ /*
+ Create the defaults file(a small my.cnf) which will pass
+ all arguments accepted by mysql_upgrade on to mysqlcheck
+ and mysql command line client
+ */
+ create_defaults_file();
+
+ /*
+ Read the mysql_upgrade_info file to check if mysql_upgrade
+ already has been run for this installation of MySQL
+ */
+ if (!opt_force && upgrade_already_done())
{
- ret= 1;
- fprintf(stderr,
- "Could not find file " MYSQL_FIX_PRIV_TABLES_NAME "\n"
- "Please use --basedir to specify the directory"
- " where MySQL is installed");
- goto error;
+ printf("This installation of MySQL is already upgraded to %s, "
+ "use --force if you still need to run mysql_upgrade\n",
+ MYSQL_SERVER_VERSION);
+ die(NULL);
}
/*
- All settings have been written to the "upgrade_defaults_path",
- instruct mysql to only read options from that file
+ Run "mysqlcheck" and "mysql_fix_privilege_tables.sql"
*/
- dynstr_append(&cmdline, " ");
- dynstr_append_os_quoted(&cmdline,
- (no_defaults ? "--defaults-file=" :
- "--defaults-extra-file="),
- upgrade_defaults_path, NullS);
- dynstr_append(&cmdline, " ");
- dynstr_append_os_quoted(&cmdline, "--force", NullS);
- dynstr_append(&cmdline, " ");
- dynstr_append_os_quoted(&cmdline, "--no-auto-rehash", NullS);
- dynstr_append(&cmdline, " ");
- dynstr_append_os_quoted(&cmdline, "--batch", NullS);
- dynstr_append(&cmdline, " ");
- dynstr_append_os_quoted(&cmdline, "--user=", user, NullS);
- dynstr_append(&cmdline, " ");
- dynstr_append_os_quoted(&cmdline, "--database=mysql", NullS);
- dynstr_append(&cmdline, " < ");
- dynstr_append_os_quoted(&cmdline, path, NullS);
-#ifdef __WIN__
- dynstr_append(&cmdline, "\"");
-#endif /* __WIN__ */
-
- /* Execute "mysql --force < mysql_fix_privilege_tables.sql" */
- if (opt_verbose)
- printf("Running %s\n", cmdline.str);
- DBUG_PRINT("info", ("Running: %s", cmdline.str));
- ret= system(cmdline.str);
- if (ret)
- fprintf(stderr, "Error executing '%s'\n", cmdline.str);
-
-error:
- dynstr_free(&cmdline);
+ if (run_mysqlcheck_upgrade() ||
+ run_sql_fix_privilege_tables())
+ {
+ /*
+ The upgrade failed to complete in some way or another,
+ significant error message should have been printed to the screen
+ */
+ die("Upgrade failed" );
+ }
+ verbose("OK");
- /* Delete the generated defaults file */
- my_delete(upgrade_defaults_path, MYF(0));
+ /* Create a file indicating upgrade has been performed */
+ create_mysql_upgrade_info_file();
- free_defaults(defaults_argv);
- my_end(info_flag ? MY_CHECK_ERROR : 0);
- return ret;
+ free_used_memory();
+ my_end(MY_CHECK_ERROR);
+ exit(0);
}
diff --git a/include/my_global.h b/include/my_global.h
index 21fe1ebc3cb..3382916840e 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -86,6 +86,14 @@
#endif
#endif /* _WIN32... */
+/* Make it easier to add conditionl code for windows */
+#ifdef __WIN__
+#define IF_WIN(A,B) (A)
+#else
+#define IF_WIN(A,B) (B)
+#endif
+
+
/* Some defines to avoid ifdefs in the code */
#ifndef NETWARE_YIELD
#define NETWARE_YIELD
diff --git a/mysql-test/r/bdb_notembedded.result b/mysql-test/r/bdb_notembedded.result
new file mode 100644
index 00000000000..14cb5fad915
--- /dev/null
+++ b/mysql-test/r/bdb_notembedded.result
@@ -0,0 +1,35 @@
+set autocommit=1;
+reset master;
+create table bug16206 (a int);
+insert into bug16206 values(1);
+start transaction;
+insert into bug16206 values(2);
+commit;
+show binlog events;
+Log_name Pos Event_type Server_id End_log_pos Info
+f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4
+f n Query 1 n use `test`; create table bug16206 (a int)
+f n Query 1 n use `test`; insert into bug16206 values(1)
+f n Query 1 n use `test`; insert into bug16206 values(2)
+drop table bug16206;
+reset master;
+create table bug16206 (a int) engine= bdb;
+insert into bug16206 values(0);
+insert into bug16206 values(1);
+start transaction;
+insert into bug16206 values(2);
+commit;
+insert into bug16206 values(3);
+show binlog events;
+Log_name Pos Event_type Server_id End_log_pos Info
+f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4
+f n Query 1 n use `test`; create table bug16206 (a int) engine= bdb
+f n Query 1 n use `test`; insert into bug16206 values(0)
+f n Query 1 n use `test`; insert into bug16206 values(1)
+f n Query 1 n use `test`; BEGIN
+f n Query 1 n use `test`; insert into bug16206 values(2)
+f n Query 1 n use `test`; COMMIT
+f n Query 1 n use `test`; insert into bug16206 values(3)
+drop table bug16206;
+set autocommit=0;
+End of 5.0 tests
diff --git a/mysql-test/r/mysql_upgrade.result b/mysql-test/r/mysql_upgrade.result
index f92540a0d55..ce4706c6d92 100644
--- a/mysql-test/r/mysql_upgrade.result
+++ b/mysql-test/r/mysql_upgrade.result
@@ -16,48 +16,9 @@ mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
mysql.user OK
-@hadGrantPriv:=1
-1
-1
-1
-@hadShowDbPriv:=1
-1
-1
-1
-@hadCreateViewPriv:=1
-1
-1
-1
-@hadCreateRoutinePriv:=1
-1
-1
-1
-@hadCreateUserPriv:=1
-1
-1
-1
Run it again - should say already completed
-@hadGrantPriv:=1
-1
-1
-1
-@hadShowDbPriv:=1
-1
-1
-1
-@hadCreateViewPriv:=1
-1
-1
-1
-@hadCreateRoutinePriv:=1
-1
-1
-1
-@hadCreateUserPriv:=1
-1
-1
-1
-Force should run it regardless of wheter it's been run before
+This installation of MySQL is already upgraded to VERSION, use --force if you still need to run mysql_upgrade
+Force should run it regardless of wether it's been run before
mysql.columns_priv OK
mysql.db OK
mysql.func OK
@@ -75,23 +36,27 @@ mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
mysql.user OK
-@hadGrantPriv:=1
-1
-1
-1
-@hadShowDbPriv:=1
-1
-1
-1
-@hadCreateViewPriv:=1
-1
-1
-1
-@hadCreateRoutinePriv:=1
-1
-1
-1
-@hadCreateUserPriv:=1
-1
-1
-1
+CREATE USER mysqltest1@'%' IDENTIFIED by 'sakila';
+GRANT ALL ON *.* TO mysqltest1@'%';
+Run mysql_upgrade with password protected account
+mysql.columns_priv OK
+mysql.db OK
+mysql.func OK
+mysql.help_category OK
+mysql.help_keyword OK
+mysql.help_relation OK
+mysql.help_topic OK
+mysql.host OK
+mysql.proc OK
+mysql.procs_priv OK
+mysql.tables_priv OK
+mysql.time_zone OK
+mysql.time_zone_leap_second OK
+mysql.time_zone_name OK
+mysql.time_zone_transition OK
+mysql.time_zone_transition_type OK
+mysql.user OK
+DROP USER mysqltest1@'%';
+Run mysql_upgrade with a non existing server socket
+mysqlcheck: Got error: 2002: Can't connect to local MySQL server through socket 'var/tmp/no_sock_here' (2) when trying to connect
+FATAL ERROR: Upgrade failed
diff --git a/mysql-test/t/bdb_notembedded.test b/mysql-test/t/bdb_notembedded.test
new file mode 100644
index 00000000000..24e64ebbfb2
--- /dev/null
+++ b/mysql-test/t/bdb_notembedded.test
@@ -0,0 +1,38 @@
+-- source include/not_embedded.inc
+-- source include/have_bdb.inc
+
+#
+# Bug #16206: Superfluous COMMIT event in binlog when updating BDB in autocommit mode
+#
+set autocommit=1;
+
+let $VERSION=`select version()`;
+
+reset master;
+create table bug16206 (a int);
+insert into bug16206 values(1);
+start transaction;
+insert into bug16206 values(2);
+commit;
+--replace_result $VERSION VERSION
+--replace_column 1 f 2 n 5 n
+show binlog events;
+drop table bug16206;
+
+reset master;
+create table bug16206 (a int) engine= bdb;
+insert into bug16206 values(0);
+insert into bug16206 values(1);
+start transaction;
+insert into bug16206 values(2);
+commit;
+insert into bug16206 values(3);
+--replace_result $VERSION VERSION
+--replace_column 1 f 2 n 5 n
+show binlog events;
+drop table bug16206;
+
+set autocommit=0;
+
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/mysql_upgrade.test b/mysql-test/t/mysql_upgrade.test
index c6133f8e85f..973e9157987 100644
--- a/mysql-test/t/mysql_upgrade.test
+++ b/mysql-test/t/mysql_upgrade.test
@@ -7,17 +7,55 @@
select LENGTH("$MYSQL_UPGRADE")>0 as have_mysql_upgrade;
--enable_query_log
+# Get version of the server so it can be masked out in the
+# error messages from mysql_upgrade
+let $VERSION=`select LEFT(version(), 6)`;
+
#
-# Basic test thta we can run mysql_upgrde and that it finds the
+# Basic test that we can run mysql_upgrde and that it finds the
# expected binaries it uses.
#
--echo Run mysql_upgrade once
---exec $MYSQL_UPGRADE 2> $MYSQLTEST_VARDIR/log/mysql_upgrade.err
+--exec $MYSQL_UPGRADE --skip-verbose 2>&1
+
+# It should have created a file in the MySQL Servers datadir
+file_exists $MYSQLTEST_VARDIR/master-data/mysql_upgrade_info;
--echo Run it again - should say already completed
---exec $MYSQL_UPGRADE 2> $MYSQLTEST_VARDIR/log/mysql_upgrade.err
+--replace_result $VERSION VERSION
+--error 1
+--exec $MYSQL_UPGRADE --skip-verbose 2>&1
+
+# It should have created a file in the MySQL Servers datadir
+file_exists $MYSQLTEST_VARDIR/master-data/mysql_upgrade_info;
+
+--echo Force should run it regardless of wether it's been run before
+--exec $MYSQL_UPGRADE --skip-verbose --force 2>&1
+
+# It should have created a file in the MySQL Servers datadir
+file_exists $MYSQLTEST_VARDIR/master-data/mysql_upgrade_info;
+
+
+#
+# Bug #25452 mysql_upgrade access denied.
+#
+
+# Password protect a root account and run mysql_upgrade
+
+CREATE USER mysqltest1@'%' IDENTIFIED by 'sakila';
+GRANT ALL ON *.* TO mysqltest1@'%';
+--echo Run mysql_upgrade with password protected account
+--exec $MYSQL_UPGRADE --skip-verbose --force --user=mysqltest1 --password=sakila 2>&1
---echo Force should run it regardless of wheter it's been run before
---exec $MYSQL_UPGRADE --force 2> $MYSQLTEST_VARDIR/log/mysql_upgrade.err
+DROP USER mysqltest1@'%';
+#
+# Bug #26639 mysql_upgrade exits successfully even if external command failed
+#
+
+--echo Run mysql_upgrade with a non existing server socket
+--replace_result $MYSQLTEST_VARDIR var
+--replace_regex /.*mysqlcheck.*: Got/mysqlcheck: Got/
+--error 1
+--exec $MYSQL_UPGRADE --skip-verbose --force --socket=$MYSQLTEST_VARDIR/tmp/no_sock_here 2>&1
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
new file mode 100755
index 00000000000..8580844097e
--- /dev/null
+++ b/scripts/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Copyright (C) 2006 MySQL AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+ADD_EXECUTABLE(comp_sql comp_sql.c)
+TARGET_LINK_LIBRARIES(comp_sql dbug mysys strings)
+
+# Build comp_sql - used for embedding SQL in C or C++ programs
+GET_TARGET_PROPERTY(COMP_SQL_EXE comp_sql LOCATION)
+
+ADD_CUSTOM_COMMAND(OUTPUT ${PROJECT_SOURCE_DIR}/client/mysql_fix_privilege_tables_sql.c
+ COMMAND ${COMP_SQL_EXE}
+ ${PROJECT_SOURCE_DIR}/scripts/mysql_fix_privilege_tables.sql
+ ${PROJECT_SOURCE_DIR}/client/mysql_fix_privilege_tables_sql.c
+ DEPENDS comp_sql ${PROJECT_SOURCE_DIR}/scripts/mysql_fix_privilege_tables.sql)
+
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index d7053a86b3a..e4a75ab4591 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -165,5 +165,19 @@ SUFFIXES = .sh
@CHMOD@ +x $@-t
@MV@ $@-t $@
+
+BUILT_SOURCES = mysql_fix_privilege_tables_sql.c
+noinst_PROGRAMS = comp_sql
+
+#
+# Build mysql_fix_privilege_tables_sql.c from
+# mysql_fix_privileges_tables.sql using comp_sql
+#
+mysql_fix_privilege_tables_sql.c: comp_sql.c mysql_fix_privilege_tables.sql
+ $(MAKE) $(AM_MAKEFLAGS) comp_sql$(EXEEXT)
+ $(top_builddir)/scripts/comp_sql$(EXEEXT) \
+ mysql_fix_privilege_tables.sql $@
+
+
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/scripts/comp_sql.c b/scripts/comp_sql.c
new file mode 100644
index 00000000000..60236774701
--- /dev/null
+++ b/scripts/comp_sql.c
@@ -0,0 +1,119 @@
+/* Copyright (C) 2004 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Written by Magnus Svensson
+*/
+
+/*
+ Converts a SQL file into a C file that can be compiled and linked
+ into other programs
+*/
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+FILE *in, *out;
+
+static void die(const char *fmt, ...)
+{
+ va_list args;
+
+ /* Print the error message */
+ fprintf(stderr, "FATAL ERROR: ");
+ if (fmt)
+ {
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ }
+ else
+ fprintf(stderr, "unknown error");
+ fprintf(stderr, "\n");
+ fflush(stderr);
+
+ /* Close any open files */
+ if (in)
+ fclose(in);
+ if (out)
+ fclose(out);
+
+ exit(1);
+}
+
+
+int main(int argc, char *argv[])
+{
+ char buff[512];
+ char* infile_name= argv[1];
+ char* outfile_name= argv[2];
+ char* end= infile_name;
+
+ if (argc != 3)
+ die("Usage: comp_sql <sql_filename> <c_filename>");
+
+ /* Open input and output file */
+ if (!(in= fopen(infile_name, "r")))
+ die("Failed to open SQL file '%s'", infile_name);
+ if (!(out= fopen(outfile_name, "w")))
+ die("Failed to open output file '%s'", outfile_name);
+
+ while(*end && *end != '.')
+ end++;
+ *end= 0;
+ fprintf(out, "const char* %s={\"\\\n", infile_name);
+
+ while (fgets(buff, sizeof(buff), in))
+ {
+ char *curr= buff;
+ while (*curr)
+ {
+ if (*curr == '\n')
+ {
+ /*
+ Reached end of line, add escaped newline, escaped
+ backslash and a newline to outfile
+ */
+ fprintf(out, "\\n\\\n");
+ curr++;
+ }
+ else if (*curr == '\r')
+ {
+ curr++; /* Skip */
+ }
+ else
+ {
+ if (*curr == '"')
+ {
+ /* Needs escape */
+ fputc('\\', out);
+ }
+
+ fputc(*curr, out);
+ curr++;
+ }
+ }
+ }
+
+ fprintf(out, "\\\n\"};\n");
+
+ fclose(in);
+ fclose(out);
+
+ exit(0);
+
+}
+
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 6667795f5f0..7961aa234c8 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -268,7 +268,6 @@ MY_LOCALE *my_locale_by_number(uint number);
#endif
#if defined(__WIN__) || defined(OS2)
-#define IF_WIN(A,B) (A)
#undef FLUSH_TIME
#define FLUSH_TIME 1800 /* Flush every half hour */
@@ -277,7 +276,6 @@ MY_LOCALE *my_locale_by_number(uint number);
#define WAIT_PRIOR 0
#define QUERY_PRIOR 2
#else
-#define IF_WIN(A,B) (B)
#define INTERRUPT_PRIOR 10
#define CONNECT_PRIOR 9
#define WAIT_PRIOR 8