diff options
-rw-r--r-- | .bzrignore | 2 | ||||
-rwxr-xr-x | CMakeLists.txt | 1 | ||||
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | client/mysql_upgrade.c | 1188 | ||||
-rw-r--r-- | include/my_global.h | 8 | ||||
-rw-r--r-- | mysql-test/r/bdb_notembedded.result | 35 | ||||
-rw-r--r-- | mysql-test/r/mysql_upgrade.result | 87 | ||||
-rw-r--r-- | mysql-test/t/bdb_notembedded.test | 38 | ||||
-rw-r--r-- | mysql-test/t/mysql_upgrade.test | 48 | ||||
-rwxr-xr-x | scripts/CMakeLists.txt | 28 | ||||
-rw-r--r-- | scripts/Makefile.am | 14 | ||||
-rw-r--r-- | scripts/comp_sql.c | 119 | ||||
-rw-r--r-- | sql/mysql_priv.h | 2 |
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*) ¤t_host, - (gptr*) ¤t_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + (gptr*)¬_used, (gptr*)¬_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 |