From d5977e4c4472b2595c78575febdb8486bd7e07cc Mon Sep 17 00:00:00 2001 From: Timothy Smith Date: Tue, 24 Jun 2008 19:25:23 -0600 Subject: [PATCH 01/11] Bug #20748: Configuration files should not be read more than once Normalize directory names before adding them to default_directories. mysys/default.c: Normalize directory names with unpack_dirname() before adding them to default_directories. This way, /etc/ and /etc will not count as duplicates. Because this entails allocating memory to store the normalized names, add error handling and ensure that it doesn't leak memory in case both my_print_defaults() and load_defaults() are called. Clean up the Windows code that finds the exe's parent directory, and pull it out into a separate function. Reorganize the code into a single init_default_directories() function, with internal #ifdefs, instead of init_default_directories_() functions which were accessed via a function pointer. This is more in line with normal MySQL coding style, and easier to read for some. --- mysys/default.c | 298 ++++++++++++++++++++++-------------------------- 1 file changed, 136 insertions(+), 162 deletions(-) diff --git a/mysys/default.c b/mysys/default.c index e58903d6d64..eb7721acaed 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -48,13 +48,12 @@ char *my_defaults_extra_file=0; /* Which directories are searched for options (and in which order) */ #define MAX_DEFAULT_DIRS 6 -const char *default_directories[MAX_DEFAULT_DIRS + 1]; +#define DEFAULT_DIRS_SIZE (MAX_DEFAULT_DIRS + 1) /* Terminate with NULL */ +static const char **default_directories = NULL; #ifdef __WIN__ static const char *f_extensions[]= { ".ini", ".cnf", 0 }; #define NEWLINE "\r\n" -static char system_dir[FN_REFLEN], shared_system_dir[FN_REFLEN], - config_dir[FN_REFLEN]; #else static const char *f_extensions[]= { ".cnf", 0 }; #define NEWLINE "\n" @@ -85,19 +84,34 @@ static int search_default_file_with_ext(Process_option_func func, const char *config_file, int recursion_level); - /** Create the list of default directories. + @param alloc MEM_ROOT where the list of directories is stored + @details + The directories searched, in order, are: + - Windows: GetSystemWindowsDirectory() + - Windows: GetWindowsDirectory() + - Windows: C:/ + - Windows: Directory above where the executable is located + - Netware: sys:/etc/ + - Unix & OS/2: /etc/ + - Unix: --sysconfdir= (compile-time option) + - OS/2: getenv(ETC) + - ALL: getenv(DEFAULT_HOME_ENV) + - ALL: --defaults-extra-file= (run-time option) + - Unix: ~/ + On all systems, if a directory is already in the list, it will be moved to the end of the list. This avoids reading defaults files multiple times, while ensuring the correct precedence. - @return void + @retval NULL Failure (out of memory, probably) + @retval other Pointer to NULL-terminated array of default directories */ -static void (*init_default_directories)(); +static const char **init_default_directories(MEM_ROOT *alloc); static char *remove_end_comment(char *ptr); @@ -386,8 +400,9 @@ int load_defaults(const char *conf_file, const char **groups, struct handle_option_ctx ctx; DBUG_ENTER("load_defaults"); - init_default_directories(); init_alloc_root(&alloc,512,0); + if ((default_directories= init_default_directories(&alloc)) == NULL) + goto err; /* Check if the user doesn't want any default option processing --no-defaults is always the first option @@ -864,34 +879,49 @@ void my_print_default_files(const char *conf_file) my_bool have_ext= fn_ext(conf_file)[0] != 0; const char **exts_to_use= have_ext ? empty_list : f_extensions; char name[FN_REFLEN], **ext; - const char **dirs; - init_default_directories(); puts("\nDefault options are read from the following files in the given order:"); if (dirname_length(conf_file)) fputs(conf_file,stdout); else { - for (dirs=default_directories ; *dirs; dirs++) + /* + If default_directories is already initialized, use it. Otherwise, + use a private MEM_ROOT. + */ + const char **dirs = default_directories; + MEM_ROOT alloc; + init_alloc_root(&alloc,512,0); + + if (!dirs && (dirs= init_default_directories(&alloc)) == NULL) { - for (ext= (char**) exts_to_use; *ext; ext++) + fputs("Internal error initializing default directories list", stdout); + } + else + { + for ( ; *dirs; dirs++) { - const char *pos; - char *end; - if (**dirs) - pos= *dirs; - else if (my_defaults_extra_file) - pos= my_defaults_extra_file; - else - continue; - end= convert_dirname(name, pos, NullS); - if (name[0] == FN_HOMELIB) /* Add . to filenames in home */ - *end++='.'; - strxmov(end, conf_file, *ext, " ", NullS); - fputs(name,stdout); + for (ext= (char**) exts_to_use; *ext; ext++) + { + const char *pos; + char *end; + if (**dirs) + pos= *dirs; + else if (my_defaults_extra_file) + pos= my_defaults_extra_file; + else + continue; + end= convert_dirname(name, pos, NullS); + if (name[0] == FN_HOMELIB) /* Add . to filenames in home */ + *end++= '.'; + strxmov(end, conf_file, *ext, " ", NullS); + fputs(name, stdout); + } } } + + free_root(&alloc, MYF(0)); } puts(""); } @@ -928,32 +958,23 @@ void print_defaults(const char *conf_file, const char **groups) #include -/* - This extra complexity is to avoid declaring 'rc' if it won't be - used. -*/ -#define ADD_DIRECTORY_INTERNAL(DIR) \ - array_append_string_unique((DIR), default_directories, \ - array_elements(default_directories)) -#ifdef DBUG_OFF -# define ADD_DIRECTORY(DIR) (void) ADD_DIRECTORY_INTERNAL(DIR) -#else -#define ADD_DIRECTORY(DIR) \ - do { \ - my_bool rc= ADD_DIRECTORY_INTERNAL(DIR); \ - DBUG_ASSERT(rc == FALSE); /* Success */ \ - } while (0) -#endif +static int add_directory(MEM_ROOT *alloc, const char *dir, const char **dirs) +{ + char buf[FN_REFLEN]; + uint len; + char *p; + my_bool err __attribute__((unused)); + /* Normalize directory name */ + len= unpack_dirname(buf, dir); + if (!(p= strmake_root(alloc, buf, len))) + return 1; /* Failure */ + /* Should never fail if DEFAULT_DIRS_SIZE is correct size */ + err= array_append_string_unique(p, dirs, DEFAULT_DIRS_SIZE); + DBUG_ASSERT(err == FALSE); -#define ADD_COMMON_DIRECTORIES() \ - do { \ - char *env; \ - if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) \ - ADD_DIRECTORY(env); \ - /* Placeholder for --defaults-extra-file= */ \ - ADD_DIRECTORY(""); \ - } while (0) + return 0; +} #ifdef __WIN__ @@ -992,138 +1013,91 @@ static uint my_get_system_windows_directory(char *buffer, uint size) } -/** - Initialize default directories for Microsoft Windows - - @details - 1. GetSystemWindowsDirectory() - 2. GetWindowsDirectory() - 3. C:/ - 4. Directory above where the executable is located - 5. getenv(DEFAULT_HOME_ENV) - 6. --defaults-extra-file= (run-time option) -*/ - -static void init_default_directories_win() +static const char *my_get_module_parent(char *buf, size_t size) { - bzero((char *) default_directories, sizeof(default_directories)); + if (!GetModuleFileName(NULL, buf, size)) + return NULL; - if (my_get_system_windows_directory(shared_system_dir, - sizeof(shared_system_dir))) - ADD_DIRECTORY(shared_system_dir); - - if (GetWindowsDirectory(system_dir,sizeof(system_dir))) - ADD_DIRECTORY(system_dir); - - ADD_DIRECTORY("C:/"); - - if (GetModuleFileName(NULL, config_dir, sizeof(config_dir))) + char *last= NULL, *end= strend(buf); + /* + Look for the second-to-last \ in the filename, but hang on + to a pointer after the last \ in case we're in the root of + a drive. + */ + for ( ; end > buf; end--) { - char *last= NULL, *end= strend(config_dir); - /* - Look for the second-to-last \ in the filename, but hang on - to a pointer after the last \ in case we're in the root of - a drive. - */ - for ( ; end > config_dir; end--) + if (*end == FN_LIBCHAR) { - if (*end == FN_LIBCHAR) + if (last) { - if (last) - { - if (end != config_dir) - { - /* Keep the last '\' as this works both with D:\ and a directory */ - end[1]= 0; - } - else - { - /* No parent directory (strange). Use current dir + '\' */ - last[1]= 0; - } - break; - } - last= end; + /* Keep the last '\' as this works both with D:\ and a directory */ + end[1]= 0; + break; } + last= end; } - ADD_DIRECTORY(config_dir); } - ADD_COMMON_DIRECTORIES(); + return buf; } +#endif /* __WIN__ */ -static void (*init_default_directories)()= init_default_directories_win; + +static const char **init_default_directories(MEM_ROOT *alloc) +{ + const char **dirs; + char *env; + int errors= 0; + + dirs= (const char **)alloc_root(alloc, DEFAULT_DIRS_SIZE * sizeof(char *)); + if (dirs == NULL) + return NULL; + bzero((char *) dirs, DEFAULT_DIRS_SIZE * sizeof(char *)); + +#ifdef __WIN__ + + { + char fname_buffer[FN_REFLEN]; + if (my_get_system_windows_directory(fname_buffer, sizeof(fname_buffer))) + errors += add_directory(alloc, fname_buffer, dirs); + + if (GetWindowsDirectory(fname_buffer, sizeof(fname_buffer))) + errors += add_directory(alloc, fname_buffer, dirs); + + errors += add_directory(alloc, "C:/", dirs); + + if (my_get_module_parent(fname_buffer, sizeof(fname_buffer)) != NULL) + errors += add_directory(alloc, fname_buffer, dirs); + } #elif defined(__NETWARE__) -/** - Initialize default directories for Novell Netware - - @details - 1. sys:/etc/ - 2. getenv(DEFAULT_HOME_ENV) - 3. --defaults-extra-file= (run-time option) -*/ - -static void init_default_directories_netware() -{ - bzero((char *) default_directories, sizeof(default_directories)); - ADD_DIRECTORY("sys:/etc/"); - ADD_COMMON_DIRECTORIES(); -} - -static void (*init_default_directories)()= init_default_directories_netware; - -#elif defined(__EMX__) || defined(OS2) - -/** - Initialize default directories for OS/2 - - @details - 1. /etc/ - 2. getenv(ETC) - 3. getenv(DEFAULT_HOME_ENV) - 4. --defaults-extra-file= (run-time option) -*/ - -static void init_default_directories_os2() -{ - const char *env; - - bzero((char *) default_directories, sizeof(default_directories)); - ADD_DIRECTORY("/etc/"); - if ((env= getenv("ETC"))) - ADD_DIRECTORY(env); - ADD_COMMON_DIRECTORIES(); -} - -static void (*init_default_directories)()= init_default_directories_os2; + errors += add_directory(alloc, "sys:/etc/", dirs); #else -/** - Initialize default directories for Unix + errors += add_directory(alloc, "/etc/", dirs); - @details - 1. /etc/ - 2. --sysconfdir= (compile-time option) - 3. getenv(DEFAULT_HOME_ENV) - 4. --defaults-extra-file= (run-time option) - 5. "~/" -*/ - -static void init_default_directories_unix() -{ - bzero((char *) default_directories, sizeof(default_directories)); - ADD_DIRECTORY("/etc/"); -#ifdef DEFAULT_SYSCONFDIR +#if defined(__EMX__) || defined(OS2) + if ((env= getenv("ETC"))) + errors += add_directory(alloc, env, dirs); +#elif defined(DEFAULT_SYSCONFDIR) if (DEFAULT_SYSCONFDIR != "") - ADD_DIRECTORY(DEFAULT_SYSCONFDIR); + errors += add_directory(alloc, DEFAULT_SYSCONFDIR, dirs); +#endif /* __EMX__ || __OS2__ */ + #endif - ADD_COMMON_DIRECTORIES(); - ADD_DIRECTORY("~/"); + + if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) + errors += add_directory(alloc, env, dirs); + + /* Placeholder for --defaults-extra-file= */ + errors += add_directory(alloc, "", dirs); + +#if !defined(__WIN__) && !defined(__NETWARE__) && \ + !defined(__EMX__) && !defined(OS2) + errors += add_directory(alloc, "~/", dirs); +#endif + + return (errors > 0 ? NULL : dirs); } - -static void (*init_default_directories)()= init_default_directories_unix; - -#endif From b83b4697d229c78d85954b219cfed5caf428b20e Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Fri, 27 Jun 2008 20:56:41 +0500 Subject: [PATCH 02/11] backport from 6.0 Bug#35658 (An empty binary value leads to mysqld crash) Before this fix, the following token b'' caused the parser to crash when reading the binary value from the empty string. The crash was caused by: ptr+= max_length - 1; because max_length is unsigned and was 0, causing an overflow. With this fix, an empty binary literal b'' is parsed as a binary value 0, in Item_bin_string. mysql-test/r/varbinary.result: Bug#35658 (An empty binary value leads to mysqld crash) mysql-test/t/varbinary.test: Bug#35658 (An empty binary value leads to mysqld crash) sql/item.cc: Bug#35658 (An empty binary value leads to mysqld crash) --- mysql-test/r/varbinary.result | 31 +++++++++++++++++++++++++++++++ mysql-test/t/varbinary.test | 28 ++++++++++++++++++++++++++++ sql/item.cc | 29 ++++++++++++++++++----------- 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/varbinary.result b/mysql-test/r/varbinary.result index a41885a257d..f584c22f98a 100644 --- a/mysql-test/r/varbinary.result +++ b/mysql-test/r/varbinary.result @@ -78,3 +78,34 @@ alter table t1 modify a varchar(255); select length(a) from t1; length(a) 6 +select 0b01000001; +0b01000001 +A +select 0x41; +0x41 +A +select b'01000001'; +b'01000001' +A +select x'41', 0+x'41'; +x'41' 0+x'41' +A 65 +select N'abc', length(N'abc'); +abc length(N'abc') +abc 3 +select N'', length(N''); + length(N'') + 0 +select '', length(''); + length('') + 0 +select b'', 0+b''; +b'' 0+b'' + 0 +select x'', 0+x''; +x'' 0+x'' + 0 +select 0x; +ERROR 42S22: Unknown column '0x' in 'field list' +select 0b; +ERROR 42S22: Unknown column '0b' in 'field list' diff --git a/mysql-test/t/varbinary.test b/mysql-test/t/varbinary.test index 2f0c1c83e84..427c1a6b84a 100644 --- a/mysql-test/t/varbinary.test +++ b/mysql-test/t/varbinary.test @@ -84,3 +84,31 @@ select length(a) from t1; alter table t1 modify a varchar(255); select length(a) from t1; +# +# Bug#35658 (An empty binary value leads to mysqld crash) +# + +select 0b01000001; + +select 0x41; + +select b'01000001'; + +select x'41', 0+x'41'; + +select N'abc', length(N'abc'); + +select N'', length(N''); + +select '', length(''); + +select b'', 0+b''; + +select x'', 0+x''; + +--error ER_BAD_FIELD_ERROR +select 0x; + +--error ER_BAD_FIELD_ERROR +select 0b; + diff --git a/sql/item.cc b/sql/item.cc index 9ff1f8c0084..bf447581afa 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5013,21 +5013,28 @@ Item_bin_string::Item_bin_string(const char *str, uint str_length) if (!ptr) return; str_value.set(ptr, max_length, &my_charset_bin); - ptr+= max_length - 1; - ptr[1]= 0; // Set end null for string - for (; end >= str; end--) + + if (max_length > 0) { - if (power == 256) + ptr+= max_length - 1; + ptr[1]= 0; // Set end null for string + for (; end >= str; end--) { - power= 1; - *ptr--= bits; - bits= 0; + if (power == 256) + { + power= 1; + *ptr--= bits; + bits= 0; + } + if (*end == '1') + bits|= power; + power<<= 1; } - if (*end == '1') - bits|= power; - power<<= 1; + *ptr= (char) bits; } - *ptr= (char) bits; + else + ptr[0]= 0; + collation.set(&my_charset_bin, DERIVATION_COERCIBLE); fixed= 1; } From 9393ae3dff60d256cd9e5aa73134e0e38168df44 Mon Sep 17 00:00:00 2001 From: Patrick Crews Date: Tue, 1 Jul 2008 14:44:47 -0400 Subject: [PATCH 03/11] Bug#37380 - Test funcs_1.is_columns_myisam_embedded fails on OS X Test was failing due to the addition of a '\x05' character in result sets Latest builds of the server have shown this problem to have disappeared. Removing code within the test that disables the test on Mac OS X. Recommit due to tree error on earlier, approved patch. --- mysql-test/suite/funcs_1/t/is_columns_myisam_embedded.test | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mysql-test/suite/funcs_1/t/is_columns_myisam_embedded.test b/mysql-test/suite/funcs_1/t/is_columns_myisam_embedded.test index 0d5f1a72cdb..3d0cca24474 100644 --- a/mysql-test/suite/funcs_1/t/is_columns_myisam_embedded.test +++ b/mysql-test/suite/funcs_1/t/is_columns_myisam_embedded.test @@ -10,11 +10,6 @@ # 2008-06-06 mleich Create this this variant for the embedded server. # -let $value= query_get_value(SHOW VARIABLES LIKE 'version_compile_os',Value,1); -if (`SELECT '$value' LIKE 'apple-darwin%'`) -{ - skip Bug#37380 Test funcs_1.is_columns_myisam_embedded fails on OS X; -} if (`SELECT VERSION() NOT LIKE '%embedded%'`) { --skip Test requires: embedded server From 5647bce3668b46c5c74349520cefb2a791125e95 Mon Sep 17 00:00:00 2001 From: Timothy Smith Date: Wed, 2 Jul 2008 16:37:29 +0200 Subject: [PATCH 04/11] Fix "C++ code in C file" syntax error in mysys/default.c --- mysys/default.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mysys/default.c b/mysys/default.c index eb7721acaed..bf32261129b 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -1015,10 +1015,12 @@ static uint my_get_system_windows_directory(char *buffer, uint size) static const char *my_get_module_parent(char *buf, size_t size) { + char *last= NULL; + char *end; if (!GetModuleFileName(NULL, buf, size)) return NULL; + end= strend(buf); - char *last= NULL, *end= strend(buf); /* Look for the second-to-last \ in the filename, but hang on to a pointer after the last \ in case we're in the root of From ac2a037ff9664b48cc90811d33818523ee9fbffc Mon Sep 17 00:00:00 2001 From: Chad MILLER Date: Fri, 4 Jul 2008 12:41:27 -0400 Subject: [PATCH 05/11] Bug#30563: Is not possible to create rpl_ or innodb test if needed \ to use ANSI_QUOTES Make all have_* tests universally safe by using ANSI quotes. --- mysql-test/include/have_archive.inc | 2 +- mysql-test/include/have_bdb.inc | 2 +- mysql-test/include/have_big5.inc | 2 +- mysql-test/include/have_blackhole.inc | 2 +- mysql-test/include/have_case_sensitive_file_system.inc | 2 +- mysql-test/include/have_compress.inc | 2 +- mysql-test/include/have_cp1250_ch.inc | 2 +- mysql-test/include/have_cp932.inc | 2 +- mysql-test/include/have_crypt.inc | 2 +- mysql-test/include/have_csv.inc | 2 +- mysql-test/include/have_eucjpms.inc | 2 +- mysql-test/include/have_euckr.inc | 2 +- mysql-test/include/have_exampledb.inc | 2 +- mysql-test/include/have_federated_db.inc | 2 +- mysql-test/include/have_gb2312.inc | 2 +- mysql-test/include/have_gbk.inc | 2 +- mysql-test/include/have_geometry.inc | 2 +- mysql-test/include/have_innodb.inc | 2 +- mysql-test/include/have_latin2_ch.inc | 2 +- mysql-test/include/have_log_bin.inc | 2 +- mysql-test/include/have_lowercase0.inc | 2 +- mysql-test/include/have_multi_ndb.inc | 4 ++-- mysql-test/include/have_ndb.inc | 2 +- mysql-test/include/have_query_cache.inc | 2 +- mysql-test/include/have_sjis.inc | 2 +- mysql-test/include/have_ssl.inc | 2 +- mysql-test/include/have_tis620.inc | 2 +- mysql-test/include/have_ucs2.inc | 2 +- mysql-test/include/have_udf.inc | 2 +- mysql-test/include/have_ujis.inc | 2 +- 30 files changed, 31 insertions(+), 31 deletions(-) diff --git a/mysql-test/include/have_archive.inc b/mysql-test/include/have_archive.inc index 262f66076a8..75460316322 100644 --- a/mysql-test/include/have_archive.inc +++ b/mysql-test/include/have_archive.inc @@ -1,4 +1,4 @@ --require r/have_archive.require --disable_query_log -show variables like "have_archive"; +show variables like 'have_archive'; --enable_query_log diff --git a/mysql-test/include/have_bdb.inc b/mysql-test/include/have_bdb.inc index 3f7377e7515..c2f29e0d286 100644 --- a/mysql-test/include/have_bdb.inc +++ b/mysql-test/include/have_bdb.inc @@ -1,4 +1,4 @@ -- require r/have_bdb.require disable_query_log; -show variables like "have_bdb"; +show variables like 'have_bdb'; enable_query_log; diff --git a/mysql-test/include/have_big5.inc b/mysql-test/include/have_big5.inc index 790e8085e1a..dad4a0a8eeb 100644 --- a/mysql-test/include/have_big5.inc +++ b/mysql-test/include/have_big5.inc @@ -1,4 +1,4 @@ -- require r/have_big5.require disable_query_log; -show collation like "big5_chinese_ci"; +show collation like 'big5_chinese_ci'; enable_query_log; diff --git a/mysql-test/include/have_blackhole.inc b/mysql-test/include/have_blackhole.inc index c2b6ea18830..d13c9fda3f5 100644 --- a/mysql-test/include/have_blackhole.inc +++ b/mysql-test/include/have_blackhole.inc @@ -1,4 +1,4 @@ -- require r/have_blackhole.require disable_query_log; -show variables like "have_blackhole_engine"; +show variables like 'have_blackhole_engine'; enable_query_log; diff --git a/mysql-test/include/have_case_sensitive_file_system.inc b/mysql-test/include/have_case_sensitive_file_system.inc index 730af975497..7bb1bef93fd 100644 --- a/mysql-test/include/have_case_sensitive_file_system.inc +++ b/mysql-test/include/have_case_sensitive_file_system.inc @@ -1,4 +1,4 @@ --require r/case_sensitive_file_system.require --disable_query_log -show variables like "lower_case_file_system"; +show variables like 'lower_case_file_system'; --enable_query_log diff --git a/mysql-test/include/have_compress.inc b/mysql-test/include/have_compress.inc index c042cd7452a..150c7f3448d 100644 --- a/mysql-test/include/have_compress.inc +++ b/mysql-test/include/have_compress.inc @@ -1,4 +1,4 @@ -- require r/have_compress.require disable_query_log; -show variables like "have_compress"; +show variables like 'have_compress'; enable_query_log; diff --git a/mysql-test/include/have_cp1250_ch.inc b/mysql-test/include/have_cp1250_ch.inc index eec5d69fbd6..426fa658597 100644 --- a/mysql-test/include/have_cp1250_ch.inc +++ b/mysql-test/include/have_cp1250_ch.inc @@ -1,4 +1,4 @@ -- require r/have_cp1250_ch.require disable_query_log; -show collation like "cp1250_czech_cs"; +show collation like 'cp1250_czech_cs'; enable_query_log; diff --git a/mysql-test/include/have_cp932.inc b/mysql-test/include/have_cp932.inc index b500dac0bbe..ecad979c02a 100644 --- a/mysql-test/include/have_cp932.inc +++ b/mysql-test/include/have_cp932.inc @@ -1,4 +1,4 @@ -- require r/have_cp932.require disable_query_log; -show collation like "cp932_japanese_ci"; +show collation like 'cp932_japanese_ci'; enable_query_log; diff --git a/mysql-test/include/have_crypt.inc b/mysql-test/include/have_crypt.inc index fe1f974bffd..cbf0a7ac876 100644 --- a/mysql-test/include/have_crypt.inc +++ b/mysql-test/include/have_crypt.inc @@ -1,4 +1,4 @@ -- require r/have_crypt.require disable_query_log; -show variables like "have_crypt"; +show variables like 'have_crypt'; enable_query_log; diff --git a/mysql-test/include/have_csv.inc b/mysql-test/include/have_csv.inc index d28199831b8..12e69962486 100644 --- a/mysql-test/include/have_csv.inc +++ b/mysql-test/include/have_csv.inc @@ -1,4 +1,4 @@ -- require r/have_csv.require disable_query_log; -show variables like "have_csv"; +show variables like 'have_csv'; enable_query_log; diff --git a/mysql-test/include/have_eucjpms.inc b/mysql-test/include/have_eucjpms.inc index a5e1a5ac547..6d96eefcc31 100644 --- a/mysql-test/include/have_eucjpms.inc +++ b/mysql-test/include/have_eucjpms.inc @@ -1,4 +1,4 @@ -- require r/have_eucjpms.require disable_query_log; -show collation like "eucjpms_japanese_ci"; +show collation like 'eucjpms_japanese_ci'; enable_query_log; diff --git a/mysql-test/include/have_euckr.inc b/mysql-test/include/have_euckr.inc index af794aafc04..4b4e870cf47 100644 --- a/mysql-test/include/have_euckr.inc +++ b/mysql-test/include/have_euckr.inc @@ -1,4 +1,4 @@ -- require r/have_euckr.require disable_query_log; -show collation like "euckr_korean_ci"; +show collation like 'euckr_korean_ci'; enable_query_log; diff --git a/mysql-test/include/have_exampledb.inc b/mysql-test/include/have_exampledb.inc index 7ddd15c48b3..b8f9a24463e 100644 --- a/mysql-test/include/have_exampledb.inc +++ b/mysql-test/include/have_exampledb.inc @@ -1,4 +1,4 @@ -- require r/have_exampledb.require disable_query_log; -show variables like "have_example_engine"; +show variables like 'have_example_engine'; enable_query_log; diff --git a/mysql-test/include/have_federated_db.inc b/mysql-test/include/have_federated_db.inc index e4cf1366fda..4745534780d 100644 --- a/mysql-test/include/have_federated_db.inc +++ b/mysql-test/include/have_federated_db.inc @@ -1,4 +1,4 @@ -- require r/have_federated_db.require disable_query_log; -show variables like "have_federated_engine"; +show variables like 'have_federated_engine'; enable_query_log; diff --git a/mysql-test/include/have_gb2312.inc b/mysql-test/include/have_gb2312.inc index 4328bc67639..27591c01b6c 100644 --- a/mysql-test/include/have_gb2312.inc +++ b/mysql-test/include/have_gb2312.inc @@ -1,4 +1,4 @@ -- require r/have_gb2312.require disable_query_log; -show collation like "gb2312_chinese_ci"; +show collation like 'gb2312_chinese_ci'; enable_query_log; diff --git a/mysql-test/include/have_gbk.inc b/mysql-test/include/have_gbk.inc index 55805da0495..72252d6b00d 100644 --- a/mysql-test/include/have_gbk.inc +++ b/mysql-test/include/have_gbk.inc @@ -1,4 +1,4 @@ -- require r/have_gbk.require disable_query_log; -show collation like "gbk_chinese_ci"; +show collation like 'gbk_chinese_ci'; enable_query_log; diff --git a/mysql-test/include/have_geometry.inc b/mysql-test/include/have_geometry.inc index f0ec22af172..f1836469017 100644 --- a/mysql-test/include/have_geometry.inc +++ b/mysql-test/include/have_geometry.inc @@ -1,4 +1,4 @@ --require r/have_geometry.require --disable_query_log -show variables like "have_geometry"; +show variables like 'have_geometry'; --enable_query_log diff --git a/mysql-test/include/have_innodb.inc b/mysql-test/include/have_innodb.inc index 4f83d378cbc..4142b84813b 100644 --- a/mysql-test/include/have_innodb.inc +++ b/mysql-test/include/have_innodb.inc @@ -1,4 +1,4 @@ -- require r/have_innodb.require disable_query_log; -show variables like "have_innodb"; +show variables like 'have_innodb'; enable_query_log; diff --git a/mysql-test/include/have_latin2_ch.inc b/mysql-test/include/have_latin2_ch.inc index 9d3ee6b341c..215715a6aaf 100644 --- a/mysql-test/include/have_latin2_ch.inc +++ b/mysql-test/include/have_latin2_ch.inc @@ -1,4 +1,4 @@ -- require r/have_latin2_ch.require disable_query_log; -show collation like "latin2_czech_cs"; +show collation like 'latin2_czech_cs'; enable_query_log; diff --git a/mysql-test/include/have_log_bin.inc b/mysql-test/include/have_log_bin.inc index 11530dc953e..5bcdb30b3e0 100644 --- a/mysql-test/include/have_log_bin.inc +++ b/mysql-test/include/have_log_bin.inc @@ -1,4 +1,4 @@ -- require r/have_log_bin.require disable_query_log; -show variables like "log_bin"; +show variables like 'log_bin'; enable_query_log; diff --git a/mysql-test/include/have_lowercase0.inc b/mysql-test/include/have_lowercase0.inc index 8d3ae02f61e..6192acb7b01 100644 --- a/mysql-test/include/have_lowercase0.inc +++ b/mysql-test/include/have_lowercase0.inc @@ -1,4 +1,4 @@ --require r/lowercase0.require --disable_query_log -show variables like "lower_case_%"; +show variables like 'lower_case_%'; --enable_query_log diff --git a/mysql-test/include/have_multi_ndb.inc b/mysql-test/include/have_multi_ndb.inc index 45a551274f7..7f922d85ff2 100644 --- a/mysql-test/include/have_multi_ndb.inc +++ b/mysql-test/include/have_multi_ndb.inc @@ -10,7 +10,7 @@ drop table if exists t1, t2; --enable_warnings flush tables; --require r/have_ndb.require -show variables like "have_ndbcluster"; +show variables like 'have_ndbcluster'; enable_query_log; # Check that server2 has NDB support @@ -21,7 +21,7 @@ drop table if exists t1, t2; --enable_warnings flush tables; --require r/have_ndb.require -show variables like "have_ndbcluster"; +show variables like 'have_ndbcluster'; enable_query_log; # Set the default connection to 'server1' diff --git a/mysql-test/include/have_ndb.inc b/mysql-test/include/have_ndb.inc index 721d79392b7..691adc12231 100644 --- a/mysql-test/include/have_ndb.inc +++ b/mysql-test/include/have_ndb.inc @@ -1,7 +1,7 @@ # Check that server is compiled and started with support for NDB -- require r/have_ndb.require disable_query_log; -show variables like "have_ndbcluster"; +show variables like 'have_ndbcluster'; enable_query_log; # Check that NDB is installed and known to be working diff --git a/mysql-test/include/have_query_cache.inc b/mysql-test/include/have_query_cache.inc index 39549157849..647f8598ae6 100644 --- a/mysql-test/include/have_query_cache.inc +++ b/mysql-test/include/have_query_cache.inc @@ -3,5 +3,5 @@ # of query cache hits -- disable_ps_protocol disable_query_log; -show variables like "have_query_cache"; +show variables like 'have_query_cache'; enable_query_log; diff --git a/mysql-test/include/have_sjis.inc b/mysql-test/include/have_sjis.inc index 0d580a3a232..ac6531ca868 100644 --- a/mysql-test/include/have_sjis.inc +++ b/mysql-test/include/have_sjis.inc @@ -1,4 +1,4 @@ -- require r/have_sjis.require disable_query_log; -show collation like "sjis_japanese_ci"; +show collation like 'sjis_japanese_ci'; enable_query_log; diff --git a/mysql-test/include/have_ssl.inc b/mysql-test/include/have_ssl.inc index fab57d630e5..6f2d5587a75 100644 --- a/mysql-test/include/have_ssl.inc +++ b/mysql-test/include/have_ssl.inc @@ -1,4 +1,4 @@ -- require r/have_ssl.require disable_query_log; -show variables like "have_ssl"; +show variables like 'have_ssl'; enable_query_log; diff --git a/mysql-test/include/have_tis620.inc b/mysql-test/include/have_tis620.inc index c1e775681b0..ad5ba9dea69 100644 --- a/mysql-test/include/have_tis620.inc +++ b/mysql-test/include/have_tis620.inc @@ -1,4 +1,4 @@ -- require r/have_tis620.require disable_query_log; -show collation like "tis620_thai_ci"; +show collation like 'tis620_thai_ci'; enable_query_log; diff --git a/mysql-test/include/have_ucs2.inc b/mysql-test/include/have_ucs2.inc index 92ec9b5fb44..324ed52dd02 100644 --- a/mysql-test/include/have_ucs2.inc +++ b/mysql-test/include/have_ucs2.inc @@ -1,4 +1,4 @@ -- require r/have_ucs2.require disable_query_log; -show collation like "ucs2_general_ci"; +show collation like 'ucs2_general_ci'; enable_query_log; diff --git a/mysql-test/include/have_udf.inc b/mysql-test/include/have_udf.inc index 42b9942f74d..154dccf2270 100644 --- a/mysql-test/include/have_udf.inc +++ b/mysql-test/include/have_udf.inc @@ -4,7 +4,7 @@ # --require r/have_udf.require disable_query_log; -show variables like "have_dynamic_loading"; +show variables like 'have_dynamic_loading'; enable_query_log; # diff --git a/mysql-test/include/have_ujis.inc b/mysql-test/include/have_ujis.inc index ecceb7a8408..e4b2f50cf93 100644 --- a/mysql-test/include/have_ujis.inc +++ b/mysql-test/include/have_ujis.inc @@ -1,4 +1,4 @@ -- require r/have_ujis.require disable_query_log; -show collation like "ujis_japanese_ci"; +show collation like 'ujis_japanese_ci'; enable_query_log; From 914cae3a2d48187ba566fb95342df4df10ecba48 Mon Sep 17 00:00:00 2001 From: Mats Kindahl Date: Mon, 7 Jul 2008 09:58:27 +0200 Subject: [PATCH 06/11] Bug #37150 Risk for crash in User_var_log_event::exec_event() On certain kinds of errors (e.g., out of stack), a call to Item_func_ set_user_var::fix_fields() might fail. Since the return value of this call was not checked inside User_var_log_event::exec_event(), continuing execution after this will cause a crash inside Item_func_set_user_var:: update_hash(). The bug is fixed by aborting execution of the event with an error if fix_fields() fails, since it is not possible to continue execution anyway. sql/log_event.cc: Aborting execution of event if fix_fields() fails since execution of update_hash() might cause a crash. --- sql/log_event.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 05dccd782ad..ef419aaee40 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4154,8 +4154,14 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) /* Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) + + Fix_fields() can fail, in which case a call of update_hash() might + crash the server, so if fix fields fails, we just return with an + error. */ - e.fix_fields(thd, 0); + if (e.fix_fields(thd, 0)) + return 1; + /* A variable can just be considered as a table with a single record and with a single column. Thus, like From c7724872d85cebf07df3380757cf7259f9116682 Mon Sep 17 00:00:00 2001 From: Marc Alff Date: Mon, 7 Jul 2008 10:00:08 -0600 Subject: [PATCH 07/11] Bug#26030 (Parsing fails for stored routine w/multi-statement execution enabled) Before this fix, the lexer and parser would treat the ';' character as a different token (either ';' or END_OF_INPUT), based on convoluted logic, which failed in simple cases where a stored procedure is implemented as a single statement, and used in a multi query. With this fix: - the character ';' is always parsed as a ';' token in the lexer, - parsing multi queries is implemented in the parser, in the 'query:' rules, - the value of thd->client_capabilities, which is the capabilities negotiated between the client and the server during bootstrap, is immutable and not arbitrarily modified during parsing (which was the root cause of the bug) --- mysql-test/r/comments.result | 2 +- mysql-test/r/parser.result | 68 ++++++++++++++++++++++++++ mysql-test/r/ps.result | 4 +- mysql-test/t/parser.test | 59 +++++++++++++++++++++++ sql/sp_head.h | 1 - sql/sql_lex.cc | 19 ++------ sql/sql_parse.cc | 5 ++ sql/sql_yacc.yy | 93 +++++++++++++++++++----------------- 8 files changed, 186 insertions(+), 65 deletions(-) create mode 100644 mysql-test/r/parser.result create mode 100644 mysql-test/t/parser.test diff --git a/mysql-test/r/comments.result b/mysql-test/r/comments.result index 1040c3fc8e9..b9d0028dc7c 100644 --- a/mysql-test/r/comments.result +++ b/mysql-test/r/comments.result @@ -35,7 +35,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*! AND 2=2;"; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*! AND 2=2;*"; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ';*' at line 1 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '*' at line 1 prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*!98765' AND b = 'bar';"; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '/*!98765' AND b = 'bar'' at line 1 prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*!98765' AND b = 'bar';*"; diff --git a/mysql-test/r/parser.result b/mysql-test/r/parser.result new file mode 100644 index 00000000000..18391bd2a45 --- /dev/null +++ b/mysql-test/r/parser.result @@ -0,0 +1,68 @@ +DROP PROCEDURE IF EXISTS p26030; +select "non terminated"$$ +non terminated +non terminated +select "terminated";$$ +terminated +terminated +select "non terminated, space" $$ +non terminated, space +non terminated, space +select "terminated, space"; $$ +terminated, space +terminated, space +select "non terminated, comment" /* comment */$$ +non terminated, comment +non terminated, comment +select "terminated, comment"; /* comment */$$ +terminated, comment +terminated, comment +select "stmt 1";select "stmt 2 non terminated"$$ +stmt 1 +stmt 1 +stmt 2 non terminated +stmt 2 non terminated +select "stmt 1";select "stmt 2 terminated";$$ +stmt 1 +stmt 1 +stmt 2 terminated +stmt 2 terminated +select "stmt 1";select "stmt 2 non terminated, space" $$ +stmt 1 +stmt 1 +stmt 2 non terminated, space +stmt 2 non terminated, space +select "stmt 1";select "stmt 2 terminated, space"; $$ +stmt 1 +stmt 1 +stmt 2 terminated, space +stmt 2 terminated, space +select "stmt 1";select "stmt 2 non terminated, comment" /* comment */$$ +stmt 1 +stmt 1 +stmt 2 non terminated, comment +stmt 2 non terminated, comment +select "stmt 1";select "stmt 2 terminated, comment"; /* comment */$$ +stmt 1 +stmt 1 +stmt 2 terminated, comment +stmt 2 terminated, comment +select "stmt 1"; select "space, stmt 2"$$ +stmt 1 +stmt 1 +space, stmt 2 +space, stmt 2 +select "stmt 1";/* comment */select "comment, stmt 2"$$ +stmt 1 +stmt 1 +comment, stmt 2 +comment, stmt 2 +DROP PROCEDURE IF EXISTS p26030; CREATE PROCEDURE p26030() BEGIN SELECT 1; END; CALL p26030() +$$ +1 +1 +DROP PROCEDURE IF EXISTS p26030; CREATE PROCEDURE p26030() SELECT 1; CALL p26030() +$$ +1 +1 +DROP PROCEDURE p26030; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 9aef58d5702..09deaf2f322 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -85,9 +85,9 @@ NULL NULL NULL prepare stmt6 from 'select 1; select2'; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; select2' at line 1 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select2' at line 1 prepare stmt6 from 'insert into t1 values (5,"five"); select2'; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; select2' at line 1 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select2' at line 1 explain prepare stmt6 from 'insert into t1 values (5,"five"); select2'; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from 'insert into t1 values (5,"five"); select2'' at line 1 create table t2 diff --git a/mysql-test/t/parser.test b/mysql-test/t/parser.test new file mode 100644 index 00000000000..02fe98dc7b2 --- /dev/null +++ b/mysql-test/t/parser.test @@ -0,0 +1,59 @@ +# +# This file contains tests covering the parser +# + +#============================================================================= +# LEXICAL PARSER (lex) +#============================================================================= + +# +# Maintainer: these tests are for the lexical parser, so every character, +# even whitespace or comments, is significant here. +# + +# +# Bug#26030 (Parsing fails for stored routine w/multi-statement execution +# enabled) +# + +--disable_warnings +DROP PROCEDURE IF EXISTS p26030; +--enable_warnings + +delimiter $$; + +select "non terminated"$$ +select "terminated";$$ +select "non terminated, space" $$ +select "terminated, space"; $$ +select "non terminated, comment" /* comment */$$ +select "terminated, comment"; /* comment */$$ + +# Multi queries can not be used in --ps-protocol test mode +--disable_ps_protocol + +select "stmt 1";select "stmt 2 non terminated"$$ +select "stmt 1";select "stmt 2 terminated";$$ +select "stmt 1";select "stmt 2 non terminated, space" $$ +select "stmt 1";select "stmt 2 terminated, space"; $$ +select "stmt 1";select "stmt 2 non terminated, comment" /* comment */$$ +select "stmt 1";select "stmt 2 terminated, comment"; /* comment */$$ + +select "stmt 1"; select "space, stmt 2"$$ +select "stmt 1";/* comment */select "comment, stmt 2"$$ + +DROP PROCEDURE IF EXISTS p26030; CREATE PROCEDURE p26030() BEGIN SELECT 1; END; CALL p26030() +$$ + +DROP PROCEDURE IF EXISTS p26030; CREATE PROCEDURE p26030() SELECT 1; CALL p26030() +$$ + +--enable_ps_protocol + +delimiter ;$$ +DROP PROCEDURE p26030; + +#============================================================================r +# SYNTACTIC PARSER (bison) +#============================================================================= + diff --git a/sql/sp_head.h b/sql/sp_head.h index 11ff7160c03..91f465a4e2a 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -117,7 +117,6 @@ public: create_field m_return_field_def; /* This is used for FUNCTIONs only. */ const char *m_tmp_query; // Temporary pointer to sub query string - uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value st_sp_chistics *m_chistics; ulong m_sql_mode; // For SHOW CREATE and execution LEX_STRING m_qname; // db.name diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 6bfcd982b04..a1bfc3edc6c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1010,21 +1010,8 @@ int MYSQLlex(void *arg, void *yythd) yySkip(); return (SET_VAR); case MY_LEX_SEMICOLON: // optional line terminator - if (yyPeek()) - { - if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) && - !lip->stmt_prepare_mode) - { - lex->safe_to_cache_query= 0; - lip->found_semicolon= lip->ptr; - thd->server_status|= SERVER_MORE_RESULTS_EXISTS; - lip->next_state= MY_LEX_END; - return (END_OF_INPUT); - } - state= MY_LEX_CHAR; // Return ';' - break; - } - /* fall true */ + state= MY_LEX_CHAR; // Return ';' + break; case MY_LEX_EOL: if (lip->ptr >= lip->end_of_query) { @@ -1039,7 +1026,7 @@ int MYSQLlex(void *arg, void *yythd) case MY_LEX_END: lip->next_state=MY_LEX_END; return(0); // We found end of input last time - + /* Actually real shouldn't start with . but allow them anyhow */ case MY_LEX_REAL_OR_POINT: if (my_isdigit(cs,yyPeek())) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 98e04e45bdd..62a5a79a833 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6169,6 +6169,11 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, (thd->query_length= (ulong)(lip.found_semicolon - thd->query))) thd->query_length--; /* Actually execute the query */ + if (*found_semicolon) + { + lex->safe_to_cache_query= 0; + thd->server_status|= SERVER_MORE_RESULTS_EXISTS; + } lex->set_trg_event_type_for_tables(); mysql_execute_command(thd); query_cache_end_of_result(thd); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ffc84bde9c1..090585392a0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1203,21 +1203,54 @@ END_OF_INPUT query: - END_OF_INPUT - { - THD *thd= YYTHD; - if (!thd->bootstrap && - (!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT))) - { - my_message(ER_EMPTY_QUERY, ER(ER_EMPTY_QUERY), MYF(0)); - MYSQL_YYABORT; - } - else - { - thd->lex->sql_command= SQLCOM_EMPTY_QUERY; - } - } - | verb_clause END_OF_INPUT {}; + END_OF_INPUT + { + THD *thd= YYTHD; + if (!thd->bootstrap && + (!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT))) + { + my_message(ER_EMPTY_QUERY, ER(ER_EMPTY_QUERY), MYF(0)); + MYSQL_YYABORT; + } + thd->lex->sql_command= SQLCOM_EMPTY_QUERY; + thd->m_lip->found_semicolon= NULL; + } + | verb_clause + { + Lex_input_stream *lip = YYTHD->m_lip; + + if ((YYTHD->client_capabilities & CLIENT_MULTI_QUERIES) && + ! lip->stmt_prepare_mode && + ! (lip->ptr >= lip->end_of_query)) + { + /* + We found a well formed query, and multi queries are allowed: + - force the parser to stop after the ';' + - mark the start of the next query for the next invocation + of the parser. + */ + lip->next_state= MY_LEX_END; + lip->found_semicolon= lip->ptr; + } + else + { + /* Single query, terminated. */ + lip->found_semicolon= NULL; + } + } + ';' + opt_end_of_input + | verb_clause END_OF_INPUT + { + /* Single query, not terminated. */ + YYTHD->m_lip->found_semicolon= NULL; + } + ; + +opt_end_of_input: + /* empty */ + | END_OF_INPUT + ; verb_clause: statement @@ -9867,13 +9900,6 @@ trigger_tail: lex->sphead= sp; lex->spname= $3; - /* - We have to turn of CLIENT_MULTI_QUERIES while parsing a - stored procedure, otherwise yylex will chop it into pieces - at each ';'. - */ - sp->m_old_cmq= thd->client_capabilities & CLIENT_MULTI_QUERIES; - thd->client_capabilities &= ~CLIENT_MULTI_QUERIES; bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); lex->sphead->m_chistics= &lex->sp_chistics; @@ -9888,9 +9914,6 @@ trigger_tail: lex->sql_command= SQLCOM_CREATE_TRIGGER; sp->init_strings(YYTHD, lex); - /* Restore flag if it was cleared above */ - if (sp->m_old_cmq) - YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; sp->restore_thd_mem_root(YYTHD); if (sp->is_not_allowed_in_function("trigger")) @@ -9968,13 +9991,6 @@ sf_tail: sp->m_type= TYPE_ENUM_FUNCTION; lex->sphead= sp; - /* - * We have to turn of CLIENT_MULTI_QUERIES while parsing a - * stored procedure, otherwise yylex will chop it into pieces - * at each ';'. - */ - sp->m_old_cmq= thd->client_capabilities & CLIENT_MULTI_QUERIES; - thd->client_capabilities &= ~CLIENT_MULTI_QUERIES; lex->sphead->m_param_begin= lip->tok_start+1; } sp_fdparam_list /* $6 */ @@ -10030,9 +10046,6 @@ sf_tail: my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str); MYSQL_YYABORT; } - /* Restore flag if it was cleared above */ - if (sp->m_old_cmq) - YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; sp->restore_thd_mem_root(YYTHD); } ; @@ -10062,13 +10075,6 @@ sp_tail: sp->init_sp_name(YYTHD, $3); lex->sphead= sp; - /* - * We have to turn of CLIENT_MULTI_QUERIES while parsing a - * stored procedure, otherwise yylex will chop it into pieces - * at each ';'. - */ - sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; - YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES); } '(' { @@ -10104,9 +10110,6 @@ sp_tail: sp->init_strings(YYTHD, lex); lex->sql_command= SQLCOM_CREATE_PROCEDURE; - /* Restore flag if it was cleared above */ - if (sp->m_old_cmq) - YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; sp->restore_thd_mem_root(YYTHD); } ; From a81572bc425727bda467f69ee5a5e2349c5144bb Mon Sep 17 00:00:00 2001 From: Matthias Leich Date: Wed, 9 Jul 2008 13:22:07 +0200 Subject: [PATCH 08/11] 1. Fix for Bug#37160 "funcs_2: The tests do not check if optional character sets exist." 2. Minor cleanup --- .../suite/funcs_2/charset/charset_master.test | 90 ++++++++++++++++++- .../suite/funcs_2/t/innodb_charset.test | 12 +-- .../suite/funcs_2/t/memory_charset.test | 12 +-- .../suite/funcs_2/t/myisam_charset.test | 12 +-- mysql-test/suite/funcs_2/t/ndb_charset.test | 12 +-- 5 files changed, 114 insertions(+), 24 deletions(-) diff --git a/mysql-test/suite/funcs_2/charset/charset_master.test b/mysql-test/suite/funcs_2/charset/charset_master.test index a241e62f0f4..09e24e2c246 100644 --- a/mysql-test/suite/funcs_2/charset/charset_master.test +++ b/mysql-test/suite/funcs_2/charset/charset_master.test @@ -1,14 +1,96 @@ ################################################################################# -# Author: Serge Kozlov # -# Date: 09/21/2005 # -# Purpose: used by ../t/*_charset.test # -# Require: set $engine_type= [NDB,MyISAM,InnoDB,etc] before calling # +# Author: Serge Kozlov # +# Date: 2005-09-21 # +# Purpose: used by ../t/*_charset.test # +# Require: set $engine_type= [NDB,MyISAM,InnoDB,etc] before calling # +# # +# Last modification: Matthias Leich # +# Date: 2008-07-02 # +# Purpose: Fix Bug#37160 funcs_2: The tests do not check if optional character # +# sets exist. # +# Add checking of prerequisites + minor cleanup # ################################################################################# # # # +# Check that all character sets needed are available +# Note(mleich): +# It is intentional that the common solution with +# "--source include/have_.inc" +# is not applied. +# - We currently do not have such a prerequisite test for every character set +# /collation needed. +# - There is also no real value in mentioning the first missing character set +# /collation within the "skip message" because it is most probably only +# one of many. +# +# Hint: 5 character_set_names per source line if possible +if (`SELECT COUNT(*) <> 36 FROM information_schema.character_sets + WHERE CHARACTER_SET_NAME IN ( + 'armscii8', 'ascii' , 'big5' , 'binary' , 'cp1250', + 'cp1251' , 'cp1256' , 'cp1257' , 'cp850' , 'cp852' , + 'cp866' , 'cp932' , 'dec8' , 'eucjpms', 'euckr' , + 'gb2312' , 'gbk' , 'geostd8', 'greek' , 'hebrew', + 'hp8' , 'keybcs2', 'koi8r' , 'koi8u' , 'latin1', + 'latin2' , 'latin5' , 'latin7' , 'macce' , 'macroman', + 'sjis' , 'swe7' , 'tis620' , 'ucs2' , 'ujis', + 'utf8' + )`) +{ + --skip Not all character sets required for this test are present +} +# Check that all collations needed are available +# Hint: 4 collation_names per source line if possible +if (`SELECT COUNT(*) <> 123 FROM information_schema.collations +WHERE collation_name IN ( +'armscii8_bin', 'armscii8_general_ci', 'ascii_bin', 'ascii_general_ci', +'big5_bin', 'big5_chinese_ci', 'cp1250_bin', 'cp1250_croatian_ci', +'cp1250_czech_cs', 'cp1250_general_ci', 'cp1251_bin', 'cp1251_bulgarian_ci', +'cp1251_general_ci', 'cp1251_general_cs', 'cp1251_ukrainian_ci', 'cp1256_bin', +'cp1256_general_ci', 'cp1257_bin', 'cp1257_general_ci', 'cp1257_lithuanian_ci', +'cp850_bin', 'cp850_general_ci', 'cp852_bin', 'cp852_general_ci', +'cp866_bin', 'cp866_general_ci', 'cp932_bin', 'cp932_japanese_ci', +'dec8_bin', 'dec8_swedish_ci', 'eucjpms_bin', 'eucjpms_japanese_ci', +'euckr_bin', 'euckr_korean_ci', 'gb2312_bin', 'gb2312_chinese_ci', +'gbk_bin', 'gbk_chinese_ci', 'geostd8_bin', 'geostd8_general_ci', +'greek_bin', 'greek_general_ci', 'hebrew_bin', 'hebrew_general_ci', +'hp8_bin', 'hp8_english_ci', 'keybcs2_bin', 'keybcs2_general_ci', +'koi8r_bin', 'koi8r_general_ci', 'koi8u_bin', 'koi8u_general_ci', +'latin1_bin', 'latin1_danish_ci', 'latin1_general_ci', 'latin1_general_cs', +'latin1_german1_ci', 'latin1_german2_ci', 'latin1_spanish_ci', 'latin1_swedish_ci', +'latin2_bin', 'latin2_croatian_ci', 'latin2_czech_cs', 'latin2_general_ci', +'latin2_hungarian_ci', 'latin5_bin', 'latin5_turkish_ci', 'latin7_bin', +'latin7_estonian_cs', 'latin7_general_ci', 'latin7_general_cs', 'macce_bin', +'macce_general_ci', 'macroman_bin', 'macroman_general_ci', 'sjis_bin', +'sjis_japanese_ci', 'swe7_bin', 'swe7_swedish_ci', 'tis620_bin', +'tis620_thai_ci', 'ucs2_bin', 'ucs2_czech_ci', 'ucs2_danish_ci', +'ucs2_estonian_ci', 'ucs2_general_ci', 'ucs2_hungarian_ci', 'ucs2_icelandic_ci', +'ucs2_latvian_ci', 'ucs2_lithuanian_ci', 'ucs2_persian_ci', 'ucs2_polish_ci', +'ucs2_roman_ci', 'ucs2_romanian_ci', 'ucs2_slovak_ci', 'ucs2_slovenian_ci', +'ucs2_spanish2_ci', 'ucs2_spanish_ci', 'ucs2_swedish_ci', 'ucs2_turkish_ci', +'ucs2_unicode_ci', 'ujis_bin', 'ujis_japanese_ci', 'utf8_bin', +'utf8_czech_ci', 'utf8_danish_ci', 'utf8_estonian_ci', 'utf8_general_ci', +'utf8_hungarian_ci', 'utf8_icelandic_ci', 'utf8_latvian_ci', 'utf8_lithuanian_ci', +'utf8_persian_ci', 'utf8_polish_ci', 'utf8_roman_ci', 'utf8_romanian_ci', +'utf8_slovak_ci', 'utf8_slovenian_ci', 'utf8_spanish2_ci', 'utf8_spanish_ci', +'utf8_swedish_ci', 'utf8_turkish_ci', 'utf8_unicode_ci' +)`) +{ + --skip Not all collations required for this test are present +} + +################################ +let $check_std_csets= 1; +let $check_ucs2_csets= 1; +let $check_utf8_csets= 1; + +# +# Check all charsets/collation combinations +# + +################################ let $check_std_csets= 1; let $check_ucs2_csets= 1; let $check_utf8_csets= 1; diff --git a/mysql-test/suite/funcs_2/t/innodb_charset.test b/mysql-test/suite/funcs_2/t/innodb_charset.test index 5d4a72cfa2e..b77bacfc01c 100644 --- a/mysql-test/suite/funcs_2/t/innodb_charset.test +++ b/mysql-test/suite/funcs_2/t/innodb_charset.test @@ -1,8 +1,10 @@ -################################################################################# -# Author: Serge Kozlov # -# Date: 09/21/2005 # -# Purpose: Testing the charsets for InnoDB engine # -################################################################################# +################################################################################ +# Author: Serge Kozlov # +# Date: 2005-09-21 # +# Purpose: Testing the charsets for InnoDB engine # +# # +# Checking of other prerequisites is in charset_master.test # +################################################################################ --source include/have_innodb.inc diff --git a/mysql-test/suite/funcs_2/t/memory_charset.test b/mysql-test/suite/funcs_2/t/memory_charset.test index ce9b80462f1..cc878652bfa 100644 --- a/mysql-test/suite/funcs_2/t/memory_charset.test +++ b/mysql-test/suite/funcs_2/t/memory_charset.test @@ -1,8 +1,10 @@ -################################################################################# -# Author: Serge Kozlov # -# Date: 09/21/2005 # -# Purpose: Testing the charsets for Memory engine # -################################################################################# +################################################################################ +# Author: Serge Kozlov # +# Date: 2005-09-21 # +# Purpose: Testing the charsets for Memory engine # +# # +# Checking of other prerequisites is in charset_master.test # +################################################################################ let $engine_type= Memory; --source suite/funcs_2/charset/charset_master.test diff --git a/mysql-test/suite/funcs_2/t/myisam_charset.test b/mysql-test/suite/funcs_2/t/myisam_charset.test index b3f862c89de..e9a62e1060b 100644 --- a/mysql-test/suite/funcs_2/t/myisam_charset.test +++ b/mysql-test/suite/funcs_2/t/myisam_charset.test @@ -1,8 +1,10 @@ -################################################################################# -# Author: Serge Kozlov # -# Date: 09/21/2005 # -# Purpose: Testing the charsets for MyISAM engine # -################################################################################# +################################################################################ +# Author: Serge Kozlov # +# Date: 2005-09-21 # +# Purpose: Testing the charsets for MyISAM engine # +# # +# Checking of other prerequisites is in charset_master.test # +################################################################################ let $engine_type= MyISAM; --source suite/funcs_2/charset/charset_master.test diff --git a/mysql-test/suite/funcs_2/t/ndb_charset.test b/mysql-test/suite/funcs_2/t/ndb_charset.test index 72ebbad43d7..68665cc1ae5 100644 --- a/mysql-test/suite/funcs_2/t/ndb_charset.test +++ b/mysql-test/suite/funcs_2/t/ndb_charset.test @@ -1,8 +1,10 @@ -################################################################################# -# Author: Serge Kozlov # -# Date: 09/21/2005 # -# Purpose: Testing the charsets for NDB engine # -################################################################################# +################################################################################ +# Author: Serge Kozlov # +# Date: 09/21/2005 # +# Purpose: Testing the charsets for NDB engine # +# # +# Checking of other prerequisites is in charset_master.test # +################################################################################ --source include/have_ndb.inc --source include/not_embedded.inc From 0833d668474a768b0b8a6e170d602097b7b43c73 Mon Sep 17 00:00:00 2001 From: "Tatiana A. Nurnberg" Date: Thu, 10 Jul 2008 03:58:30 +0200 Subject: [PATCH 09/11] Bug#35848: UUID() returns UUIDs with the wrong time offset for time part in UUIDs was 1/1000 of what it should be. In other words, offset was off. Also handle the case where we count into the future when several UUIDs are generated in one "tick", and then the next call is late enough for us to unwind some but not all of those borrowed ticks. Lastly, handle the case where we keep borrowing and borrowing until the tick-counter overflows by also changing into a new "numberspace" by creating a new random suffix. mysql-test/r/func_misc.result: Show that time-part of UUIDs is correct now. mysql-test/t/func_misc.test: Show that time-part of UUIDs is correct now by replicating the C-code's resultin SQL. Results also decode to expect date-data on command-line (external validation). No test for unwinding of borrowed ticks as this a) is a race and b) depends on what timer we get. sql/item_strfunc.cc: correct offset for date/time-part of UUID. also make sure that when we counted into the future earlier (several UUIDs generated in same tick), we only give back as many "borrowed" ticks as we can without duplicating past timestamps. If our tick-counter overflows before we can give back, or if the system-clock is set back (by user or Daylight Saving Time), we create a new random suffix to avoid collisions and clear the tick-counter. --- mysql-test/r/func_misc.result | 14 ++++++++ mysql-test/t/func_misc.test | 19 ++++++++++ sql/item_strfunc.cc | 65 ++++++++++++++++++++++++++++------- 3 files changed, 86 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index d50dda55bfb..ce177b511b9 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -305,4 +305,18 @@ drop table t1; SELECT NAME_CONST('var', 'value') COLLATE latin1_general_cs; NAME_CONST('var', 'value') COLLATE latin1_general_cs value +select @@session.time_zone into @save_tz; +set @@session.time_zone='UTC'; +select uuid() into @my_uuid; +select mid(@my_uuid,15,1); +mid(@my_uuid,15,1) +1 +select 24 * 60 * 60 * 1000 * 1000 * 10 into @my_uuid_one_day; +select concat('0',mid(@my_uuid,16,3),mid(@my_uuid,10,4),left(@my_uuid,8)) into @my_uuidate; +select floor(conv(@my_uuidate,16,10)/@my_uuid_one_day) into @my_uuid_date; +select 141427 + datediff(curdate(),'1970-01-01') into @my_uuid_synthetic; +select @my_uuid_date - @my_uuid_synthetic; +@my_uuid_date - @my_uuid_synthetic +0 +set @@session.time_zone=@save_tz; End of 5.0 tests diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index 36c18979154..93fe94ec94f 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -417,5 +417,24 @@ drop table t1; # SELECT NAME_CONST('var', 'value') COLLATE latin1_general_cs; +# +# Bug #35848: UUID() returns UUIDs with the wrong time +# +select @@session.time_zone into @save_tz; + +# make sure all times are UTC so the DayNr won't differ +set @@session.time_zone='UTC'; +select uuid() into @my_uuid; +# if version nibble isn't 1, the following calculations will be rubbish +select mid(@my_uuid,15,1); +select 24 * 60 * 60 * 1000 * 1000 * 10 into @my_uuid_one_day; +select concat('0',mid(@my_uuid,16,3),mid(@my_uuid,10,4),left(@my_uuid,8)) into @my_uuidate; +select floor(conv(@my_uuidate,16,10)/@my_uuid_one_day) into @my_uuid_date; +select 141427 + datediff(curdate(),'1970-01-01') into @my_uuid_synthetic; +# these should be identical; date part of UUID should be current date +select @my_uuid_date - @my_uuid_synthetic; + +set @@session.time_zone=@save_tz; + --echo End of 5.0 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index c443364ce52..1d447d6e976 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3258,7 +3258,8 @@ static char clock_seq_and_node_str[]="-0000-000000000000"; /* number of 100-nanosecond intervals between 1582-10-15 00:00:00.00 and 1970-01-01 00:00:00.00 */ -#define UUID_TIME_OFFSET ((ulonglong) 141427 * 24 * 60 * 60 * 1000 * 10 ) +#define UUID_TIME_OFFSET ((ulonglong) 141427 * 24 * 60 * 60 * \ + 1000 * 1000 * 10) #define UUID_VERSION 0x1000 #define UUID_VARIANT 0x8000 @@ -3317,24 +3318,64 @@ String *Item_func_uuid::val_str(String *str) set_clock_seq_str(); } - ulonglong tv=my_getsystime() + UUID_TIME_OFFSET + nanoseq; - if (unlikely(tv < uuid_time)) - set_clock_seq_str(); - else if (unlikely(tv == uuid_time)) + ulonglong tv= my_getsystime() + UUID_TIME_OFFSET + nanoseq; + + if (likely(tv > uuid_time)) { - /* special protection from low-res system clocks */ - nanoseq++; - tv++; + /* + Current time is ahead of last timestamp, as it should be. + If we "borrowed time", give it back, just as long as we + stay ahead of the previous timestamp. + */ + if (nanoseq) + { + DBUG_ASSERT((tv > uuid_time) && (nanoseq > 0)); + /* + -1 so we won't make tv= uuid_time for nanoseq >= (tv - uuid_time) + */ + long delta= min(nanoseq, tv - uuid_time -1); + tv-= delta; + nanoseq-= delta; + } } else { - if (nanoseq) + if (unlikely(tv == uuid_time)) { - tv-=nanoseq; - nanoseq=0; + /* + For low-res system clocks. If several requests for UUIDs + end up on the same tick, we add a nano-second to make them + different. + ( current_timestamp + nanoseq * calls_in_this_period ) + may end up > next_timestamp; this is OK. Nonetheless, we'll + try to unwind nanoseq when we get a chance to. + If nanoseq overflows, we'll start over with a new numberspace + (so the if() below is needed so we can avoid the ++tv and thus + match the follow-up if() if nanoseq overflows!). + */ + if (likely(++nanoseq)) + ++tv; + } + + if (unlikely(tv <= uuid_time)) + { + /* + If the admin changes the system clock (or due to Daylight + Saving Time), the system clock may be turned *back* so we + go through a period once more for which we already gave out + UUIDs. To avoid duplicate UUIDs despite potentially identical + times, we make a new random component. + We also come here if the nanoseq "borrowing" overflows. + In either case, we throw away any nanoseq borrowing since it's + irrelevant in the new numberspace. + */ + set_clock_seq_str(); + tv= my_getsystime() + UUID_TIME_OFFSET; + nanoseq= 0; + DBUG_PRINT("uuid",("making new numberspace")); } - DBUG_ASSERT(tv > uuid_time); } + uuid_time=tv; pthread_mutex_unlock(&LOCK_uuid_generator); From 547ca1397599fa3acc2feca9d06d1dfdf3d0e971 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Fri, 11 Jul 2008 02:32:54 +0500 Subject: [PATCH 10/11] warning elimination --- sql/item_strfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 1d447d6e976..c12a1acc980 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3333,7 +3333,7 @@ String *Item_func_uuid::val_str(String *str) /* -1 so we won't make tv= uuid_time for nanoseq >= (tv - uuid_time) */ - long delta= min(nanoseq, tv - uuid_time -1); + long delta= min(nanoseq, (long) (tv - uuid_time -1)); tv-= delta; nanoseq-= delta; } From d5077086f73cfa24b8c4c9451fb70bc5a77922ae Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Fri, 11 Jul 2008 04:51:58 +0500 Subject: [PATCH 11/11] warning elimination --- sql/item_strfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index c12a1acc980..d1e3f45bba1 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3333,7 +3333,7 @@ String *Item_func_uuid::val_str(String *str) /* -1 so we won't make tv= uuid_time for nanoseq >= (tv - uuid_time) */ - long delta= min(nanoseq, (long) (tv - uuid_time -1)); + ulong delta= min(nanoseq, (ulong) (tv - uuid_time -1)); tv-= delta; nanoseq-= delta; }