diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 6ec361392c8..b8344606448 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -16,21 +16,42 @@ #include "client_priv.h" #include +#include +#include + +#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" + +#define MY_PARENT (1 << 0) +#define MY_ISDIR (1 << 1) +#define MY_SEARCH_SELF (1 << 2) #ifdef __WIN__ const char *mysqlcheck_name= "mysqlcheck.exe"; const char *mysql_name= "mysql.exe"; +const char *mysqld_name= "mysqld.exe"; #else const char *mysqlcheck_name= "mysqlcheck"; const char *mysql_name= "mysql"; +const char *mysqld_name= "mysqld"; #endif /*__WIN__*/ -static my_bool opt_force= 0, opt_verbose= 0, tty_password= 0; +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 my_bool upgrade_defaults_created= 0; -static my_string opt_mysql_port, opt_mysql_unix_port= 0; -static char *default_dbug_option= (char*) "d:t:O,/tmp/comp_err.trace"; -static my_bool info_flag= 0; +static 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 struct my_option my_long_options[]= { @@ -50,27 +71,51 @@ static struct my_option my_long_options[]= #endif {"debug-info", 'T', "Print some debug info at exit.", (gptr *) & info_flag, (gptr *) & info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"force", 'f', "Continue even if we get an sql-error.", + {"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}, + {"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}, + {"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}, {"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}, + "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}, +#ifdef __WIN__ + {"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}, + (gptr*) &opt_mysql_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#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}, +#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}, + (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}, - {"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}, +#include + {"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}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; + static const char *load_default_groups[]= { "mysql_upgrade", 0 @@ -78,6 +123,81 @@ static const char *load_default_groups[]= #include +static LIST *extra_defaults= NULL; + +typedef struct _extra_default +{ + 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) +{ + 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 */ + /* 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; + } + + 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) + 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); + } + } +} + + static my_bool get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)), char *argument) @@ -85,16 +205,13 @@ get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)), switch (optid) { case '?': puts - ("MySQL utility script to upgrade database to the current server version"); + ("MySQL utility to upgrade database to the current server version"); puts(""); my_print_help(my_long_options); exit(0); case '#': DBUG_PUSH(argument ? argument : default_dbug_option); break; - case 'f': - opt_force= TRUE; - break; case 'p': tty_password= 1; if (argument) @@ -109,315 +226,415 @@ get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)), 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)); + break; +#endif + case OPT_MYSQL_PROTOCOL: + if (find_type(argument, &sql_protocol_typelib, 0) > 0) + { + my_free(opt_protocol, MYF(MY_ALLOW_ZERO_PTR)); + opt_protocol= my_strdup(argument, MYF(MY_FAE)); + } + else + { + fprintf(stderr, "Unknown option to protocol: %s\n", argument); + exit(1); + } + break; +#include default:; - }; + } + set_extra_default(opt->id, opt); return 0; } -/* buffer should be not smaller than FN_REFLEN */ -static my_bool test_file_exists_res(const char *dir, const char *fname, - char *buffer, char **buf_end) -{ - MY_STAT stat_info; - - *buf_end= strxnmov(buffer, FN_REFLEN-1, dir, "/", fname, NullS); - unpack_filename(buffer, buffer); - return my_stat(buffer, &stat_info, MYF(0)) != 0; -} - - -static my_bool test_file_exists(const char *dir, const char *fname) -{ - char path[FN_REFLEN]; - char *path_end; - return test_file_exists_res(dir, fname, path, &path_end); -} - - static int create_check_file(const char *path) { - File check_file= my_open(path, O_CREAT | O_WRONLY, MYF(MY_FAE | MY_WME)); - int error; - - if (check_file < 0) - return 1; - - error= my_write(check_file, - MYSQL_SERVER_VERSION, strlen(MYSQL_SERVER_VERSION), + int ret; + File fd; + + fd= my_open(path, O_CREAT | O_WRONLY, MYF(MY_FAE | MY_WME)); + if (fd < 0) { + ret= 1; + goto error; + } + ret= my_write(fd, MYSQL_SERVER_VERSION, + sizeof(MYSQL_SERVER_VERSION) - 1, MYF(MY_WME | MY_FNABP)); - error= my_close(check_file, MYF(MY_FAE | MY_WME)) || error; - return error; + ret|= my_close(fd, MYF(MY_FAE | MY_WME)); +error: + return ret; } -static int create_defaults_file(const char *path, const char *our_defaults_path) +static int create_defaults_file(const char *path, const char *forced_path) { - uint b_read; - File our_defaults_file, defaults_file; - char buffer[512]; - char *buffer_end; - int failed_to_open_count= 0; - int error; + int ret; + uint cnt; + File forced_file, defaults_file; + + DYNAMIC_STRING buf; + extra_default_t *d; - /* check if the defaults file is needed at all */ - if (!opt_password) - return 0; - -retry_open: + 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) { - if (failed_to_open_count == 0) - { - remove(path); - failed_to_open_count+= 1; - goto retry_open; - } - else - return 1; + ret= 1; + goto out; } - upgrade_defaults_created= 1; - if (our_defaults_path) + if (init_dynamic_string(&buf, NULL, my_getpagesize(), FN_REFLEN)) { - our_defaults_file= my_open(our_defaults_path, O_RDONLY, - MYF(MY_FAE | MY_WME)); - if (our_defaults_file < 0) - return 1; + ret= 1; + goto error; + } + + if (forced_path) + { + forced_file= my_open(forced_path, O_RDONLY, MYF(MY_FAE | MY_WME)); + if (forced_file < 0) + { + ret= 1; + goto error; + } do { - if (((b_read= my_read(our_defaults_file, buffer, - sizeof(buffer), MYF(MY_WME))) == MY_FILE_ERROR) || - my_write(defaults_file, buffer, b_read, MYF(MY_FNABP | MY_WME))) + 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))) { - error= 1; - goto close_return; + ret= 1; + my_close(forced_file, MYF(0)); + goto error; } - } while (b_read == sizeof(buffer)); + } while (cnt == buf.max_length); + my_close(forced_file, MYF(0)); } - buffer_end= strnmov(buffer, "\n[client]", sizeof(buffer)); - if (opt_password) - buffer_end= strxnmov(buffer_end, sizeof(buffer), - "\npassword=", opt_password, NullS); - error= my_write(defaults_file, buffer, (int) (buffer_end - buffer), - MYF(MY_WME | MY_FNABP)); -close_return: - return my_close(defaults_file, MYF(MY_WME)) || error; + + dynstr_set(&buf, "\n[client]"); + 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() */ + { + if (my_write(defaults_file, buf.str, buf.length, MYF(MY_FNABP | MY_WME))) + { + ret= 1; + goto error; + } + dynstr_set(&buf, NULL); + } + 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)))) + { + ret= 1; + goto error; + } + my_delete((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))) + { + ret= 1; + goto error; + } + /* 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: + return ret; +} + + +/* Compare filenames */ +static int comp_names(struct fileinfo *a, struct fileinfo *b) +{ + return (strcmp(a->name,b->name)); +} + + +static int +find_file(const char *name, const char *root, uint flags, char *result, size_t len, ...) +{ + int ret; + va_list va; + FILEINFO key= { (char*)name, NULL }; + const char *subdir; + char *cp; + + DBUG_ASSERT(root != NULL); + + cp= strmake(result, root, len); + if (cp[-1] != FN_LIBCHAR) + *cp= FN_LIBCHAR; + + ret= 1; + va_start(va, len); + subdir= (!(flags & MY_SEARCH_SELF)) ? va_arg(va, char *) : ""; + while (ret && subdir) + { + MY_DIR *dir; + FILEINFO *match; + char *cp1; + + cp1= strnmov(cp + 1, 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) + { + if (!(flags & MY_PARENT)) + { + if (cp1[-1] != FN_LIBCHAR) + *cp1++= FN_LIBCHAR; + strnmov(cp1, name, len - (cp1 - result)); + } + else + { + if (cp1[-1] == FN_LIBCHAR) + --cp1; + while (*--cp1 == FN_LIBCHAR) + {} + *++cp1= FN_LIBCHAR; + *++cp1= '\0'; + } + if (flags & MY_ISDIR) + ret= !MY_S_ISDIR(match->mystat->st_mode); + else + ret= 0; + } + my_dirend(dir); + } + subdir= va_arg(va, char *); + } + va_end(va); + return ret; } int main(int argc, char **argv) { - char bindir[FN_REFLEN]; - char *bindir_end, *buf_end; - char datadir_buf[FN_REFLEN]; - char mysqlcheck_line[FN_REFLEN], *mysqlcheck_end; - char check_file_name[FN_REFLEN]; - int check_file; - char fix_priv_tables_cmd[FN_REFLEN], *fix_cmd_end; - char script_line[FN_REFLEN]; - int error; + int ret; + char *forced_defaults_file; char *forced_extra_defaults; char *defaults_group_suffix; - char upgrade_defaults_path[FN_REFLEN], *defaults_to_use= 0; - char port_socket[100], *port_socket_end; + const char *script_line; + char *upgrade_defaults_path; + char *defaults_to_use= NULL; + int upgrade_defaults_created= 0; + + char path[FN_REFLEN]; + DYNAMIC_STRING cmdline; MY_INIT(argv[0]); #ifdef __NETWARE__ setscreenmode(SCR_AUTOCLOSE_ON_EXIT); #endif - load_defaults("my", load_default_groups, &argc, &argv); - - if ((error= handle_options(&argc, &argv, my_long_options, get_one_option))) - exit(error); - - if (tty_password) - opt_password= get_tty_password(NullS); - - /* Check if we want to force the use a specific default file */ + /* Check if we are forced to use specific defaults */ get_defaults_options(argc, argv, &forced_defaults_file, &forced_extra_defaults, &defaults_group_suffix); + + load_defaults("my", load_default_groups, &argc, &argv); - port_socket_end= port_socket; - if (opt_mysql_port) - port_socket_end= strxnmov(port_socket, sizeof(port_socket) - 1, " --port=", - opt_mysql_port, NullS); - if (opt_mysql_unix_port) - port_socket_end= strxnmov(port_socket_end, - sizeof(port_socket) - - (int)(port_socket_end - port_socket) - 1, - " --socket=", opt_mysql_unix_port, NullS); - *port_socket_end= 0; - - if (basedir) + if (handle_options(&argc, &argv, my_long_options, get_one_option)) { - bindir_end= strmake(bindir, basedir, sizeof(bindir)-1); + ret= 1; + goto error; } - else + if (tty_password) + opt_password= get_tty_password(NullS); + + if (init_dynamic_string(&cmdline, NULL, 2 * FN_REFLEN + 128, FN_REFLEN)) { - if (test_file_exists("./share/mysql/english", "errmsg.sys") - && (test_file_exists("./bin", "mysqld") || - test_file_exists("./libexec", "mysqld"))) + ret= 1; + goto error; + } + 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_getwd(bindir, sizeof(bindir), MYF(0)); - bindir_end= bindir + strlen(bindir); - } - else - { - bindir_end= strmake(bindir, DEFAULT_MYSQL_HOME, sizeof(bindir)-1); + my_strdup((gptr)basedir, MYF(0)); + basedir= (char *)DEFAULT_MYSQL_HOME; } } if (!datadir) { - datadir= datadir_buf; - if (test_file_exists(bindir, "data/mysql")) - { - *strxnmov(datadir_buf, sizeof(datadir_buf)-1, bindir, "/data", NullS)= 0; - } - else if (test_file_exists(bindir, "var/mysql")) - { - *strxnmov(datadir_buf, sizeof(datadir_buf)-1, bindir, "/var", NullS)= 0; - } + 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; + datadir= (char *)DATADIR; + } + if (find_file("user.frm", datadir, MYF(0), path, sizeof(path), + "mysql", NullS)) + { + ret= 1; + puts("Can't find data directory. Please restart with" + " --datadir=path-to-writable-data-dir"); + goto error; } - strmake(bindir_end, "/bin", sizeof(bindir) - (int) (bindir_end - bindir)-1); - - if (!test_file_exists_res - (bindir, mysqlcheck_name, mysqlcheck_line, &mysqlcheck_end)) + /* + Create the modified defaults file to be used by mysqlcheck + and mysql tools + */ + fn_format(path, UPGRADE_DEFAULTS_NAME, datadir, "", MYF(0)); + upgrade_defaults_path= my_strdup(path, MYF(0)); + + if (extra_defaults) { - printf("Can't find program '%s'\n", mysqlcheck_line); - puts("Please restart with --basedir=mysql-install-directory"); - exit(1); - } + ret= create_defaults_file(upgrade_defaults_path, forced_extra_defaults); + if (ret) + goto error; + + defaults_to_use= upgrade_defaults_path; + upgrade_defaults_created= 1; + } + else + defaults_to_use= forced_extra_defaults; - if (!test_file_exists(datadir, "mysql/user.frm")) + if (!find_file(MYSQL_UPGRADE_INFO_NAME, datadir, MY_SEARCH_SELF, + path, sizeof(path), NULL, NullS) + && !opt_force) { - puts - ("Can't find data directory. Please restart with --datadir=path-to-data-dir"); - exit(1); - } - - /* create the modified defaults file to be used by mysqlcheck */ - /* and mysql tools */ - *strxnmov(upgrade_defaults_path, sizeof(upgrade_defaults_path)-1, - datadir, "/upgrade_defaults", NullS)= 0; - unpack_filename(upgrade_defaults_path, upgrade_defaults_path); - if ((error= - create_defaults_file(upgrade_defaults_path, forced_extra_defaults))) - goto err_exit; - - defaults_to_use= upgrade_defaults_created ? - upgrade_defaults_path : forced_extra_defaults; - - if (test_file_exists_res(datadir, "mysql_upgrade_info", check_file_name, - &buf_end) && !opt_force) - { - char chf_buffer[50]; - int b_read; - check_file= my_open(check_file_name, O_RDONLY, MYF(0)); - b_read= my_read(check_file, chf_buffer, sizeof(chf_buffer)-1, MYF(0)); - chf_buffer[b_read]= 0; - my_close(check_file, MYF(0)); - if (!strcmp(chf_buffer, MYSQL_SERVER_VERSION)) + 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 already done for this version"); + puts("mysql_upgrade has already been done for this version"); goto fix_priv_tables; } } + + if (find_file(mysqlcheck_name, basedir, MYF(0), path, sizeof(path), + "bin", NullS)) + { + ret= 1; + printf("Can't find program '%s'\n", mysqlcheck_name); + puts("Please restart with --basedir=mysql-install-directory"); + goto error; + } + else + dynstr_set(&cmdline, path); if (defaults_to_use) { - mysqlcheck_end= strxnmov(mysqlcheck_end, - sizeof(mysqlcheck_line) - (int) (mysqlcheck_end - - mysqlcheck_line), - " --defaults-extra-file=", defaults_to_use,NullS); + dynstr_append(&cmdline, " --defaults-extra-file="); + dynstr_append(&cmdline, defaults_to_use); } - - mysqlcheck_end= strxnmov(mysqlcheck_end, - sizeof(mysqlcheck_line) - - (int) (mysqlcheck_end - mysqlcheck_line - 1), - " --check-upgrade --all-databases --auto-repair --user=", - user, port_socket, NullS); - *mysqlcheck_end= 0; + + dynstr_append(&cmdline, " --check-upgrade --all-databases" + " --auto-repair --user="); + dynstr_append(&cmdline, user); if (opt_verbose) - printf("Running %s\n", mysqlcheck_line); - if ((error= system(mysqlcheck_line))) + printf("Running %s\n", cmdline.str); + + ret= system(cmdline.str); + if (ret) { - printf("Error executing '%s'\n", mysqlcheck_line); - goto err_exit; + printf("Error executing '%s'\n", cmdline.str); + goto error; } - if ((error= create_check_file(check_file_name))) - goto err_exit; + fn_format(path, MYSQL_UPGRADE_INFO_NAME, datadir, "", MYF(0)); + ret= create_check_file(path); + if (ret) + goto error; fix_priv_tables: - if (!test_file_exists_res(bindir, mysql_name, - fix_priv_tables_cmd, &fix_cmd_end)) + if (find_file(mysql_name, basedir, MYF(0), path, sizeof(path), + "bin", NullS)) { - puts("Could not find MySQL command-line client (mysql)."); - puts - ("Please use --basedir to specify the directory where MySQL is installed."); - error= 1; - goto err_exit; + ret= 1; + puts("Could not find MySQL command-line client (mysql).\n" + "Please use --basedir to specify the directory" + " where MySQL is installed."); + goto error; } + else + dynstr_set(&cmdline, path); - if (!test_file_exists_res(basedir, - "support_files/mysql_fix_privilege_tables.sql", - script_line, &buf_end) - && !test_file_exists_res(basedir, "share/mysql_fix_privilege_tables.sql", - script_line, &buf_end) - && !test_file_exists_res(basedir, - "share/mysql/mysql_fix_privilege_tables.sql", - script_line, &buf_end) - && !test_file_exists_res(basedir, - "scripts/mysql_fix_privilege_tables.sql", - script_line, &buf_end) - && !test_file_exists_res("/usr/local/mysql/share/mysql", - "mysql_fix_privilege_tables.sql", script_line, - &buf_end)) + if (find_file(MYSQL_FIX_PRIV_TABLES_NAME, basedir, MYF(0), + path, sizeof(path), + "support_files", "share/mysql", "scripts", + NullS) + && find_file(MYSQL_FIX_PRIV_TABLES_NAME, "/usr/local/mysql", MYF(0), + path, sizeof(path), + "share/mysql", NullS)) { - puts("Could not find file mysql_fix_privilege_tables.sql"); - puts - ("Please use --basedir to specify the directory where MySQL is installed"); - error= 1; - goto err_exit; + ret= 1; + puts("Could not find file " MYSQL_FIX_PRIV_TABLES_NAME "\n" + "Please use --basedir to specify the directory" + " where MySQL is installed"); + goto error; } + else + script_line= my_strdup(path, MYF(0)); if (defaults_to_use) { - fix_cmd_end= strxnmov(fix_cmd_end, - sizeof(fix_priv_tables_cmd) - - (int) (fix_cmd_end - fix_priv_tables_cmd - 1), - " --defaults-extra-file=", defaults_to_use, NullS); + dynstr_append(&cmdline, " --defaults-extra-file="); + dynstr_append(&cmdline, defaults_to_use); } - fix_cmd_end= strxnmov(fix_cmd_end, - sizeof(fix_priv_tables_cmd) - (int) (fix_cmd_end - - fix_priv_tables_cmd), - " --user=", user, port_socket, " mysql < ", script_line, NullS); - *fix_cmd_end= 0; + dynstr_append(&cmdline, " --force --no-auto-rehash --batch --user="); + dynstr_append(&cmdline, user); + dynstr_append(&cmdline, " mysql < "); + dynstr_append(&cmdline, script_line); - if ((error= system(fix_priv_tables_cmd))) - { - /* Problem is that the 'Duplicate column' error */ - /* which is not a bug for the script makes 'mysql' return */ - /* an error */ - /* printf("Error executing '%s'\n", fix_priv_tables_cmd); */ - } + if (opt_verbose) + printf("Running %s\n", cmdline.str); + + ret= system(cmdline.str); + if (ret) + printf("Error executing '%s'\n", cmdline.str); + +error: + dynstr_free(&cmdline); -err_exit: if (upgrade_defaults_created) my_delete(upgrade_defaults_path, MYF(0)); + my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); - return error; -} /* main */ + return ret; +} + diff --git a/client/mysqltest.c b/client/mysqltest.c index aeb86575333..561bc541c74 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -80,13 +80,13 @@ enum { OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER, OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, OPT_SSL_VERIFY_SERVER_CERT, OPT_MAX_CONNECT_RETRIES, - OPT_MARK_PROGRESS + OPT_MARK_PROGRESS, OPT_CHARSETS_DIR }; static int record= 0, opt_sleep= -1; static char *db= 0, *pass= 0; const char *user= 0, *host= 0, *unix_sock= 0, *opt_basedir= "./"; -const char *opt_include= 0; +const char *opt_include= 0, *opt_charsets_dir; static int port= 0; static int opt_max_connect_retries; static my_bool opt_compress= 0, silent= 0, verbose= 0; @@ -145,7 +145,6 @@ static struct st_test_file* file_stack_end; static CHARSET_INFO *charset_info= &my_charset_latin1; /* Default charset */ -static const char *charset_name= "latin1"; /* Default character set name */ static const char *embedded_server_groups[]= { @@ -3093,7 +3092,11 @@ void do_connect(struct st_command *command) if (opt_compress || con_compress) mysql_options(&next_con->mysql, MYSQL_OPT_COMPRESS, NullS); mysql_options(&next_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0); - mysql_options(&next_con->mysql, MYSQL_SET_CHARSET_NAME, charset_name); + mysql_options(&next_con->mysql, MYSQL_SET_CHARSET_NAME, + charset_info->csname); + if (opt_charsets_dir) + mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_DIR, + opt_charsets_dir); #ifdef HAVE_OPENSSL if (opt_use_ssl || con_ssl) @@ -3779,6 +3782,9 @@ static struct my_option my_long_options[] = 0, 0, 0, 0, 0, 0}, {"basedir", 'b', "Basedir for tests.", (gptr*) &opt_basedir, (gptr*) &opt_basedir, 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}, {"compress", 'C', "Use the compressed server/client protocol.", (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -5511,7 +5517,11 @@ int main(int argc, char **argv) if (opt_compress) mysql_options(&cur_con->mysql,MYSQL_OPT_COMPRESS,NullS); mysql_options(&cur_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0); - mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_NAME, charset_name); + mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_NAME, + charset_info->csname); + if (opt_charsets_dir) + mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_DIR, + opt_charsets_dir); #ifdef HAVE_OPENSSL diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index c3b23781c56..ba9f788494a 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -591,7 +591,7 @@ sub command_line_setup () { 'tmpdir=s' => \$opt_tmpdir, 'vardir=s' => \$opt_vardir, 'benchdir=s' => \$glob_mysql_bench_dir, - 'mem' => \$opt_mem, + 'mem:s' => \$opt_mem, # Misc 'comment=s' => \$opt_comment, @@ -734,17 +734,18 @@ sub command_line_setup () { # -------------------------------------------------------------------------- # Check if we should speed up tests by trying to run on tmpfs # -------------------------------------------------------------------------- - if ( $opt_mem ) + if ( defined $opt_mem ) { mtr_error("Can't use --mem and --vardir at the same time ") if $opt_vardir; mtr_error("Can't use --mem and --tmpdir at the same time ") if $opt_tmpdir; - # Use /dev/shm as the preferred location for vardir and - # thus implicitly also tmpdir. Add other locations to list - my @tmpfs_locations= ($opt_mem, "/dev/shm"); - # One could maybe use "mount" to find tmpfs location(s) + # Search through list of locations that are known + # to be "fast disks" to list to find a suitable location + # Use --mem= as first location to look. + my @tmpfs_locations= ($opt_mem, "/dev/shm", "/tmp"); + foreach my $fs (@tmpfs_locations) { if ( -d $fs ) @@ -2988,9 +2989,9 @@ sub analyze_testcase_failure_sync_with_master($) mtr_add_arg($args, "--no-defaults"); mtr_add_arg($args, "--silent"); - mtr_add_arg($args, "-v"); mtr_add_arg($args, "--skip-safemalloc"); mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); + mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir); mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_sock'}); mtr_add_arg($args, "--port=%d", $master->[0]->{'port'}); @@ -4174,9 +4175,9 @@ sub run_check_testcase ($$) { mtr_add_arg($args, "--no-defaults"); mtr_add_arg($args, "--silent"); - mtr_add_arg($args, "-v"); mtr_add_arg($args, "--skip-safemalloc"); mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); + mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir); mtr_add_arg($args, "--socket=%s", $mysqld->{'path_sock'}); mtr_add_arg($args, "--port=%d", $mysqld->{'port'}); @@ -4220,9 +4221,9 @@ sub run_mysqltest ($) { mtr_add_arg($args, "--no-defaults"); mtr_add_arg($args, "--silent"); - mtr_add_arg($args, "-v"); mtr_add_arg($args, "--skip-safemalloc"); mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); + mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir); if ($tinfo->{'component_id'} eq 'im') { @@ -4307,13 +4308,11 @@ sub run_mysqltest ($) { if ( $opt_ssl ) { # Turn on SSL for _all_ test cases if option --ssl was used - mtr_add_arg($args, "--ssl", - $glob_mysql_test_dir); + mtr_add_arg($args, "--ssl"); } elsif ( $opt_ssl_supported ) { - mtr_add_arg($args, "--skip-ssl", - $glob_mysql_test_dir); + mtr_add_arg($args, "--skip-ssl"); } # ---------------------------------------------------------------------- @@ -4648,9 +4647,12 @@ Options to control directories to use vardir=DIR The directory where files generated from the test run is stored (default: ./var). Specifying a ramdisk or tmpfs will speed up tests. - mem Run testsuite in "memory" using tmpfs if - available(default: /dev/shm) - reads path from MTR_MEM environment variable + mem[=DIR] Run testsuite in "memory" using tmpfs or ramdisk + Attempts to use DIR first if specified else + uses as builtin list of standard locations + for tmpfs (/dev/shm) + The option can also be set using environment + variable MTR_MEM=[DIR] Options to control what test suites or cases to run diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index c2c12f8d291..e5342eec54f 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -1148,4 +1148,759 @@ id select_type table type possible_keys key key_len ref rows Extra Warnings: Note 1003 select `test`.`t1`.`code` AS `code`,`test`.`t2`.`id` AS `id` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`code` = _latin1'a12') and (length(`test`.`t1`.`code`) = 5)) DROP TABLE t1,t2; +select locate('he','hello',-2); +locate('he','hello',-2) +0 +select locate('lo','hello',-4294967295); +locate('lo','hello',-4294967295) +0 +select locate('lo','hello',4294967295); +locate('lo','hello',4294967295) +0 +select locate('lo','hello',-4294967296); +locate('lo','hello',-4294967296) +0 +select locate('lo','hello',4294967296); +locate('lo','hello',4294967296) +0 +select locate('lo','hello',-4294967297); +locate('lo','hello',-4294967297) +0 +select locate('lo','hello',4294967297); +locate('lo','hello',4294967297) +0 +select locate('lo','hello',-18446744073709551615); +locate('lo','hello',-18446744073709551615) +0 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select locate('lo','hello',18446744073709551615); +locate('lo','hello',18446744073709551615) +0 +select locate('lo','hello',-18446744073709551616); +locate('lo','hello',-18446744073709551616) +0 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select locate('lo','hello',18446744073709551616); +locate('lo','hello',18446744073709551616) +0 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select locate('lo','hello',-18446744073709551617); +locate('lo','hello',-18446744073709551617) +0 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select locate('lo','hello',18446744073709551617); +locate('lo','hello',18446744073709551617) +0 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select left('hello', 10); +left('hello', 10) +hello +select left('hello', 0); +left('hello', 0) + +select left('hello', -1); +left('hello', -1) + +select left('hello', -4294967295); +left('hello', -4294967295) + +select left('hello', 4294967295); +left('hello', 4294967295) +hello +select left('hello', -4294967296); +left('hello', -4294967296) + +select left('hello', 4294967296); +left('hello', 4294967296) +hello +select left('hello', -4294967297); +left('hello', -4294967297) + +select left('hello', 4294967297); +left('hello', 4294967297) +hello +select left('hello', -18446744073709551615); +left('hello', -18446744073709551615) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select left('hello', 18446744073709551615); +left('hello', 18446744073709551615) +hello +select left('hello', -18446744073709551616); +left('hello', -18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select left('hello', 18446744073709551616); +left('hello', 18446744073709551616) +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select left('hello', -18446744073709551617); +left('hello', -18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select left('hello', 18446744073709551617); +left('hello', 18446744073709551617) +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select right('hello', 10); +right('hello', 10) +hello +select right('hello', 0); +right('hello', 0) + +select right('hello', -1); +right('hello', -1) + +select right('hello', -4294967295); +right('hello', -4294967295) + +select right('hello', 4294967295); +right('hello', 4294967295) +hello +select right('hello', -4294967296); +right('hello', -4294967296) + +select right('hello', 4294967296); +right('hello', 4294967296) +hello +select right('hello', -4294967297); +right('hello', -4294967297) + +select right('hello', 4294967297); +right('hello', 4294967297) +hello +select right('hello', -18446744073709551615); +right('hello', -18446744073709551615) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select right('hello', 18446744073709551615); +right('hello', 18446744073709551615) +hello +select right('hello', -18446744073709551616); +right('hello', -18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select right('hello', 18446744073709551616); +right('hello', 18446744073709551616) +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select right('hello', -18446744073709551617); +right('hello', -18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select right('hello', 18446744073709551617); +right('hello', 18446744073709551617) +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 2, -1); +substring('hello', 2, -1) + +select substring('hello', -1, 1); +substring('hello', -1, 1) +o +select substring('hello', -2, 1); +substring('hello', -2, 1) +l +select substring('hello', -4294967295, 1); +substring('hello', -4294967295, 1) + +select substring('hello', 4294967295, 1); +substring('hello', 4294967295, 1) + +select substring('hello', -4294967296, 1); +substring('hello', -4294967296, 1) + +select substring('hello', 4294967296, 1); +substring('hello', 4294967296, 1) + +select substring('hello', -4294967297, 1); +substring('hello', -4294967297, 1) + +select substring('hello', 4294967297, 1); +substring('hello', 4294967297, 1) + +select substring('hello', -18446744073709551615, 1); +substring('hello', -18446744073709551615, 1) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 18446744073709551615, 1); +substring('hello', 18446744073709551615, 1) + +select substring('hello', -18446744073709551616, 1); +substring('hello', -18446744073709551616, 1) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 18446744073709551616, 1); +substring('hello', 18446744073709551616, 1) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', -18446744073709551617, 1); +substring('hello', -18446744073709551617, 1) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 18446744073709551617, 1); +substring('hello', 18446744073709551617, 1) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 1, -1); +substring('hello', 1, -1) + +select substring('hello', 1, -4294967295); +substring('hello', 1, -4294967295) + +select substring('hello', 1, 4294967295); +substring('hello', 1, 4294967295) +hello +select substring('hello', 1, -4294967296); +substring('hello', 1, -4294967296) + +select substring('hello', 1, 4294967296); +substring('hello', 1, 4294967296) +hello +select substring('hello', 1, -4294967297); +substring('hello', 1, -4294967297) + +select substring('hello', 1, 4294967297); +substring('hello', 1, 4294967297) +hello +select substring('hello', 1, -18446744073709551615); +substring('hello', 1, -18446744073709551615) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 1, 18446744073709551615); +substring('hello', 1, 18446744073709551615) +hello +select substring('hello', 1, -18446744073709551616); +substring('hello', 1, -18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 1, 18446744073709551616); +substring('hello', 1, 18446744073709551616) +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 1, -18446744073709551617); +substring('hello', 1, -18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 1, 18446744073709551617); +substring('hello', 1, 18446744073709551617) +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', -1, -1); +substring('hello', -1, -1) + +select substring('hello', -4294967295, -4294967295); +substring('hello', -4294967295, -4294967295) + +select substring('hello', 4294967295, 4294967295); +substring('hello', 4294967295, 4294967295) + +select substring('hello', -4294967296, -4294967296); +substring('hello', -4294967296, -4294967296) + +select substring('hello', 4294967296, 4294967296); +substring('hello', 4294967296, 4294967296) + +select substring('hello', -4294967297, -4294967297); +substring('hello', -4294967297, -4294967297) + +select substring('hello', 4294967297, 4294967297); +substring('hello', 4294967297, 4294967297) + +select substring('hello', -18446744073709551615, -18446744073709551615); +substring('hello', -18446744073709551615, -18446744073709551615) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 18446744073709551615, 18446744073709551615); +substring('hello', 18446744073709551615, 18446744073709551615) + +select substring('hello', -18446744073709551616, -18446744073709551616); +substring('hello', -18446744073709551616, -18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 18446744073709551616, 18446744073709551616); +substring('hello', 18446744073709551616, 18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', -18446744073709551617, -18446744073709551617); +substring('hello', -18446744073709551617, -18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 18446744073709551617, 18446744073709551617); +substring('hello', 18446744073709551617, 18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', -1, 1, 'hi'); +insert('hello', -1, 1, 'hi') +hello +select insert('hello', -4294967295, 1, 'hi'); +insert('hello', -4294967295, 1, 'hi') +hello +select insert('hello', 4294967295, 1, 'hi'); +insert('hello', 4294967295, 1, 'hi') +hello +select insert('hello', -4294967296, 1, 'hi'); +insert('hello', -4294967296, 1, 'hi') +hello +select insert('hello', 4294967296, 1, 'hi'); +insert('hello', 4294967296, 1, 'hi') +hello +select insert('hello', -4294967297, 1, 'hi'); +insert('hello', -4294967297, 1, 'hi') +hello +select insert('hello', 4294967297, 1, 'hi'); +insert('hello', 4294967297, 1, 'hi') +hello +select insert('hello', -18446744073709551615, 1, 'hi'); +insert('hello', -18446744073709551615, 1, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 18446744073709551615, 1, 'hi'); +insert('hello', 18446744073709551615, 1, 'hi') +hello +select insert('hello', -18446744073709551616, 1, 'hi'); +insert('hello', -18446744073709551616, 1, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 18446744073709551616, 1, 'hi'); +insert('hello', 18446744073709551616, 1, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', -18446744073709551617, 1, 'hi'); +insert('hello', -18446744073709551617, 1, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 18446744073709551617, 1, 'hi'); +insert('hello', 18446744073709551617, 1, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 1, -1, 'hi'); +insert('hello', 1, -1, 'hi') +hi +select insert('hello', 1, -4294967295, 'hi'); +insert('hello', 1, -4294967295, 'hi') +hi +select insert('hello', 1, 4294967295, 'hi'); +insert('hello', 1, 4294967295, 'hi') +hi +select insert('hello', 1, -4294967296, 'hi'); +insert('hello', 1, -4294967296, 'hi') +hi +select insert('hello', 1, 4294967296, 'hi'); +insert('hello', 1, 4294967296, 'hi') +hi +select insert('hello', 1, -4294967297, 'hi'); +insert('hello', 1, -4294967297, 'hi') +hi +select insert('hello', 1, 4294967297, 'hi'); +insert('hello', 1, 4294967297, 'hi') +hi +select insert('hello', 1, -18446744073709551615, 'hi'); +insert('hello', 1, -18446744073709551615, 'hi') +hi +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 1, 18446744073709551615, 'hi'); +insert('hello', 1, 18446744073709551615, 'hi') +hi +select insert('hello', 1, -18446744073709551616, 'hi'); +insert('hello', 1, -18446744073709551616, 'hi') +hi +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 1, 18446744073709551616, 'hi'); +insert('hello', 1, 18446744073709551616, 'hi') +hi +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 1, -18446744073709551617, 'hi'); +insert('hello', 1, -18446744073709551617, 'hi') +hi +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 1, 18446744073709551617, 'hi'); +insert('hello', 1, 18446744073709551617, 'hi') +hi +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', -1, -1, 'hi'); +insert('hello', -1, -1, 'hi') +hello +select insert('hello', -4294967295, -4294967295, 'hi'); +insert('hello', -4294967295, -4294967295, 'hi') +hello +select insert('hello', 4294967295, 4294967295, 'hi'); +insert('hello', 4294967295, 4294967295, 'hi') +hello +select insert('hello', -4294967296, -4294967296, 'hi'); +insert('hello', -4294967296, -4294967296, 'hi') +hello +select insert('hello', 4294967296, 4294967296, 'hi'); +insert('hello', 4294967296, 4294967296, 'hi') +hello +select insert('hello', -4294967297, -4294967297, 'hi'); +insert('hello', -4294967297, -4294967297, 'hi') +hello +select insert('hello', 4294967297, 4294967297, 'hi'); +insert('hello', 4294967297, 4294967297, 'hi') +hello +select insert('hello', -18446744073709551615, -18446744073709551615, 'hi'); +insert('hello', -18446744073709551615, -18446744073709551615, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 18446744073709551615, 18446744073709551615, 'hi'); +insert('hello', 18446744073709551615, 18446744073709551615, 'hi') +hello +select insert('hello', -18446744073709551616, -18446744073709551616, 'hi'); +insert('hello', -18446744073709551616, -18446744073709551616, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 18446744073709551616, 18446744073709551616, 'hi'); +insert('hello', 18446744073709551616, 18446744073709551616, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', -18446744073709551617, -18446744073709551617, 'hi'); +insert('hello', -18446744073709551617, -18446744073709551617, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 18446744073709551617, 18446744073709551617, 'hi'); +insert('hello', 18446744073709551617, 18446744073709551617, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select repeat('hello', -1); +repeat('hello', -1) + +select repeat('hello', -4294967295); +repeat('hello', -4294967295) + +select repeat('hello', 4294967295); +repeat('hello', 4294967295) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select repeat('hello', -4294967296); +repeat('hello', -4294967296) + +select repeat('hello', 4294967296); +repeat('hello', 4294967296) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select repeat('hello', -4294967297); +repeat('hello', -4294967297) + +select repeat('hello', 4294967297); +repeat('hello', 4294967297) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select repeat('hello', -18446744073709551615); +repeat('hello', -18446744073709551615) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select repeat('hello', 18446744073709551615); +repeat('hello', 18446744073709551615) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select repeat('hello', -18446744073709551616); +repeat('hello', -18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select repeat('hello', 18446744073709551616); +repeat('hello', 18446744073709551616) +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select repeat('hello', -18446744073709551617); +repeat('hello', -18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select repeat('hello', 18446744073709551617); +repeat('hello', 18446744073709551617) +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select space(-1); +space(-1) + +select space(-4294967295); +space(-4294967295) + +select space(4294967295); +space(4294967295) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select space(-4294967296); +space(-4294967296) + +select space(4294967296); +space(4294967296) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select space(-4294967297); +space(-4294967297) + +select space(4294967297); +space(4294967297) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select space(-18446744073709551615); +space(-18446744073709551615) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select space(18446744073709551615); +space(18446744073709551615) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select space(-18446744073709551616); +space(-18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select space(18446744073709551616); +space(18446744073709551616) +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select space(-18446744073709551617); +space(-18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select space(18446744073709551617); +space(18446744073709551617) +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select rpad('hello', -1, '1'); +rpad('hello', -1, '1') +NULL +select rpad('hello', -4294967295, '1'); +rpad('hello', -4294967295, '1') +NULL +select rpad('hello', 4294967295, '1'); +rpad('hello', 4294967295, '1') +NULL +Warnings: +Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated +select rpad('hello', -4294967296, '1'); +rpad('hello', -4294967296, '1') +NULL +select rpad('hello', 4294967296, '1'); +rpad('hello', 4294967296, '1') +NULL +Warnings: +Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated +select rpad('hello', -4294967297, '1'); +rpad('hello', -4294967297, '1') +NULL +select rpad('hello', 4294967297, '1'); +rpad('hello', 4294967297, '1') +NULL +Warnings: +Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated +select rpad('hello', -18446744073709551615, '1'); +rpad('hello', -18446744073709551615, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select rpad('hello', 18446744073709551615, '1'); +rpad('hello', 18446744073709551615, '1') +NULL +Warnings: +Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated +select rpad('hello', -18446744073709551616, '1'); +rpad('hello', -18446744073709551616, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select rpad('hello', 18446744073709551616, '1'); +rpad('hello', 18446744073709551616, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated +select rpad('hello', -18446744073709551617, '1'); +rpad('hello', -18446744073709551617, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select rpad('hello', 18446744073709551617, '1'); +rpad('hello', 18446744073709551617, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated +select lpad('hello', -1, '1'); +lpad('hello', -1, '1') +NULL +select lpad('hello', -4294967295, '1'); +lpad('hello', -4294967295, '1') +NULL +select lpad('hello', 4294967295, '1'); +lpad('hello', 4294967295, '1') +NULL +Warnings: +Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated +select lpad('hello', -4294967296, '1'); +lpad('hello', -4294967296, '1') +NULL +select lpad('hello', 4294967296, '1'); +lpad('hello', 4294967296, '1') +NULL +Warnings: +Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated +select lpad('hello', -4294967297, '1'); +lpad('hello', -4294967297, '1') +NULL +select lpad('hello', 4294967297, '1'); +lpad('hello', 4294967297, '1') +NULL +Warnings: +Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated +select lpad('hello', -18446744073709551615, '1'); +lpad('hello', -18446744073709551615, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select lpad('hello', 18446744073709551615, '1'); +lpad('hello', 18446744073709551615, '1') +NULL +Warnings: +Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated +select lpad('hello', -18446744073709551616, '1'); +lpad('hello', -18446744073709551616, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select lpad('hello', 18446744073709551616, '1'); +lpad('hello', 18446744073709551616, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated +select lpad('hello', -18446744073709551617, '1'); +lpad('hello', -18446744073709551617, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select lpad('hello', 18446744073709551617, '1'); +lpad('hello', 18446744073709551617, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated End of 5.0 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 45415882ac7..9622de96143 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -780,4 +780,193 @@ SELECT * FROM t1 INNER JOIN t2 ON code=id DROP TABLE t1,t2; +# +# Bug #10963 +# 4294967296 18446744073709551616 + +select locate('he','hello',-2); +select locate('lo','hello',-4294967295); +select locate('lo','hello',4294967295); +select locate('lo','hello',-4294967296); +select locate('lo','hello',4294967296); +select locate('lo','hello',-4294967297); +select locate('lo','hello',4294967297); +select locate('lo','hello',-18446744073709551615); +select locate('lo','hello',18446744073709551615); +select locate('lo','hello',-18446744073709551616); +select locate('lo','hello',18446744073709551616); +select locate('lo','hello',-18446744073709551617); +select locate('lo','hello',18446744073709551617); + +select left('hello', 10); +select left('hello', 0); +select left('hello', -1); +select left('hello', -4294967295); +select left('hello', 4294967295); +select left('hello', -4294967296); +select left('hello', 4294967296); +select left('hello', -4294967297); +select left('hello', 4294967297); +select left('hello', -18446744073709551615); +select left('hello', 18446744073709551615); +select left('hello', -18446744073709551616); +select left('hello', 18446744073709551616); +select left('hello', -18446744073709551617); +select left('hello', 18446744073709551617); + +select right('hello', 10); +select right('hello', 0); +select right('hello', -1); +select right('hello', -4294967295); +select right('hello', 4294967295); +select right('hello', -4294967296); +select right('hello', 4294967296); +select right('hello', -4294967297); +select right('hello', 4294967297); +select right('hello', -18446744073709551615); +select right('hello', 18446744073709551615); +select right('hello', -18446744073709551616); +select right('hello', 18446744073709551616); +select right('hello', -18446744073709551617); +select right('hello', 18446744073709551617); + +select substring('hello', 2, -1); + +select substring('hello', -1, 1); +select substring('hello', -2, 1); +select substring('hello', -4294967295, 1); +select substring('hello', 4294967295, 1); +select substring('hello', -4294967296, 1); +select substring('hello', 4294967296, 1); +select substring('hello', -4294967297, 1); +select substring('hello', 4294967297, 1); +select substring('hello', -18446744073709551615, 1); +select substring('hello', 18446744073709551615, 1); +select substring('hello', -18446744073709551616, 1); +select substring('hello', 18446744073709551616, 1); +select substring('hello', -18446744073709551617, 1); +select substring('hello', 18446744073709551617, 1); +select substring('hello', 1, -1); +select substring('hello', 1, -4294967295); +select substring('hello', 1, 4294967295); +select substring('hello', 1, -4294967296); +select substring('hello', 1, 4294967296); +select substring('hello', 1, -4294967297); +select substring('hello', 1, 4294967297); +select substring('hello', 1, -18446744073709551615); +select substring('hello', 1, 18446744073709551615); +select substring('hello', 1, -18446744073709551616); +select substring('hello', 1, 18446744073709551616); +select substring('hello', 1, -18446744073709551617); +select substring('hello', 1, 18446744073709551617); +select substring('hello', -1, -1); +select substring('hello', -4294967295, -4294967295); +select substring('hello', 4294967295, 4294967295); +select substring('hello', -4294967296, -4294967296); +select substring('hello', 4294967296, 4294967296); +select substring('hello', -4294967297, -4294967297); +select substring('hello', 4294967297, 4294967297); +select substring('hello', -18446744073709551615, -18446744073709551615); +select substring('hello', 18446744073709551615, 18446744073709551615); +select substring('hello', -18446744073709551616, -18446744073709551616); +select substring('hello', 18446744073709551616, 18446744073709551616); +select substring('hello', -18446744073709551617, -18446744073709551617); +select substring('hello', 18446744073709551617, 18446744073709551617); + +select insert('hello', -1, 1, 'hi'); +select insert('hello', -4294967295, 1, 'hi'); +select insert('hello', 4294967295, 1, 'hi'); +select insert('hello', -4294967296, 1, 'hi'); +select insert('hello', 4294967296, 1, 'hi'); +select insert('hello', -4294967297, 1, 'hi'); +select insert('hello', 4294967297, 1, 'hi'); +select insert('hello', -18446744073709551615, 1, 'hi'); +select insert('hello', 18446744073709551615, 1, 'hi'); +select insert('hello', -18446744073709551616, 1, 'hi'); +select insert('hello', 18446744073709551616, 1, 'hi'); +select insert('hello', -18446744073709551617, 1, 'hi'); +select insert('hello', 18446744073709551617, 1, 'hi'); +select insert('hello', 1, -1, 'hi'); +select insert('hello', 1, -4294967295, 'hi'); +select insert('hello', 1, 4294967295, 'hi'); +select insert('hello', 1, -4294967296, 'hi'); +select insert('hello', 1, 4294967296, 'hi'); +select insert('hello', 1, -4294967297, 'hi'); +select insert('hello', 1, 4294967297, 'hi'); +select insert('hello', 1, -18446744073709551615, 'hi'); +select insert('hello', 1, 18446744073709551615, 'hi'); +select insert('hello', 1, -18446744073709551616, 'hi'); +select insert('hello', 1, 18446744073709551616, 'hi'); +select insert('hello', 1, -18446744073709551617, 'hi'); +select insert('hello', 1, 18446744073709551617, 'hi'); +select insert('hello', -1, -1, 'hi'); +select insert('hello', -4294967295, -4294967295, 'hi'); +select insert('hello', 4294967295, 4294967295, 'hi'); +select insert('hello', -4294967296, -4294967296, 'hi'); +select insert('hello', 4294967296, 4294967296, 'hi'); +select insert('hello', -4294967297, -4294967297, 'hi'); +select insert('hello', 4294967297, 4294967297, 'hi'); +select insert('hello', -18446744073709551615, -18446744073709551615, 'hi'); +select insert('hello', 18446744073709551615, 18446744073709551615, 'hi'); +select insert('hello', -18446744073709551616, -18446744073709551616, 'hi'); +select insert('hello', 18446744073709551616, 18446744073709551616, 'hi'); +select insert('hello', -18446744073709551617, -18446744073709551617, 'hi'); +select insert('hello', 18446744073709551617, 18446744073709551617, 'hi'); + +select repeat('hello', -1); +select repeat('hello', -4294967295); +select repeat('hello', 4294967295); +select repeat('hello', -4294967296); +select repeat('hello', 4294967296); +select repeat('hello', -4294967297); +select repeat('hello', 4294967297); +select repeat('hello', -18446744073709551615); +select repeat('hello', 18446744073709551615); +select repeat('hello', -18446744073709551616); +select repeat('hello', 18446744073709551616); +select repeat('hello', -18446744073709551617); +select repeat('hello', 18446744073709551617); + +select space(-1); +select space(-4294967295); +select space(4294967295); +select space(-4294967296); +select space(4294967296); +select space(-4294967297); +select space(4294967297); +select space(-18446744073709551615); +select space(18446744073709551615); +select space(-18446744073709551616); +select space(18446744073709551616); +select space(-18446744073709551617); +select space(18446744073709551617); + +select rpad('hello', -1, '1'); +select rpad('hello', -4294967295, '1'); +select rpad('hello', 4294967295, '1'); +select rpad('hello', -4294967296, '1'); +select rpad('hello', 4294967296, '1'); +select rpad('hello', -4294967297, '1'); +select rpad('hello', 4294967297, '1'); +select rpad('hello', -18446744073709551615, '1'); +select rpad('hello', 18446744073709551615, '1'); +select rpad('hello', -18446744073709551616, '1'); +select rpad('hello', 18446744073709551616, '1'); +select rpad('hello', -18446744073709551617, '1'); +select rpad('hello', 18446744073709551617, '1'); + +select lpad('hello', -1, '1'); +select lpad('hello', -4294967295, '1'); +select lpad('hello', 4294967295, '1'); +select lpad('hello', -4294967296, '1'); +select lpad('hello', 4294967296, '1'); +select lpad('hello', -4294967297, '1'); +select lpad('hello', 4294967297, '1'); +select lpad('hello', -18446744073709551615, '1'); +select lpad('hello', 18446744073709551615, '1'); +select lpad('hello', -18446744073709551616, '1'); +select lpad('hello', 18446744073709551616, '1'); +select lpad('hello', -18446744073709551617, '1'); +select lpad('hello', 18446744073709551617, '1'); + --echo End of 5.0 tests diff --git a/sql/item_func.cc b/sql/item_func.cc index ca71701841b..fa953889619 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2313,21 +2313,27 @@ longlong Item_func_locate::val_int() return 0; /* purecov: inspected */ } null_value=0; - uint start=0; - uint start0=0; + /* must be longlong to avoid truncation */ + longlong start= 0; + longlong start0= 0; my_match_t match; if (arg_count == 3) { - start0= start =(uint) args[2]->val_int()-1; - start=a->charpos(start); - - if (start > a->length() || start+b->length() > a->length()) + start0= start= args[2]->val_int() - 1; + + if ((start < 0) || (start > a->length())) + return 0; + + /* start is now sufficiently valid to pass to charpos function */ + start= a->charpos(start); + + if (start + b->length() > a->length()) return 0; } if (!b->length()) // Found empty string at start - return (longlong) (start+1); + return start + 1; if (!cmp_collation.collation->coll->instr(cmp_collation.collation, a->ptr()+start, a->length()-start, diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 4f3e280fc8a..c2f16ffac10 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -951,22 +951,33 @@ String *Item_func_insert::val_str(String *str) { DBUG_ASSERT(fixed == 1); String *res,*res2; - uint start,length; + longlong start, length; /* must be longlong to avoid truncation */ null_value=0; res=args[0]->val_str(str); res2=args[3]->val_str(&tmp_value); - start=(uint) args[1]->val_int()-1; - length=(uint) args[2]->val_int(); + start= args[1]->val_int() - 1; + length= args[2]->val_int(); + if (args[0]->null_value || args[1]->null_value || args[2]->null_value || args[3]->null_value) goto null; /* purecov: inspected */ - start=res->charpos(start); - length=res->charpos(length,start); - if (start > res->length()+1) - return res; // Wrong param; skip insert - if (length > res->length()-start) - length=res->length()-start; + + if ((start < 0) || (start > res->length() + 1)) + return res; // Wrong param; skip insert + if ((length < 0) || (length > res->length() + 1)) + length= res->length() + 1; + + /* start and length are now sufficiently valid to pass to charpos function */ + start= res->charpos(start); + length= res->charpos(length, start); + + /* Re-testing with corrected params */ + if (start > res->length() + 1) + return res; // Wrong param; skip insert + if (length > res->length() - start) + length= res->length() - start; + if (res->length() - length + res2->length() > current_thd->variables.max_allowed_packet) { @@ -1039,16 +1050,21 @@ String *Item_str_conv::val_str(String *str) String *Item_func_left::val_str(String *str) { DBUG_ASSERT(fixed == 1); - String *res =args[0]->val_str(str); - long length =(long) args[1]->val_int(); + String *res= args[0]->val_str(str); + + /* must be longlong to avoid truncation */ + longlong length= args[1]->val_int(); uint char_pos; if ((null_value=(args[0]->null_value || args[1]->null_value))) return 0; - if (length <= 0) + + /* if "unsigned_flag" is set, we have a *huge* positive number. */ + if ((length <= 0) && (!args[1]->unsigned_flag)) return &my_empty_string; - if (res->length() <= (uint) length || - res->length() <= (char_pos= res->charpos(length))) + + if ((res->length() <= (ulonglong) length) || + (res->length() <= (char_pos= res->charpos(length)))) return res; tmp_value.set(*res, 0, char_pos); @@ -1080,14 +1096,18 @@ void Item_func_left::fix_length_and_dec() String *Item_func_right::val_str(String *str) { DBUG_ASSERT(fixed == 1); - String *res =args[0]->val_str(str); - long length =(long) args[1]->val_int(); + String *res= args[0]->val_str(str); + /* must be longlong to avoid truncation */ + longlong length= args[1]->val_int(); if ((null_value=(args[0]->null_value || args[1]->null_value))) return 0; /* purecov: inspected */ - if (length <= 0) + + /* if "unsigned_flag" is set, we have a *huge* positive number. */ + if ((length <= 0) && (!args[1]->unsigned_flag)) return &my_empty_string; /* purecov: inspected */ - if (res->length() <= (uint) length) + + if (res->length() <= (ulonglong) length) return res; /* purecov: inspected */ uint start=res->numchars(); @@ -1110,25 +1130,43 @@ String *Item_func_substr::val_str(String *str) { DBUG_ASSERT(fixed == 1); String *res = args[0]->val_str(str); - int32 start = (int32) args[1]->val_int(); - int32 length = arg_count == 3 ? (int32) args[2]->val_int() : INT_MAX32; - int32 tmp_length; + /* must be longlong to avoid truncation */ + longlong start= args[1]->val_int(); + /* Assumes that the maximum length of a String is < INT_MAX32. */ + /* Limit so that code sees out-of-bound value properly. */ + longlong length= arg_count == 3 ? args[2]->val_int() : INT_MAX32; + longlong tmp_length; if ((null_value=(args[0]->null_value || args[1]->null_value || (arg_count == 3 && args[2]->null_value)))) return 0; /* purecov: inspected */ - start= (int32)((start < 0) ? res->numchars() + start : start -1); - start=res->charpos(start); - length=res->charpos(length,start); - if (start < 0 || (uint) start+1 > res->length() || length <= 0) + + /* Negative length, will return empty string. */ + if ((arg_count == 3) && (length <= 0) && !args[2]->unsigned_flag) return &my_empty_string; - tmp_length=(int32) res->length()-start; - length=min(length,tmp_length); + /* Assumes that the maximum length of a String is < INT_MAX32. */ + /* Set here so that rest of code sees out-of-bound value as such. */ + if ((length <= 0) || (length > INT_MAX32)) + length= INT_MAX32; - if (!start && res->length() == (uint) length) + /* if "unsigned_flag" is set, we have a *huge* positive number. */ + /* Assumes that the maximum length of a String is < INT_MAX32. */ + if ((args[1]->unsigned_flag) || (start < INT_MIN32) || (start > INT_MAX32)) + return &my_empty_string; + + start= ((start < 0) ? res->numchars() + start : start - 1); + start= res->charpos(start); + if ((start < 0) || ((uint) start + 1 > res->length())) + return &my_empty_string; + + length= res->charpos(length, start); + tmp_length= res->length() - start; + length= min(length, tmp_length); + + if (!start && res->length() == (ulonglong) length) return res; - tmp_value.set(*res,(uint) start,(uint) length); + tmp_value.set(*res, (ulonglong) start, (ulonglong) length); return &tmp_value; } @@ -2141,8 +2179,15 @@ void Item_func_repeat::fix_length_and_dec() collation.set(args[0]->collation); if (args[1]->const_item()) { - ulonglong max_result_length= ((ulonglong) args[0]->max_length * - args[1]->val_int()); + /* must be longlong to avoid truncation */ + longlong count= args[1]->val_int(); + + /* Assumes that the maximum length of a String is < INT_MAX32. */ + /* Set here so that rest of code sees out-of-bound value as such. */ + if (count > INT_MAX32) + count= INT_MAX32; + + ulonglong max_result_length= (ulonglong) args[0]->max_length * count; if (max_result_length >= MAX_BLOB_WIDTH) { max_result_length= MAX_BLOB_WIDTH; @@ -2167,13 +2212,20 @@ String *Item_func_repeat::val_str(String *str) DBUG_ASSERT(fixed == 1); uint length,tot_length; char *to; - long count= (long) args[1]->val_int(); - String *res =args[0]->val_str(str); + /* must be longlong to avoid truncation */ + longlong tmp_count= args[1]->val_int(); + long count= tmp_count; + String *res= args[0]->val_str(str); + + /* Assumes that the maximum length of a String is < INT_MAX32. */ + /* Bounds check on count: If this is triggered, we will error. */ + if ((tmp_count > INT_MAX32) || args[1]->unsigned_flag) + count= INT_MAX32; if (args[0]->null_value || args[1]->null_value) goto err; // string and/or delim are null - null_value=0; - if (count <= 0) // For nicer SQL code + null_value= 0; + if ((tmp_count <= 0) && !args[1]->unsigned_flag) // For nicer SQL code return &my_empty_string; if (count == 1) // To avoid reallocs return res; @@ -2212,8 +2264,20 @@ void Item_func_rpad::fix_length_and_dec() return; if (args[1]->const_item()) { - ulonglong length= ((ulonglong) args[1]->val_int() * - collation.collation->mbmaxlen); + ulonglong length= 0; + + if (collation.collation->mbmaxlen > 0) + { + ulonglong temp= (ulonglong) args[1]->val_int(); + + /* Assumes that the maximum length of a String is < INT_MAX32. */ + /* Set here so that rest of code sees out-of-bound value as such. */ + if (temp > INT_MAX32) + temp = INT_MAX32; + + length= temp * collation.collation->mbmaxlen; + } + if (length >= MAX_BLOB_WIDTH) { length= MAX_BLOB_WIDTH; @@ -2235,21 +2299,30 @@ String *Item_func_rpad::val_str(String *str) uint32 res_byte_length,res_char_length,pad_char_length,pad_byte_length; char *to; const char *ptr_pad; - int32 count= (int32) args[1]->val_int(); - int32 byte_count= count * collation.collation->mbmaxlen; - String *res =args[0]->val_str(str); - String *rpad = args[2]->val_str(&rpad_str); + /* must be longlong to avoid truncation */ + longlong count= args[1]->val_int(); + longlong byte_count; + String *res= args[0]->val_str(str); + String *rpad= args[2]->val_str(&rpad_str); + + /* Assumes that the maximum length of a String is < INT_MAX32. */ + /* Set here so that rest of code sees out-of-bound value as such. */ + if ((count > INT_MAX32) || args[1]->unsigned_flag) + count= INT_MAX32; if (!res || args[1]->null_value || !rpad || count < 0) goto err; null_value=0; - if (count <= (int32) (res_char_length=res->numchars())) + + if (count <= (res_char_length= res->numchars())) { // String to pad is big enough res->length(res->charpos(count)); // Shorten result if longer return (res); } pad_char_length= rpad->numchars(); - if ((ulong) byte_count > current_thd->variables.max_allowed_packet) + + byte_count= count * collation.collation->mbmaxlen; + if ((ulonglong) byte_count > current_thd->variables.max_allowed_packet) { push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_ALLOWED_PACKET_OVERFLOWED, @@ -2295,8 +2368,20 @@ void Item_func_lpad::fix_length_and_dec() if (args[1]->const_item()) { - ulonglong length= ((ulonglong) args[1]->val_int() * - collation.collation->mbmaxlen); + ulonglong length= 0; + + if (collation.collation->mbmaxlen > 0) + { + ulonglong temp= (ulonglong) args[1]->val_int(); + + /* Assumes that the maximum length of a String is < INT_MAX32. */ + /* Set here so that rest of code sees out-of-bound value as such. */ + if (temp > INT_MAX32) + temp= INT_MAX32; + + length= temp * collation.collation->mbmaxlen; + } + if (length >= MAX_BLOB_WIDTH) { length= MAX_BLOB_WIDTH; @@ -2316,13 +2401,19 @@ String *Item_func_lpad::val_str(String *str) { DBUG_ASSERT(fixed == 1); uint32 res_char_length,pad_char_length; - ulong count= (long) args[1]->val_int(), byte_count; + /* must be longlong to avoid truncation */ + longlong count= args[1]->val_int(); + longlong byte_count; String *res= args[0]->val_str(&tmp_value); String *pad= args[2]->val_str(&lpad_str); - if (!res || args[1]->null_value || !pad) - goto err; + /* Assumes that the maximum length of a String is < INT_MAX32. */ + /* Set here so that rest of code sees out-of-bound value as such. */ + if ((count > INT_MAX32) || args[1]->unsigned_flag) + count= INT_MAX32; + if (!res || args[1]->null_value || !pad || count < 0) + goto err; null_value=0; res_char_length= res->numchars();