diff options
author | unknown <malff/marcsql@weblab.(none)> | 2007-09-04 12:25:54 -0600 |
---|---|---|
committer | unknown <malff/marcsql@weblab.(none)> | 2007-09-04 12:25:54 -0600 |
commit | c458f7f6a3b6cf6754c9843d6801c9b0f86ffe48 (patch) | |
tree | e709d9cce3d8a2b77acda70637623f1faf7eb64f | |
parent | 943ed8fe354734fa52417bf36920462ab23756d3 (diff) | |
parent | 6bfae914a2a0e7661c75c030b0bf88c8490323ed (diff) | |
download | mariadb-git-c458f7f6a3b6cf6754c9843d6801c9b0f86ffe48.tar.gz |
Merge weblab.(none):/home/marcsql/TREE/mysql-5.1-base
into weblab.(none):/home/marcsql/TREE/mysql-5.1-rt50-merge
mysql-test/r/sp.result:
Auto merged
mysql-test/t/mysql.test:
Auto merged
mysql-test/t/query_cache.test:
Auto merged
mysql-test/t/sp.test:
Auto merged
sql/item_cmpfunc.h:
Auto merged
sql/rpl_utility.h:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_cache.cc:
Auto merged
sql/sql_lex.cc:
Auto merged
sql/sql_lex.h:
Auto merged
58 files changed, 3132 insertions, 426 deletions
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 6b3708f475f..e940f7a3371 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -105,7 +105,7 @@ if [ "x$warning_mode" != "xpedantic" ]; then # Added unless --with-debug=full debug_extra_cflags="-O1 -Wuninitialized" else - warnings="-W -Wall -ansi -pedantic -Wno-long-long -D_POSIX_SOURCE" + warnings="-W -Wall -ansi -pedantic -Wno-long-long -Wno-unused -D_POSIX_SOURCE" c_warnings="$warnings" cxx_warnings="$warnings -std=c++98" # NOTE: warning mode should not influence optimize/debug mode. @@ -207,3 +207,28 @@ then echo "$CC" | grep "ccache" > /dev/null || CC="ccache $CC" echo "$CXX" | grep "ccache" > /dev/null || CXX="ccache $CXX" fi + +# gcov + +# The -fprofile-arcs and -ftest-coverage options cause GCC to instrument the +# code with profiling information used by gcov. +# The -DDISABLE_TAO_ASM is needed to avoid build failures in Yassl. +# The -DHAVE_gcov enables code to write out coverage info even when crashing. + +gcov_compile_flags="-fprofile-arcs -ftest-coverage" +gcov_compile_flags="$gcov_compile_flags -DDISABLE_TAO_ASM" +gcov_compile_flags="$gcov_compile_flags -DMYSQL_SERVER_SUFFIX=-gcov -DHAVE_gcov" + +# GCC4 needs -fprofile-arcs -ftest-coverage on the linker command line (as well +# as on the compiler command line), and this requires setting LDFLAGS for BDB. + +gcov_link_flags="-fprofile-arcs -ftest-coverage" + +gcov_configs="--disable-shared" + +# gprof + +gprof_compile_flags="-O2 -pg -g" + +gprof_link_flags="--disable-shared $static_link" + diff --git a/BUILD/compile-amd64-gcov b/BUILD/compile-amd64-gcov new file mode 100755 index 00000000000..239a4aed0fb --- /dev/null +++ b/BUILD/compile-amd64-gcov @@ -0,0 +1,17 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +# Need to disable ccache, or we loose the gcov-needed compiler output files. +CCACHE_DISABLE=1 +export CCACHE_DISABLE + +export LDFLAGS="$gcov_link_flags" + +extra_flags="$amd64_cflags $debug_cflags $max_cflags $gcov_compile_flags" +c_warnings="$c_warnings $debug_extra_warnings" +cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$amd64_configs $debug_configs $gcov_configs $max_configs" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-amd64-gprof b/BUILD/compile-amd64-gprof new file mode 100755 index 00000000000..6cfb8a4302c --- /dev/null +++ b/BUILD/compile-amd64-gprof @@ -0,0 +1,9 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$amd64_cflags $gprof_compile_flags" +extra_configs="$amd64_configs $debug_configs $gprof_link_flags" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-gcov b/BUILD/compile-pentium-gcov index 77de5867d48..42666b2632c 100755 --- a/BUILD/compile-pentium-gcov +++ b/BUILD/compile-pentium-gcov @@ -20,18 +20,11 @@ export CCACHE_GCOV_VERSION_ENABLED path=`dirname $0` . "$path/SETUP.sh" -# GCC4 needs -fprofile-arcs -ftest-coverage on the linker command line (as well -# as on the compiler command line), and this requires setting LDFLAGS for BDB. -export LDFLAGS="-fprofile-arcs -ftest-coverage" +export LDFLAGS="$gcov_link_flags" -# The -fprofile-arcs and -ftest-coverage options cause GCC to instrument the -# code with profiling information used by gcov. -# The -DDISABLE_TAO_ASM is needed to avoid build failures in Yassl. -# The -DHAVE_gcov enables code to write out coverage info even when crashing. -extra_flags="$pentium_cflags -fprofile-arcs -ftest-coverage -DDISABLE_TAO_ASM -DHAVE_MUTEX_THREAD_ONLY $debug_extra_flags $debug_cflags $max_cflags -DMYSQL_SERVER_SUFFIX=-gcov -DHAVE_gcov" -extra_configs="$pentium_configs $debug_configs --disable-shared $static_link" -extra_configs="$extra_configs $max_configs" +extra_flags="$pentium_cflags $debug_cflags $max_cflags $gcov_compile_flags" c_warnings="$c_warnings $debug_extra_warnings" cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$pentium_configs $debug_configs $gcov_configs $max_configs" . "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-gprof b/BUILD/compile-pentium-gprof index aa74de0b1b2..4aebc1d2e02 100755 --- a/BUILD/compile-pentium-gprof +++ b/BUILD/compile-pentium-gprof @@ -3,7 +3,7 @@ path=`dirname $0` . "$path/SETUP.sh" -extra_flags="$pentium_cflags -O2 -pg -g" -extra_configs="$pentium_configs $debug_configs --disable-shared $static_link" +extra_flags="$pentium_cflags $gprof_compile_flags" +extra_configs="$pentium_configs $debug_configs $gprof_link_flags" . "$path/FINISH.sh" diff --git a/BUILD/compile-pentium64-gcov b/BUILD/compile-pentium64-gcov new file mode 100755 index 00000000000..5a99b7f8796 --- /dev/null +++ b/BUILD/compile-pentium64-gcov @@ -0,0 +1,17 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +# Need to disable ccache, or we loose the gcov-needed compiler output files. +CCACHE_DISABLE=1 +export CCACHE_DISABLE + +export LDFLAGS="$gcov_link_flags" + +extra_flags="$pentium64_cflags $debug_cflags $max_cflags $gcov_compile_flags" +c_warnings="$c_warnings $debug_extra_warnings" +cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$pentium64_configs $debug_configs $gcov_configs $max_configs" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium64-gprof b/BUILD/compile-pentium64-gprof new file mode 100755 index 00000000000..f64dee6d196 --- /dev/null +++ b/BUILD/compile-pentium64-gprof @@ -0,0 +1,9 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$pentium64_cflags $gprof_compile_flags" +extra_configs="$pentium64_configs $debug_configs $gprof_link_flags" + +. "$path/FINISH.sh" diff --git a/client/mysql.cc b/client/mysql.cc index 8e6a4dd99ae..794f252853a 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1263,6 +1263,7 @@ static bool add_line(String &buffer,char *line,char *in_string, char buff[80], *pos, *out; COMMANDS *com; bool need_space= 0; + bool ss_comment= 0; DBUG_ENTER("add_line"); if (!line[0] && buffer.is_empty()) @@ -1311,22 +1312,36 @@ static bool add_line(String &buffer,char *line,char *in_string, } if ((com=find_command(NullS,(char) inchar))) { - const String tmp(line,(uint) (out-line), charset_info); - buffer.append(tmp); - if ((*com->func)(&buffer,pos-1) > 0) - DBUG_RETURN(1); // Quit - if (com->takes_params) - { - for (pos++ ; - *pos && (*pos != *delimiter || - !is_prefix(pos + 1, delimiter + 1)) ; pos++) - ; // Remove parameters - if (!*pos) - pos--; - else - pos+= delimiter_length - 1; // Point at last delim char - } - out=line; + const String tmp(line,(uint) (out-line), charset_info); + buffer.append(tmp); + if ((*com->func)(&buffer,pos-1) > 0) + DBUG_RETURN(1); // Quit + if (com->takes_params) + { + if (ss_comment) + { + /* + If a client-side macro appears inside a server-side comment, + discard all characters in the comment after the macro (that is, + until the end of the comment rather than the next delimiter) + */ + for (pos++; *pos && (*pos != '*' || *(pos + 1) != '/'); pos++) + ; + pos--; + } + else + { + for (pos++ ; + *pos && (*pos != *delimiter || + !is_prefix(pos + 1, delimiter + 1)) ; pos++) + ; // Remove parameters + if (!*pos) + pos--; + else + pos+= delimiter_length - 1; // Point at last delim char + } + } + out=line; } else { @@ -1386,7 +1401,7 @@ static bool add_line(String &buffer,char *line,char *in_string, out=line; } } - else if (*ml_comment && inchar == '*' && *(pos + 1) == '/') + else if (*ml_comment && !ss_comment && inchar == '*' && *(pos + 1) == '/') { pos++; *ml_comment= 0; @@ -1394,6 +1409,11 @@ static bool add_line(String &buffer,char *line,char *in_string, } else { // Add found char to buffer + if (!*in_string && inchar == '/' && *(pos + 1) == '*' && + *(pos + 2) == '!') + ss_comment= 1; + else if (!*in_string && ss_comment && inchar == '*' && *(pos + 1) == '/') + ss_comment= 0; if (inchar == *in_string) *in_string= 0; else if (!*ml_comment && !*in_string && diff --git a/include/my_global.h b/include/my_global.h index 8b6cdef8daa..12129523939 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -562,12 +562,6 @@ int __void__; #define PURIFY_OR_LINT_INIT(var) #endif -/* Define some useful general macros */ -#if !defined(max) -#define max(a, b) ((a) > (b) ? (a) : (b)) -#define min(a, b) ((a) < (b) ? (a) : (b)) -#endif - #if !defined(HAVE_UINT) #undef HAVE_UINT #define HAVE_UINT @@ -1508,4 +1502,10 @@ inline void operator delete[](void*, void*) { /* Do nothing */ } /* Length of decimal number represented by INT64. */ #define MY_INT64_NUM_DECIMAL_DIGITS 21 +/* Define some useful general macros (should be done after all headers). */ +#if !defined(max) +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + #endif /* my_global_h */ diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index 61ed7be738f..50ec051d111 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -785,5 +785,28 @@ void mysql_query_cache_invalidate4(MYSQL_THD thd, } #endif +#ifdef __cplusplus +/** + Provide a handler data getter to simplify coding +*/ +inline +void * +thd_get_ha_data(const MYSQL_THD thd, const struct handlerton *hton) +{ + return *thd_ha_data(thd, hton); +} + +/** + Provide a handler data setter to simplify coding +*/ +inline +void +thd_set_ha_data(const MYSQL_THD thd, const struct handlerton *hton, + const void *ha_data) +{ + *thd_ha_data(thd, hton)= (void*) ha_data; +} +#endif + #endif diff --git a/mysql-test/include/deadlock.inc b/mysql-test/include/deadlock.inc index 41c68f39320..89c34abc871 100644 --- a/mysql-test/include/deadlock.inc +++ b/mysql-test/include/deadlock.inc @@ -144,4 +144,29 @@ disconnect con1; disconnect con2; drop table t1, t2; -# End of 4.1 tests +--echo End of 4.1 tests + +# +# Bug#25164 create table `a` as select * from `A` hangs +# + +set storage_engine=innodb; + +--disable_warnings +drop table if exists a; +drop table if exists A; +--enable_warnings + +create table A (c int); +insert into A (c) values (0); +--error 0,ER_LOCK_DEADLOCK,ER_UPDATE_TABLE_USED +create table a as select * from A; +drop table A; + +--disable_warnings +drop table if exists a; +--enable_warnings + +set storage_engine=default; + +--echo End of 5.0 tests. diff --git a/mysql-test/include/handler.inc b/mysql-test/include/handler.inc index a5b8c6cc7c9..437dd6ced4d 100644 --- a/mysql-test/include/handler.inc +++ b/mysql-test/include/handler.inc @@ -479,3 +479,22 @@ handler t1 open; --echo --> client 1 connection default; drop table t1; + +# +# Bug#30632 HANDLER read failure causes hang +# +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +handler t1 open as t1_alias; +--error 1176 +handler t1_alias read a next; +--error 1054 +handler t1_alias READ a next where inexistent > 0; +--error 1176 +handler t1_alias read a next; +--error 1054 +handler t1_alias READ a next where inexistent > 0; +handler t1_alias close; +drop table t1; diff --git a/mysql-test/include/query_cache_sql_prepare.inc b/mysql-test/include/query_cache_sql_prepare.inc index cf6d4c26959..1842d5412bb 100644 --- a/mysql-test/include/query_cache_sql_prepare.inc +++ b/mysql-test/include/query_cache_sql_prepare.inc @@ -275,5 +275,223 @@ drop table t1; --echo ---- disconnect connection con1 ---- disconnect con1; +# +# Bug #25843 Changing default database between PREPARE and EXECUTE of statement +# breaks binlog. +# +# There were actually two problems discovered by this bug: +# +# 1. Default (current) database is not fixed at the creation time. +# That leads to wrong output of DATABASE() function. +# +# 2. Database attributes (@@collation_database) are not fixed at the creation +# time. That leads to wrong resultset. +# +# Binlog breakage and Query Cache wrong output happened because of the first +# problem. +# + +--echo ######################################################################## +--echo # +--echo # BUG#25843: Changing default database between PREPARE and EXECUTE of +--echo # statement breaks binlog. +--echo # +--echo ######################################################################## + +############################################################################### + +--echo +--echo # +--echo # Check that default database and its attributes are fixed at the +--echo # creation time. +--echo # + +# Prepare data structures. + +--echo +--disable_warnings +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; +--enable_warnings + +--echo +CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci; +CREATE DATABASE mysqltest2 COLLATE utf8_general_ci; + +--echo +CREATE TABLE mysqltest1.t1(msg VARCHAR(255)); +CREATE TABLE mysqltest2.t1(msg VARCHAR(255)); + +# - Create a prepared statement with mysqltest1 as default database; + +--echo + +use mysqltest1; + +PREPARE stmt_a_1 FROM 'INSERT INTO t1 VALUES(DATABASE())'; +PREPARE stmt_a_2 FROM 'INSERT INTO t1 VALUES(@@collation_database)'; + +# - Execute on mysqltest1. + +--echo + +EXECUTE stmt_a_1; +EXECUTE stmt_a_2; + +# - Execute on mysqltest2. + +--echo + +use mysqltest2; + +EXECUTE stmt_a_1; +EXECUTE stmt_a_2; + +# - Check the results; + +--echo +SELECT * FROM mysqltest1.t1; + +--echo +SELECT * FROM mysqltest2.t1; + +# - Drop prepared statements. + +--echo +DROP PREPARE stmt_a_1; +DROP PREPARE stmt_a_2; + +############################################################################### + +--echo +--echo # +--echo # The Query Cache test case. +--echo # + +--echo +DELETE FROM mysqltest1.t1; +DELETE FROM mysqltest2.t1; + +--echo +INSERT INTO mysqltest1.t1 VALUES('mysqltest1.t1'); +INSERT INTO mysqltest2.t1 VALUES('mysqltest2.t1'); + +--echo +use mysqltest1; +PREPARE stmt_b_1 FROM 'SELECT * FROM t1'; + +--echo +use mysqltest2; +PREPARE stmt_b_2 FROM 'SELECT * FROM t1'; + +--echo +EXECUTE stmt_b_1; + +--echo +EXECUTE stmt_b_2; + +--echo +use mysqltest1; + +--echo +EXECUTE stmt_b_1; + +--echo +EXECUTE stmt_b_2; + +--echo +DROP PREPARE stmt_b_1; +DROP PREPARE stmt_b_2; + +# Cleanup. + +--echo +use test; + +--echo +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; + +############################################################################### + +--echo +--echo # +--echo # Check that prepared statements work properly when there is no current +--echo # database. +--echo # + +--echo +CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci; +CREATE DATABASE mysqltest2 COLLATE utf8_general_ci; + +--echo +use mysqltest1; + +--echo +PREPARE stmt_c_1 FROM 'SELECT DATABASE(), @@collation_database'; + +--echo +use mysqltest2; + +--echo +PREPARE stmt_c_2 FROM 'SELECT DATABASE(), @@collation_database'; + +--echo +DROP DATABASE mysqltest2; + +--echo +SELECT DATABASE(), @@collation_database; + +# -- Here we have: current db: NULL; stmt db: mysqltest1; +--echo +EXECUTE stmt_c_1; + +--echo +SELECT DATABASE(), @@collation_database; + +# -- Here we have: current db: NULL; stmt db: mysqltest2 (non-existent); +--echo +EXECUTE stmt_c_2; + +--echo +SELECT DATABASE(), @@collation_database; + +# -- Create prepared statement, which has no current database. + +--echo +PREPARE stmt_c_3 FROM 'SELECT DATABASE(), @@collation_database'; + +# -- Here we have: current db: NULL; stmt db: NULL; +--echo +EXECUTE stmt_c_3; + +--echo +use mysqltest1; + +# -- Here we have: current db: mysqltest1; stmt db: mysqltest2 (non-existent); +--echo +EXECUTE stmt_c_2; + +--echo +SELECT DATABASE(), @@collation_database; + +# -- Here we have: current db: mysqltest1; stmt db: NULL; +--echo +EXECUTE stmt_c_3; + +--echo +SELECT DATABASE(), @@collation_database; + +--echo +DROP DATABASE mysqltest1; + +--echo +use test; + +--echo +--echo ######################################################################## + +############################################################################### + set @@global.query_cache_size=@initial_query_cache_size; flush status; # reset Qcache status variables for next tests diff --git a/mysql-test/r/comments.result b/mysql-test/r/comments.result index 98921c561d1..d8ac68e2468 100644 --- a/mysql-test/r/comments.result +++ b/mysql-test/r/comments.result @@ -36,3 +36,18 @@ select 1/*!999992*/; select 1 + /*!00000 2 */ + 3 /*!99999 noise*/ + 4; 1 + 2 + 3 + 4 10 +drop table if exists table_28779; +create table table_28779 (a int); +prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*' 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 '/*' AND b = 'bar'' at line 1 +prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*' 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 '/*' AND b = 'bar';*' 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 +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/*!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';*"; +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 +drop table table_28779; diff --git a/mysql-test/r/deadlock_innodb.result b/mysql-test/r/deadlock_innodb.result index a0686d1c844..7a4874d6aab 100644 --- a/mysql-test/r/deadlock_innodb.result +++ b/mysql-test/r/deadlock_innodb.result @@ -112,3 +112,14 @@ id x commit; # Switch to connection default + disconnect con1 and con2 drop table t1, t2; +End of 4.1 tests +set storage_engine=innodb; +drop table if exists a; +drop table if exists A; +create table A (c int); +insert into A (c) values (0); +create table a as select * from A; +drop table A; +drop table if exists a; +set storage_engine=default; +End of 5.0 tests. diff --git a/mysql-test/r/events.result b/mysql-test/r/events.result index 579f5907882..d1ee6d1c5a1 100644 --- a/mysql-test/r/events.result +++ b/mysql-test/r/events.result @@ -454,8 +454,11 @@ create event закачка on schedule every 10 hour do select get_lock("test_l select definer, name, db from mysql.event; definer name db root@localhost закачка events_test -"Should be only 1 process" -select /*1*/ user, host, db, command, state, info from information_schema.processlist where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info; +"Should be only 0 process" +select /*1*/ user, host, db, command, state, info +from information_schema.processlist +where (user='event_scheduler') +order by info; user host db command state info select release_lock("test_lock1"); release_lock("test_lock1") @@ -472,14 +475,15 @@ get_lock("test_lock2", 20) 1 "Create an event which tries to acquire a mutex. The event locks on the mutex" create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20); -"Let some time pass to the event starts" "Should have only 2 processes: the scheduler and the locked event" -select /*2*/ user, host, db, command, state, info from information_schema.processlist where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info; +select /*2*/ user, host, db, command, state, info +from information_schema.processlist +where (info like "select get_lock%" OR user='event_scheduler') +order by info; user host db command state info event_scheduler localhost NULL Daemon Waiting for next activation NULL root localhost events_test Connect User lock select get_lock("test_lock2", 20) "Release the mutex, the event worker should finish." -"Release the mutex, the event worker should finish." select release_lock("test_lock2"); release_lock("test_lock2") 1 @@ -489,16 +493,25 @@ select get_lock("test_lock2_1", 20); get_lock("test_lock2_1", 20) 1 create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20); -"Should have only 3 processes: the scheduler, our conn and the locked event" -select /*3*/ user, host, db, command, state, info from information_schema.processlist where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info; +"Should have only 2 processes: the scheduler and the locked event" +select /*3*/ user, host, db, command, state, info +from information_schema.processlist +where (info like "select get_lock%" OR user='event_scheduler') +order by info; user host db command state info event_scheduler localhost NULL Daemon Waiting for next activation NULL root localhost events_test Connect User lock select get_lock("test_lock2_1", 20) set global event_scheduler=off; "Should have only our process now:" -select /*4*/ user, host, db, command, state, info from information_schema.processlist where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info; +select /*4*/ user, host, db, command, state, info +from information_schema.processlist +where (info like "select get_lock%" OR user='event_scheduler') +order by info; user host db command state info root localhost events_test Connect User lock select get_lock("test_lock2_1", 20) +select release_lock("test_lock2_1"); +release_lock("test_lock2_1") +1 drop event закачка21; create table t_16 (s1 int); create trigger t_16_bi before insert on t_16 for each row create event e_16 on schedule every 1 second do set @a=5; diff --git a/mysql-test/r/handler_innodb.result b/mysql-test/r/handler_innodb.result index 81d1e26f8d0..98b8922bc5f 100644 --- a/mysql-test/r/handler_innodb.result +++ b/mysql-test/r/handler_innodb.result @@ -522,3 +522,16 @@ handler t1 open; ERROR HY000: Table storage engine for 't1' doesn't have this option --> client 1 drop table t1; +drop table if exists t1; +create table t1 (a int); +handler t1 open as t1_alias; +handler t1_alias read a next; +ERROR 42000: Key 'a' doesn't exist in table 't1_alias' +handler t1_alias READ a next where inexistent > 0; +ERROR 42S22: Unknown column 'inexistent' in 'field list' +handler t1_alias read a next; +ERROR 42000: Key 'a' doesn't exist in table 't1_alias' +handler t1_alias READ a next where inexistent > 0; +ERROR 42S22: Unknown column 'inexistent' in 'field list' +handler t1_alias close; +drop table t1; diff --git a/mysql-test/r/handler_myisam.result b/mysql-test/r/handler_myisam.result index 5d04604959b..464b775b795 100644 --- a/mysql-test/r/handler_myisam.result +++ b/mysql-test/r/handler_myisam.result @@ -522,3 +522,16 @@ handler t1 open; ERROR HY000: Table storage engine for 't1' doesn't have this option --> client 1 drop table t1; +drop table if exists t1; +create table t1 (a int); +handler t1 open as t1_alias; +handler t1_alias read a next; +ERROR 42000: Key 'a' doesn't exist in table 't1_alias' +handler t1_alias READ a next where inexistent > 0; +ERROR 42S22: Unknown column 'inexistent' in 'field list' +handler t1_alias read a next; +ERROR 42000: Key 'a' doesn't exist in table 't1_alias' +handler t1_alias READ a next where inexistent > 0; +ERROR 42S22: Unknown column 'inexistent' in 'field list' +handler t1_alias close; +drop table t1; diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index 704cf444681..3aec9594d36 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -407,3 +407,22 @@ select if( @stamp1 = @stamp2, "correct", "wrong"); if( @stamp1 = @stamp2, "correct", "wrong") correct drop table t1; +connection: default +set low_priority_updates=1; +drop table if exists t1; +create table t1 (a int, b int, unique key t1$a (a)); +lock table t1 read; +connection: update +set low_priority_updates=1; +show variables like 'low_priority_updates'; +Variable_name Value +low_priority_updates ON +insert into t1 values (1, 2) ON DUPLICATE KEY UPDATE b = 2;; +connection: select +select * from t1; +a b +connection: default +select * from t1; +a b +drop table t1; +set low_priority_updates=default; diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index f5b369f246a..df77bc99c22 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -176,5 +176,7 @@ ERROR at line 1: DELIMITER cannot contain a backslash character ERROR at line 1: DELIMITER cannot contain a backslash character 1 1 +1 +1 End of 5.0 tests WARNING: --server-arg option not supported in this configuration. diff --git a/mysql-test/r/parser_precedence.result b/mysql-test/r/parser_precedence.result new file mode 100644 index 00000000000..cf301ec677b --- /dev/null +++ b/mysql-test/r/parser_precedence.result @@ -0,0 +1,747 @@ +drop table if exists t1_30237_bool; +create table t1_30237_bool(A boolean, B boolean, C boolean); +insert into t1_30237_bool values +(FALSE, FALSE, FALSE), +(FALSE, FALSE, NULL), +(FALSE, FALSE, TRUE), +(FALSE, NULL, FALSE), +(FALSE, NULL, NULL), +(FALSE, NULL, TRUE), +(FALSE, TRUE, FALSE), +(FALSE, TRUE, NULL), +(FALSE, TRUE, TRUE), +(NULL, FALSE, FALSE), +(NULL, FALSE, NULL), +(NULL, FALSE, TRUE), +(NULL, NULL, FALSE), +(NULL, NULL, NULL), +(NULL, NULL, TRUE), +(NULL, TRUE, FALSE), +(NULL, TRUE, NULL), +(NULL, TRUE, TRUE), +(TRUE, FALSE, FALSE), +(TRUE, FALSE, NULL), +(TRUE, FALSE, TRUE), +(TRUE, NULL, FALSE), +(TRUE, NULL, NULL), +(TRUE, NULL, TRUE), +(TRUE, TRUE, FALSE), +(TRUE, TRUE, NULL), +(TRUE, TRUE, TRUE) ; +Testing OR, XOR, AND +select A, B, A OR B, A XOR B, A AND B +from t1_30237_bool where C is null order by A, B; +A B A OR B A XOR B A AND B +NULL NULL NULL NULL NULL +NULL 0 NULL NULL 0 +NULL 1 1 NULL NULL +0 NULL NULL NULL 0 +0 0 0 0 0 +0 1 1 1 0 +1 NULL 1 NULL NULL +1 0 1 1 0 +1 1 1 0 1 +Testing that OR is associative +select A, B, C, (A OR B) OR C, A OR (B OR C), A OR B OR C +from t1_30237_bool order by A, B, C; +A B C (A OR B) OR C A OR (B OR C) A OR B OR C +NULL NULL NULL NULL NULL NULL +NULL NULL 0 NULL NULL NULL +NULL NULL 1 1 1 1 +NULL 0 NULL NULL NULL NULL +NULL 0 0 NULL NULL NULL +NULL 0 1 1 1 1 +NULL 1 NULL 1 1 1 +NULL 1 0 1 1 1 +NULL 1 1 1 1 1 +0 NULL NULL NULL NULL NULL +0 NULL 0 NULL NULL NULL +0 NULL 1 1 1 1 +0 0 NULL NULL NULL NULL +0 0 0 0 0 0 +0 0 1 1 1 1 +0 1 NULL 1 1 1 +0 1 0 1 1 1 +0 1 1 1 1 1 +1 NULL NULL 1 1 1 +1 NULL 0 1 1 1 +1 NULL 1 1 1 1 +1 0 NULL 1 1 1 +1 0 0 1 1 1 +1 0 1 1 1 1 +1 1 NULL 1 1 1 +1 1 0 1 1 1 +1 1 1 1 1 1 +select count(*) from t1_30237_bool +where ((A OR B) OR C) != (A OR (B OR C)); +count(*) +0 +Testing that XOR is associative +select A, B, C, (A XOR B) XOR C, A XOR (B XOR C), A XOR B XOR C +from t1_30237_bool order by A, B, C; +A B C (A XOR B) XOR C A XOR (B XOR C) A XOR B XOR C +NULL NULL NULL NULL NULL NULL +NULL NULL 0 NULL NULL NULL +NULL NULL 1 NULL NULL NULL +NULL 0 NULL NULL NULL NULL +NULL 0 0 NULL NULL NULL +NULL 0 1 NULL NULL NULL +NULL 1 NULL NULL NULL NULL +NULL 1 0 NULL NULL NULL +NULL 1 1 NULL NULL NULL +0 NULL NULL NULL NULL NULL +0 NULL 0 NULL NULL NULL +0 NULL 1 NULL NULL NULL +0 0 NULL NULL NULL NULL +0 0 0 0 0 0 +0 0 1 1 1 1 +0 1 NULL NULL NULL NULL +0 1 0 1 1 1 +0 1 1 0 0 0 +1 NULL NULL NULL NULL NULL +1 NULL 0 NULL NULL NULL +1 NULL 1 NULL NULL NULL +1 0 NULL NULL NULL NULL +1 0 0 1 1 1 +1 0 1 0 0 0 +1 1 NULL NULL NULL NULL +1 1 0 0 0 0 +1 1 1 1 1 1 +select count(*) from t1_30237_bool +where ((A XOR B) XOR C) != (A XOR (B XOR C)); +count(*) +0 +Testing that AND is associative +select A, B, C, (A AND B) AND C, A AND (B AND C), A AND B AND C +from t1_30237_bool order by A, B, C; +A B C (A AND B) AND C A AND (B AND C) A AND B AND C +NULL NULL NULL NULL NULL NULL +NULL NULL 0 0 0 0 +NULL NULL 1 NULL NULL NULL +NULL 0 NULL 0 0 0 +NULL 0 0 0 0 0 +NULL 0 1 0 0 0 +NULL 1 NULL NULL NULL NULL +NULL 1 0 0 0 0 +NULL 1 1 NULL NULL NULL +0 NULL NULL 0 0 0 +0 NULL 0 0 0 0 +0 NULL 1 0 0 0 +0 0 NULL 0 0 0 +0 0 0 0 0 0 +0 0 1 0 0 0 +0 1 NULL 0 0 0 +0 1 0 0 0 0 +0 1 1 0 0 0 +1 NULL NULL NULL NULL NULL +1 NULL 0 0 0 0 +1 NULL 1 NULL NULL NULL +1 0 NULL 0 0 0 +1 0 0 0 0 0 +1 0 1 0 0 0 +1 1 NULL NULL NULL NULL +1 1 0 0 0 0 +1 1 1 1 1 1 +select count(*) from t1_30237_bool +where ((A AND B) AND C) != (A AND (B AND C)); +count(*) +0 +Testing that AND has precedence over OR +select A, B, C, (A OR B) AND C, A OR (B AND C), A OR B AND C +from t1_30237_bool order by A, B, C; +A B C (A OR B) AND C A OR (B AND C) A OR B AND C +NULL NULL NULL NULL NULL NULL +NULL NULL 0 0 NULL NULL +NULL NULL 1 NULL NULL NULL +NULL 0 NULL NULL NULL NULL +NULL 0 0 0 NULL NULL +NULL 0 1 NULL NULL NULL +NULL 1 NULL NULL NULL NULL +NULL 1 0 0 NULL NULL +NULL 1 1 1 1 1 +0 NULL NULL NULL NULL NULL +0 NULL 0 0 0 0 +0 NULL 1 NULL NULL NULL +0 0 NULL 0 0 0 +0 0 0 0 0 0 +0 0 1 0 0 0 +0 1 NULL NULL NULL NULL +0 1 0 0 0 0 +0 1 1 1 1 1 +1 NULL NULL NULL 1 1 +1 NULL 0 0 1 1 +1 NULL 1 1 1 1 +1 0 NULL NULL 1 1 +1 0 0 0 1 1 +1 0 1 1 1 1 +1 1 NULL NULL 1 1 +1 1 0 0 1 1 +1 1 1 1 1 1 +select count(*) from t1_30237_bool +where (A OR (B AND C)) != (A OR B AND C); +count(*) +0 +select A, B, C, (A AND B) OR C, A AND (B OR C), A AND B OR C +from t1_30237_bool order by A, B, C; +A B C (A AND B) OR C A AND (B OR C) A AND B OR C +NULL NULL NULL NULL NULL NULL +NULL NULL 0 NULL NULL NULL +NULL NULL 1 1 NULL 1 +NULL 0 NULL NULL NULL NULL +NULL 0 0 0 0 0 +NULL 0 1 1 NULL 1 +NULL 1 NULL NULL NULL NULL +NULL 1 0 NULL NULL NULL +NULL 1 1 1 NULL 1 +0 NULL NULL NULL 0 NULL +0 NULL 0 0 0 0 +0 NULL 1 1 0 1 +0 0 NULL NULL 0 NULL +0 0 0 0 0 0 +0 0 1 1 0 1 +0 1 NULL NULL 0 NULL +0 1 0 0 0 0 +0 1 1 1 0 1 +1 NULL NULL NULL NULL NULL +1 NULL 0 NULL NULL NULL +1 NULL 1 1 1 1 +1 0 NULL NULL NULL NULL +1 0 0 0 0 0 +1 0 1 1 1 1 +1 1 NULL 1 1 1 +1 1 0 1 1 1 +1 1 1 1 1 1 +select count(*) from t1_30237_bool +where ((A AND B) OR C) != (A AND B OR C); +count(*) +0 +Testing that AND has precedence over XOR +select A, B, C, (A XOR B) AND C, A XOR (B AND C), A XOR B AND C +from t1_30237_bool order by A, B, C; +A B C (A XOR B) AND C A XOR (B AND C) A XOR B AND C +NULL NULL NULL NULL NULL NULL +NULL NULL 0 0 NULL NULL +NULL NULL 1 NULL NULL NULL +NULL 0 NULL NULL NULL NULL +NULL 0 0 0 NULL NULL +NULL 0 1 NULL NULL NULL +NULL 1 NULL NULL NULL NULL +NULL 1 0 0 NULL NULL +NULL 1 1 NULL NULL NULL +0 NULL NULL NULL NULL NULL +0 NULL 0 0 0 0 +0 NULL 1 NULL NULL NULL +0 0 NULL 0 0 0 +0 0 0 0 0 0 +0 0 1 0 0 0 +0 1 NULL NULL NULL NULL +0 1 0 0 0 0 +0 1 1 1 1 1 +1 NULL NULL NULL NULL NULL +1 NULL 0 0 1 1 +1 NULL 1 NULL NULL NULL +1 0 NULL NULL 1 1 +1 0 0 0 1 1 +1 0 1 1 1 1 +1 1 NULL 0 NULL NULL +1 1 0 0 1 1 +1 1 1 0 0 0 +select count(*) from t1_30237_bool +where (A XOR (B AND C)) != (A XOR B AND C); +count(*) +0 +select A, B, C, (A AND B) XOR C, A AND (B XOR C), A AND B XOR C +from t1_30237_bool order by A, B, C; +A B C (A AND B) XOR C A AND (B XOR C) A AND B XOR C +NULL NULL NULL NULL NULL NULL +NULL NULL 0 NULL NULL NULL +NULL NULL 1 NULL NULL NULL +NULL 0 NULL NULL NULL NULL +NULL 0 0 0 0 0 +NULL 0 1 1 NULL 1 +NULL 1 NULL NULL NULL NULL +NULL 1 0 NULL NULL NULL +NULL 1 1 NULL 0 NULL +0 NULL NULL NULL 0 NULL +0 NULL 0 0 0 0 +0 NULL 1 1 0 1 +0 0 NULL NULL 0 NULL +0 0 0 0 0 0 +0 0 1 1 0 1 +0 1 NULL NULL 0 NULL +0 1 0 0 0 0 +0 1 1 1 0 1 +1 NULL NULL NULL NULL NULL +1 NULL 0 NULL NULL NULL +1 NULL 1 NULL NULL NULL +1 0 NULL NULL NULL NULL +1 0 0 0 0 0 +1 0 1 1 1 1 +1 1 NULL NULL NULL NULL +1 1 0 1 1 1 +1 1 1 0 0 0 +select count(*) from t1_30237_bool +where ((A AND B) XOR C) != (A AND B XOR C); +count(*) +0 +Testing that XOR has precedence over OR +select A, B, C, (A XOR B) OR C, A XOR (B OR C), A XOR B OR C +from t1_30237_bool order by A, B, C; +A B C (A XOR B) OR C A XOR (B OR C) A XOR B OR C +NULL NULL NULL NULL NULL NULL +NULL NULL 0 NULL NULL NULL +NULL NULL 1 1 NULL 1 +NULL 0 NULL NULL NULL NULL +NULL 0 0 NULL NULL NULL +NULL 0 1 1 NULL 1 +NULL 1 NULL NULL NULL NULL +NULL 1 0 NULL NULL NULL +NULL 1 1 1 NULL 1 +0 NULL NULL NULL NULL NULL +0 NULL 0 NULL NULL NULL +0 NULL 1 1 1 1 +0 0 NULL NULL NULL NULL +0 0 0 0 0 0 +0 0 1 1 1 1 +0 1 NULL 1 1 1 +0 1 0 1 1 1 +0 1 1 1 1 1 +1 NULL NULL NULL NULL NULL +1 NULL 0 NULL NULL NULL +1 NULL 1 1 0 1 +1 0 NULL 1 NULL 1 +1 0 0 1 1 1 +1 0 1 1 0 1 +1 1 NULL NULL 0 NULL +1 1 0 0 0 0 +1 1 1 1 0 1 +select count(*) from t1_30237_bool +where ((A XOR B) OR C) != (A XOR B OR C); +count(*) +0 +select A, B, C, (A OR B) XOR C, A OR (B XOR C), A OR B XOR C +from t1_30237_bool order by A, B, C; +A B C (A OR B) XOR C A OR (B XOR C) A OR B XOR C +NULL NULL NULL NULL NULL NULL +NULL NULL 0 NULL NULL NULL +NULL NULL 1 NULL NULL NULL +NULL 0 NULL NULL NULL NULL +NULL 0 0 NULL NULL NULL +NULL 0 1 NULL 1 1 +NULL 1 NULL NULL NULL NULL +NULL 1 0 1 1 1 +NULL 1 1 0 NULL NULL +0 NULL NULL NULL NULL NULL +0 NULL 0 NULL NULL NULL +0 NULL 1 NULL NULL NULL +0 0 NULL NULL NULL NULL +0 0 0 0 0 0 +0 0 1 1 1 1 +0 1 NULL NULL NULL NULL +0 1 0 1 1 1 +0 1 1 0 0 0 +1 NULL NULL NULL 1 1 +1 NULL 0 1 1 1 +1 NULL 1 0 1 1 +1 0 NULL NULL 1 1 +1 0 0 1 1 1 +1 0 1 0 1 1 +1 1 NULL NULL 1 1 +1 1 0 1 1 1 +1 1 1 0 1 1 +select count(*) from t1_30237_bool +where (A OR (B XOR C)) != (A OR B XOR C); +count(*) +0 +drop table t1_30237_bool; +Testing that NOT has precedence over OR +select (NOT FALSE) OR TRUE, NOT (FALSE OR TRUE), NOT FALSE OR TRUE; +(NOT FALSE) OR TRUE NOT (FALSE OR TRUE) NOT FALSE OR TRUE +1 0 1 +Testing that NOT has precedence over XOR +select (NOT FALSE) XOR FALSE, NOT (FALSE XOR FALSE), NOT FALSE XOR FALSE; +(NOT FALSE) XOR FALSE NOT (FALSE XOR FALSE) NOT FALSE XOR FALSE +1 1 1 +Testing that NOT has precedence over AND +select (NOT FALSE) AND FALSE, NOT (FALSE AND FALSE), NOT FALSE AND FALSE; +(NOT FALSE) AND FALSE NOT (FALSE AND FALSE) NOT FALSE AND FALSE +0 1 0 +Testing that NOT is associative +select NOT NOT TRUE, NOT NOT NOT FALSE; +NOT NOT TRUE NOT NOT NOT FALSE +1 1 +Testing that IS has precedence over NOT +select (NOT NULL) IS TRUE, NOT (NULL IS TRUE), NOT NULL IS TRUE; +(NOT NULL) IS TRUE NOT (NULL IS TRUE) NOT NULL IS TRUE +0 1 1 +select (NOT NULL) IS NOT TRUE, NOT (NULL IS NOT TRUE), NOT NULL IS NOT TRUE; +(NOT NULL) IS NOT TRUE NOT (NULL IS NOT TRUE) NOT NULL IS NOT TRUE +1 0 0 +select (NOT NULL) IS FALSE, NOT (NULL IS FALSE), NOT NULL IS FALSE; +(NOT NULL) IS FALSE NOT (NULL IS FALSE) NOT NULL IS FALSE +0 1 1 +select (NOT NULL) IS NOT FALSE, NOT (NULL IS NOT FALSE), NOT NULL IS NOT FALSE; +(NOT NULL) IS NOT FALSE NOT (NULL IS NOT FALSE) NOT NULL IS NOT FALSE +1 0 0 +select (NOT TRUE) IS UNKNOWN, NOT (TRUE IS UNKNOWN), NOT TRUE IS UNKNOWN; +(NOT TRUE) IS UNKNOWN NOT (TRUE IS UNKNOWN) NOT TRUE IS UNKNOWN +0 1 1 +select (NOT TRUE) IS NOT UNKNOWN, NOT (TRUE IS NOT UNKNOWN), NOT TRUE IS NOT UNKNOWN; +(NOT TRUE) IS NOT UNKNOWN NOT (TRUE IS NOT UNKNOWN) NOT TRUE IS NOT UNKNOWN +1 0 0 +select (NOT TRUE) IS NULL, NOT (TRUE IS NULL), NOT TRUE IS NULL; +(NOT TRUE) IS NULL NOT (TRUE IS NULL) NOT TRUE IS NULL +0 1 1 +select (NOT TRUE) IS NOT NULL, NOT (TRUE IS NOT NULL), NOT TRUE IS NOT NULL; +(NOT TRUE) IS NOT NULL NOT (TRUE IS NOT NULL) NOT TRUE IS NOT NULL +1 0 0 +Testing that IS [NOT] TRUE/FALSE/UNKNOWN predicates are not associative +select TRUE IS TRUE IS TRUE IS TRUE; +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 'IS TRUE IS TRUE' at line 1 +select FALSE IS NOT TRUE IS NOT TRUE IS NOT TRUE; +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 'IS NOT TRUE IS NOT TRUE' at line 1 +select NULL IS FALSE IS FALSE IS FALSE; +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 'IS FALSE IS FALSE' at line 1 +select TRUE IS NOT FALSE IS NOT FALSE IS NOT FALSE; +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 'IS NOT FALSE IS NOT FALSE' at line 1 +select FALSE IS UNKNOWN IS UNKNOWN IS UNKNOWN; +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 'IS UNKNOWN IS UNKNOWN' at line 1 +select TRUE IS NOT UNKNOWN IS NOT UNKNOWN IS NOT UNKNOWN; +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 'IS NOT UNKNOWN IS NOT UNKNOWN' at line 1 +Testing that IS [NOT] NULL predicates are associative +select FALSE IS NULL IS NULL IS NULL; +FALSE IS NULL IS NULL IS NULL +0 +select TRUE IS NOT NULL IS NOT NULL IS NOT NULL; +TRUE IS NOT NULL IS NOT NULL IS NOT NULL +1 +Testing that comparison operators are left associative +select 1 <=> 2 <=> 2, (1 <=> 2) <=> 2, 1 <=> (2 <=> 2); +1 <=> 2 <=> 2 (1 <=> 2) <=> 2 1 <=> (2 <=> 2) +0 0 1 +select 1 = 2 = 2, (1 = 2) = 2, 1 = (2 = 2); +1 = 2 = 2 (1 = 2) = 2 1 = (2 = 2) +0 0 1 +select 1 != 2 != 3, (1 != 2) != 3, 1 != (2 != 3); +1 != 2 != 3 (1 != 2) != 3 1 != (2 != 3) +1 1 0 +select 1 <> 2 <> 3, (1 <> 2) <> 3, 1 <> (2 <> 3); +1 <> 2 <> 3 (1 <> 2) <> 3 1 <> (2 <> 3) +1 1 0 +select 1 < 2 < 3, (1 < 2) < 3, 1 < (2 < 3); +1 < 2 < 3 (1 < 2) < 3 1 < (2 < 3) +1 1 0 +select 3 <= 2 <= 1, (3 <= 2) <= 1, 3 <= (2 <= 1); +3 <= 2 <= 1 (3 <= 2) <= 1 3 <= (2 <= 1) +1 1 0 +select 1 > 2 > 3, (1 > 2) > 3, 1 > (2 > 3); +1 > 2 > 3 (1 > 2) > 3 1 > (2 > 3) +0 0 1 +select 1 >= 2 >= 3, (1 >= 2) >= 3, 1 >= (2 >= 3); +1 >= 2 >= 3 (1 >= 2) >= 3 1 >= (2 >= 3) +0 0 1 +Testing that | is associative +select 0xF0 | 0x0F | 0x55, (0xF0 | 0x0F) | 0x55, 0xF0 | (0x0F | 0x55); +0xF0 | 0x0F | 0x55 (0xF0 | 0x0F) | 0x55 0xF0 | (0x0F | 0x55) +255 255 255 +Testing that & is associative +select 0xF5 & 0x5F & 0x55, (0xF5 & 0x5F) & 0x55, 0xF5 & (0x5F & 0x55); +0xF5 & 0x5F & 0x55 (0xF5 & 0x5F) & 0x55 0xF5 & (0x5F & 0x55) +85 85 85 +Testing that << is left associative +select 4 << 3 << 2, (4 << 3) << 2, 4 << (3 << 2); +4 << 3 << 2 (4 << 3) << 2 4 << (3 << 2) +128 128 16384 +Testing that >> is left associative +select 256 >> 3 >> 2, (256 >> 3) >> 2, 256 >> (3 >> 2); +256 >> 3 >> 2 (256 >> 3) >> 2 256 >> (3 >> 2) +8 8 256 +Testing that & has precedence over | +select 0xF0 & 0x0F | 0x55, (0xF0 & 0x0F) | 0x55, 0xF0 & (0x0F | 0x55); +0xF0 & 0x0F | 0x55 (0xF0 & 0x0F) | 0x55 0xF0 & (0x0F | 0x55) +85 85 80 +select 0x55 | 0xF0 & 0x0F, (0x55 | 0xF0) & 0x0F, 0x55 | (0xF0 & 0x0F); +0x55 | 0xF0 & 0x0F (0x55 | 0xF0) & 0x0F 0x55 | (0xF0 & 0x0F) +85 5 85 +Testing that << has precedence over | +select 0x0F << 4 | 0x0F, (0x0F << 4) | 0x0F, 0x0F << (4 | 0x0F); +0x0F << 4 | 0x0F (0x0F << 4) | 0x0F 0x0F << (4 | 0x0F) +255 255 491520 +select 0x0F | 0x0F << 4, (0x0F | 0x0F) << 4, 0x0F | (0x0F << 4); +0x0F | 0x0F << 4 (0x0F | 0x0F) << 4 0x0F | (0x0F << 4) +255 240 255 +Testing that >> has precedence over | +select 0xF0 >> 4 | 0xFF, (0xF0 >> 4) | 0xFF, 0xF0 >> (4 | 0xFF); +0xF0 >> 4 | 0xFF (0xF0 >> 4) | 0xFF 0xF0 >> (4 | 0xFF) +255 255 0 +select 0xFF | 0xF0 >> 4, (0xFF | 0xF0) >> 4, 0xFF | (0xF0 >> 4); +0xFF | 0xF0 >> 4 (0xFF | 0xF0) >> 4 0xFF | (0xF0 >> 4) +255 15 255 +Testing that << has precedence over & +select 0x0F << 4 & 0xF0, (0x0F << 4) & 0xF0, 0x0F << (4 & 0xF0); +0x0F << 4 & 0xF0 (0x0F << 4) & 0xF0 0x0F << (4 & 0xF0) +240 240 15 +select 0xF0 & 0x0F << 4, (0xF0 & 0x0F) << 4, 0xF0 & (0x0F << 4); +0xF0 & 0x0F << 4 (0xF0 & 0x0F) << 4 0xF0 & (0x0F << 4) +240 0 240 +Testing that >> has precedence over & +select 0xF0 >> 4 & 0x55, (0xF0 >> 4) & 0x55, 0xF0 >> (4 & 0x55); +0xF0 >> 4 & 0x55 (0xF0 >> 4) & 0x55 0xF0 >> (4 & 0x55) +5 5 15 +select 0x0F & 0xF0 >> 4, (0x0F & 0xF0) >> 4, 0x0F & (0xF0 >> 4); +0x0F & 0xF0 >> 4 (0x0F & 0xF0) >> 4 0x0F & (0xF0 >> 4) +15 0 15 +Testing that >> and << have the same precedence +select 0xFF >> 4 << 2, (0xFF >> 4) << 2, 0xFF >> (4 << 2); +0xFF >> 4 << 2 (0xFF >> 4) << 2 0xFF >> (4 << 2) +60 60 0 +select 0x0F << 4 >> 2, (0x0F << 4) >> 2, 0x0F << (4 >> 2); +0x0F << 4 >> 2 (0x0F << 4) >> 2 0x0F << (4 >> 2) +60 60 30 +Testing that binary + is associative +select 1 + 2 + 3, (1 + 2) + 3, 1 + (2 + 3); +1 + 2 + 3 (1 + 2) + 3 1 + (2 + 3) +6 6 6 +Testing that binary - is left associative +select 1 - 2 - 3, (1 - 2) - 3, 1 - (2 - 3); +1 - 2 - 3 (1 - 2) - 3 1 - (2 - 3) +-4 -4 2 +Testing that binary + and binary - have the same precedence +select 1 + 2 - 3, (1 + 2) - 3, 1 + (2 - 3); +1 + 2 - 3 (1 + 2) - 3 1 + (2 - 3) +0 0 0 +select 1 - 2 + 3, (1 - 2) + 3, 1 - (2 + 3); +1 - 2 + 3 (1 - 2) + 3 1 - (2 + 3) +2 2 -4 +Testing that binary + has precedence over | +select 0xF0 + 0x0F | 0x55, (0xF0 + 0x0F) | 0x55, 0xF0 + (0x0F | 0x55); +0xF0 + 0x0F | 0x55 (0xF0 + 0x0F) | 0x55 0xF0 + (0x0F | 0x55) +255 255 335 +select 0x55 | 0xF0 + 0x0F, (0x55 | 0xF0) + 0x0F, 0x55 | (0xF0 + 0x0F); +0x55 | 0xF0 + 0x0F (0x55 | 0xF0) + 0x0F 0x55 | (0xF0 + 0x0F) +255 260 255 +Testing that binary + has precedence over & +select 0xF0 + 0x0F & 0x55, (0xF0 + 0x0F) & 0x55, 0xF0 + (0x0F & 0x55); +0xF0 + 0x0F & 0x55 (0xF0 + 0x0F) & 0x55 0xF0 + (0x0F & 0x55) +85 85 245 +select 0x55 & 0xF0 + 0x0F, (0x55 & 0xF0) + 0x0F, 0x55 & (0xF0 + 0x0F); +0x55 & 0xF0 + 0x0F (0x55 & 0xF0) + 0x0F 0x55 & (0xF0 + 0x0F) +85 95 85 +Testing that binary + has precedence over << +select 2 + 3 << 4, (2 + 3) << 4, 2 + (3 << 4); +2 + 3 << 4 (2 + 3) << 4 2 + (3 << 4) +80 80 50 +select 3 << 4 + 2, (3 << 4) + 2, 3 << (4 + 2); +3 << 4 + 2 (3 << 4) + 2 3 << (4 + 2) +192 50 192 +Testing that binary + has precedence over >> +select 4 + 3 >> 2, (4 + 3) >> 2, 4 + (3 >> 2); +4 + 3 >> 2 (4 + 3) >> 2 4 + (3 >> 2) +1 1 4 +select 3 >> 2 + 1, (3 >> 2) + 1, 3 >> (2 + 1); +3 >> 2 + 1 (3 >> 2) + 1 3 >> (2 + 1) +0 1 0 +Testing that binary - has precedence over | +select 0xFF - 0x0F | 0x55, (0xFF - 0x0F) | 0x55, 0xFF - (0x0F | 0x55); +0xFF - 0x0F | 0x55 (0xFF - 0x0F) | 0x55 0xFF - (0x0F | 0x55) +245 245 160 +select 0x55 | 0xFF - 0xF0, (0x55 | 0xFF) - 0xF0, 0x55 | (0xFF - 0xF0); +0x55 | 0xFF - 0xF0 (0x55 | 0xFF) - 0xF0 0x55 | (0xFF - 0xF0) +95 15 95 +Testing that binary - has precedence over & +select 0xFF - 0xF0 & 0x55, (0xFF - 0xF0) & 0x55, 0xFF - (0xF0 & 0x55); +0xFF - 0xF0 & 0x55 (0xFF - 0xF0) & 0x55 0xFF - (0xF0 & 0x55) +5 5 175 +select 0x55 & 0xFF - 0xF0, (0x55 & 0xFF) - 0xF0, 0x55 & (0xFF - 0xF0); +0x55 & 0xFF - 0xF0 (0x55 & 0xFF) - 0xF0 0x55 & (0xFF - 0xF0) +5 -155 5 +Testing that binary - has precedence over << +select 16 - 3 << 2, (16 - 3) << 2, 16 - (3 << 2); +16 - 3 << 2 (16 - 3) << 2 16 - (3 << 2) +52 52 4 +select 4 << 3 - 2, (4 << 3) - 2, 4 << (3 - 2); +4 << 3 - 2 (4 << 3) - 2 4 << (3 - 2) +8 30 8 +Testing that binary - has precedence over >> +select 16 - 3 >> 2, (16 - 3) >> 2, 16 - (3 >> 2); +16 - 3 >> 2 (16 - 3) >> 2 16 - (3 >> 2) +3 3 16 +select 16 >> 3 - 2, (16 >> 3) - 2, 16 >> (3 - 2); +16 >> 3 - 2 (16 >> 3) - 2 16 >> (3 - 2) +8 0 8 +Testing that * is associative +select 2 * 3 * 4, (2 * 3) * 4, 2 * (3 * 4); +2 * 3 * 4 (2 * 3) * 4 2 * (3 * 4) +24 24 24 +Testing that * has precedence over | +select 2 * 0x40 | 0x0F, (2 * 0x40) | 0x0F, 2 * (0x40 | 0x0F); +2 * 0x40 | 0x0F (2 * 0x40) | 0x0F 2 * (0x40 | 0x0F) +143 143 158 +select 0x0F | 2 * 0x40, (0x0F | 2) * 0x40, 0x0F | (2 * 0x40); +0x0F | 2 * 0x40 (0x0F | 2) * 0x40 0x0F | (2 * 0x40) +143 960 143 +Testing that * has precedence over & +select 2 * 0x40 & 0x55, (2 * 0x40) & 0x55, 2 * (0x40 & 0x55); +2 * 0x40 & 0x55 (2 * 0x40) & 0x55 2 * (0x40 & 0x55) +0 0 128 +select 0xF0 & 2 * 0x40, (0xF0 & 2) * 0x40, 0xF0 & (2 * 0x40); +0xF0 & 2 * 0x40 (0xF0 & 2) * 0x40 0xF0 & (2 * 0x40) +128 0 128 +Testing that * has precedence over << +select 5 * 3 << 4, (5 * 3) << 4, 5 * (3 << 4); +5 * 3 << 4 (5 * 3) << 4 5 * (3 << 4) +240 240 240 +select 2 << 3 * 4, (2 << 3) * 4, 2 << (3 * 4); +2 << 3 * 4 (2 << 3) * 4 2 << (3 * 4) +8192 64 8192 +Testing that * has precedence over >> +select 3 * 4 >> 2, (3 * 4) >> 2, 3 * (4 >> 2); +3 * 4 >> 2 (3 * 4) >> 2 3 * (4 >> 2) +3 3 3 +select 4 >> 2 * 3, (4 >> 2) * 3, 4 >> (2 * 3); +4 >> 2 * 3 (4 >> 2) * 3 4 >> (2 * 3) +0 3 0 +Testing that * has precedence over binary + +select 2 * 3 + 4, (2 * 3) + 4, 2 * (3 + 4); +2 * 3 + 4 (2 * 3) + 4 2 * (3 + 4) +10 10 14 +select 2 + 3 * 4, (2 + 3) * 4, 2 + (3 * 4); +2 + 3 * 4 (2 + 3) * 4 2 + (3 * 4) +14 20 14 +Testing that * has precedence over binary - +select 4 * 3 - 2, (4 * 3) - 2, 4 * (3 - 2); +4 * 3 - 2 (4 * 3) - 2 4 * (3 - 2) +10 10 4 +select 4 - 3 * 2, (4 - 3) * 2, 4 - (3 * 2); +4 - 3 * 2 (4 - 3) * 2 4 - (3 * 2) +-2 2 -2 +Testing that / is left associative +select 15 / 5 / 3, (15 / 5) / 3, 15 / (5 / 3); +15 / 5 / 3 (15 / 5) / 3 15 / (5 / 3) +1.00000000 1.00000000 9.0000 +Testing that / has precedence over | +select 105 / 5 | 2, (105 / 5) | 2, 105 / (5 | 2); +105 / 5 | 2 (105 / 5) | 2 105 / (5 | 2) +23 23 15.0000 +select 105 | 2 / 5, (105 | 2) / 5, 105 | (2 / 5); +105 | 2 / 5 (105 | 2) / 5 105 | (2 / 5) +105 21.4000 105 +Testing that / has precedence over & +select 105 / 5 & 0x0F, (105 / 5) & 0x0F, 105 / (5 & 0x0F); +105 / 5 & 0x0F (105 / 5) & 0x0F 105 / (5 & 0x0F) +5 5 21.0000 +select 0x0F & 105 / 5, (0x0F & 105) / 5, 0x0F & (105 / 5); +0x0F & 105 / 5 (0x0F & 105) / 5 0x0F & (105 / 5) +5 1.8000 5 +Testing that / has precedence over << +select 0x80 / 4 << 2, (0x80 / 4) << 2, 0x80 / (4 << 2); +0x80 / 4 << 2 (0x80 / 4) << 2 0x80 / (4 << 2) +128 128 8.0000 +select 0x80 << 4 / 2, (0x80 << 4) / 2, 0x80 << (4 / 2); +0x80 << 4 / 2 (0x80 << 4) / 2 0x80 << (4 / 2) +512 1024.0000 512 +Testing that / has precedence over >> +select 0x80 / 4 >> 2, (0x80 / 4) >> 2, 0x80 / (4 >> 2); +0x80 / 4 >> 2 (0x80 / 4) >> 2 0x80 / (4 >> 2) +8 8 128.0000 +select 0x80 >> 4 / 2, (0x80 >> 4) / 2, 0x80 >> (4 / 2); +0x80 >> 4 / 2 (0x80 >> 4) / 2 0x80 >> (4 / 2) +32 4.0000 32 +Testing that / has precedence over binary + +select 0x80 / 2 + 2, (0x80 / 2) + 2, 0x80 / (2 + 2); +0x80 / 2 + 2 (0x80 / 2) + 2 0x80 / (2 + 2) +66.0000 66.0000 32.0000 +select 0x80 + 2 / 2, (0x80 + 2) / 2, 0x80 + (2 / 2); +0x80 + 2 / 2 (0x80 + 2) / 2 0x80 + (2 / 2) +129.0000 65.0000 129.0000 +Testing that / has precedence over binary - +select 0x80 / 4 - 2, (0x80 / 4) - 2, 0x80 / (4 - 2); +0x80 / 4 - 2 (0x80 / 4) - 2 0x80 / (4 - 2) +30.0000 30.0000 64.0000 +select 0x80 - 4 / 2, (0x80 - 4) / 2, 0x80 - (4 / 2); +0x80 - 4 / 2 (0x80 - 4) / 2 0x80 - (4 / 2) +126.0000 62.0000 126.0000 +Testing that ^ is associative +select 0xFF ^ 0xF0 ^ 0x0F, (0xFF ^ 0xF0) ^ 0x0F, 0xFF ^ (0xF0 ^ 0x0F); +0xFF ^ 0xF0 ^ 0x0F (0xFF ^ 0xF0) ^ 0x0F 0xFF ^ (0xF0 ^ 0x0F) +0 0 0 +select 0xFF ^ 0xF0 ^ 0x55, (0xFF ^ 0xF0) ^ 0x55, 0xFF ^ (0xF0 ^ 0x55); +0xFF ^ 0xF0 ^ 0x55 (0xFF ^ 0xF0) ^ 0x55 0xFF ^ (0xF0 ^ 0x55) +90 90 90 +Testing that ^ has precedence over | +select 0xFF ^ 0xF0 | 0x0F, (0xFF ^ 0xF0) | 0x0F, 0xFF ^ (0xF0 | 0x0F); +0xFF ^ 0xF0 | 0x0F (0xFF ^ 0xF0) | 0x0F 0xFF ^ (0xF0 | 0x0F) +15 15 0 +select 0xF0 | 0xFF ^ 0xF0, (0xF0 | 0xFF) ^ 0xF0, 0xF0 | (0xFF ^ 0xF0); +0xF0 | 0xFF ^ 0xF0 (0xF0 | 0xFF) ^ 0xF0 0xF0 | (0xFF ^ 0xF0) +255 15 255 +Testing that ^ has precedence over & +select 0xFF ^ 0xF0 & 0x0F, (0xFF ^ 0xF0) & 0x0F, 0xFF ^ (0xF0 & 0x0F); +0xFF ^ 0xF0 & 0x0F (0xFF ^ 0xF0) & 0x0F 0xFF ^ (0xF0 & 0x0F) +15 15 255 +select 0x0F & 0xFF ^ 0xF0, (0x0F & 0xFF) ^ 0xF0, 0x0F & (0xFF ^ 0xF0); +0x0F & 0xFF ^ 0xF0 (0x0F & 0xFF) ^ 0xF0 0x0F & (0xFF ^ 0xF0) +15 255 15 +Testing that ^ has precedence over << +select 0xFF ^ 0xF0 << 2, (0xFF ^ 0xF0) << 2, 0xFF ^ (0xF0 << 2); +0xFF ^ 0xF0 << 2 (0xFF ^ 0xF0) << 2 0xFF ^ (0xF0 << 2) +60 60 831 +select 0x0F << 2 ^ 0xFF, (0x0F << 2) ^ 0xFF, 0x0F << (2 ^ 0xFF); +0x0F << 2 ^ 0xFF (0x0F << 2) ^ 0xFF 0x0F << (2 ^ 0xFF) +0 195 0 +Testing that ^ has precedence over >> +select 0xFF ^ 0xF0 >> 2, (0xFF ^ 0xF0) >> 2, 0xFF ^ (0xF0 >> 2); +0xFF ^ 0xF0 >> 2 (0xFF ^ 0xF0) >> 2 0xFF ^ (0xF0 >> 2) +3 3 195 +select 0xFF >> 2 ^ 0xF0, (0xFF >> 2) ^ 0xF0, 0xFF >> (2 ^ 0xF0); +0xFF >> 2 ^ 0xF0 (0xFF >> 2) ^ 0xF0 0xFF >> (2 ^ 0xF0) +0 207 0 +Testing that ^ has precedence over binary + +select 0xFF ^ 0xF0 + 0x0F, (0xFF ^ 0xF0) + 0x0F, 0xFF ^ (0xF0 + 0x0F); +0xFF ^ 0xF0 + 0x0F (0xFF ^ 0xF0) + 0x0F 0xFF ^ (0xF0 + 0x0F) +30 30 0 +select 0x0F + 0xFF ^ 0xF0, (0x0F + 0xFF) ^ 0xF0, 0x0F + (0xFF ^ 0xF0); +0x0F + 0xFF ^ 0xF0 (0x0F + 0xFF) ^ 0xF0 0x0F + (0xFF ^ 0xF0) +30 510 30 +Testing that ^ has precedence over binary - +select 0xFF ^ 0xF0 - 1, (0xFF ^ 0xF0) - 1, 0xFF ^ (0xF0 - 1); +0xFF ^ 0xF0 - 1 (0xFF ^ 0xF0) - 1 0xFF ^ (0xF0 - 1) +14 14 16 +select 0x55 - 0x0F ^ 0x55, (0x55 - 0x0F) ^ 0x55, 0x55 - (0x0F ^ 0x55); +0x55 - 0x0F ^ 0x55 (0x55 - 0x0F) ^ 0x55 0x55 - (0x0F ^ 0x55) +-5 19 -5 +Testing that ^ has precedence over * +select 0xFF ^ 0xF0 * 2, (0xFF ^ 0xF0) * 2, 0xFF ^ (0xF0 * 2); +0xFF ^ 0xF0 * 2 (0xFF ^ 0xF0) * 2 0xFF ^ (0xF0 * 2) +30 30 287 +select 2 * 0xFF ^ 0xF0, (2 * 0xFF) ^ 0xF0, 2 * (0xFF ^ 0xF0); +2 * 0xFF ^ 0xF0 (2 * 0xFF) ^ 0xF0 2 * (0xFF ^ 0xF0) +30 270 30 +Testing that ^ has precedence over / +select 0xFF ^ 0xF0 / 2, (0xFF ^ 0xF0) / 2, 0xFF ^ (0xF0 / 2); +0xFF ^ 0xF0 / 2 (0xFF ^ 0xF0) / 2 0xFF ^ (0xF0 / 2) +7.5000 7.5000 135 +select 0xF2 / 2 ^ 0xF0, (0xF2 / 2) ^ 0xF0, 0xF2 / (2 ^ 0xF0); +0xF2 / 2 ^ 0xF0 (0xF2 / 2) ^ 0xF0 0xF2 / (2 ^ 0xF0) +1.0000 137 1.0000 +Testing that ^ has precedence over % +select 0xFF ^ 0xF0 % 0x20, (0xFF ^ 0xF0) % 0x20, 0xFF ^ (0xF0 % 0x20); +0xFF ^ 0xF0 % 0x20 (0xFF ^ 0xF0) % 0x20 0xFF ^ (0xF0 % 0x20) +15 15 239 +select 0xFF % 0x20 ^ 0xF0, (0xFF % 0x20) ^ 0xF0, 0xFF % (0x20 ^ 0xF0); +0xFF % 0x20 ^ 0xF0 (0xFF % 0x20) ^ 0xF0 0xFF % (0x20 ^ 0xF0) +47 239 47 +Testing that ^ has precedence over DIV +select 0xFF ^ 0xF0 DIV 2, (0xFF ^ 0xF0) DIV 2, 0xFF ^ (0xF0 DIV 2); +0xFF ^ 0xF0 DIV 2 (0xFF ^ 0xF0) DIV 2 0xFF ^ (0xF0 DIV 2) +7 7 135 +select 0xF2 DIV 2 ^ 0xF0, (0xF2 DIV 2) ^ 0xF0, 0xF2 DIV (2 ^ 0xF0); +0xF2 DIV 2 ^ 0xF0 (0xF2 DIV 2) ^ 0xF0 0xF2 DIV (2 ^ 0xF0) +1 137 1 +Testing that ^ has precedence over MOD +select 0xFF ^ 0xF0 MOD 0x20, (0xFF ^ 0xF0) MOD 0x20, 0xFF ^ (0xF0 MOD 0x20); +0xFF ^ 0xF0 MOD 0x20 (0xFF ^ 0xF0) MOD 0x20 0xFF ^ (0xF0 MOD 0x20) +15 15 239 +select 0xFF MOD 0x20 ^ 0xF0, (0xFF MOD 0x20) ^ 0xF0, 0xFF MOD (0x20 ^ 0xF0); +0xFF MOD 0x20 ^ 0xF0 (0xFF MOD 0x20) ^ 0xF0 0xFF MOD (0x20 ^ 0xF0) +47 239 47 diff --git a/mysql-test/r/query_cache_ps_no_prot.result b/mysql-test/r/query_cache_ps_no_prot.result index 29d16d8a619..0efb2540c64 100644 --- a/mysql-test/r/query_cache_ps_no_prot.result +++ b/mysql-test/r/query_cache_ps_no_prot.result @@ -371,5 +371,163 @@ Variable_name Value Qcache_hits 21 drop table t1; ---- disconnect connection con1 ---- +######################################################################## +# +# BUG#25843: Changing default database between PREPARE and EXECUTE of +# statement breaks binlog. +# +######################################################################## + +# +# Check that default database and its attributes are fixed at the +# creation time. +# + +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; + +CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci; +CREATE DATABASE mysqltest2 COLLATE utf8_general_ci; + +CREATE TABLE mysqltest1.t1(msg VARCHAR(255)); +CREATE TABLE mysqltest2.t1(msg VARCHAR(255)); + +use mysqltest1; +PREPARE stmt_a_1 FROM 'INSERT INTO t1 VALUES(DATABASE())'; +PREPARE stmt_a_2 FROM 'INSERT INTO t1 VALUES(@@collation_database)'; + +EXECUTE stmt_a_1; +EXECUTE stmt_a_2; + +use mysqltest2; +EXECUTE stmt_a_1; +EXECUTE stmt_a_2; + +SELECT * FROM mysqltest1.t1; +msg +mysqltest1 +utf8_unicode_ci +mysqltest1 +utf8_unicode_ci + +SELECT * FROM mysqltest2.t1; +msg + +DROP PREPARE stmt_a_1; +DROP PREPARE stmt_a_2; + +# +# The Query Cache test case. +# + +DELETE FROM mysqltest1.t1; +DELETE FROM mysqltest2.t1; + +INSERT INTO mysqltest1.t1 VALUES('mysqltest1.t1'); +INSERT INTO mysqltest2.t1 VALUES('mysqltest2.t1'); + +use mysqltest1; +PREPARE stmt_b_1 FROM 'SELECT * FROM t1'; + +use mysqltest2; +PREPARE stmt_b_2 FROM 'SELECT * FROM t1'; + +EXECUTE stmt_b_1; +msg +mysqltest1.t1 + +EXECUTE stmt_b_2; +msg +mysqltest2.t1 + +use mysqltest1; + +EXECUTE stmt_b_1; +msg +mysqltest1.t1 + +EXECUTE stmt_b_2; +msg +mysqltest2.t1 + +DROP PREPARE stmt_b_1; +DROP PREPARE stmt_b_2; + +use test; + +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; + +# +# Check that prepared statements work properly when there is no current +# database. +# + +CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci; +CREATE DATABASE mysqltest2 COLLATE utf8_general_ci; + +use mysqltest1; + +PREPARE stmt_c_1 FROM 'SELECT DATABASE(), @@collation_database'; + +use mysqltest2; + +PREPARE stmt_c_2 FROM 'SELECT DATABASE(), @@collation_database'; + +DROP DATABASE mysqltest2; + +SELECT DATABASE(), @@collation_database; +DATABASE() @@collation_database +NULL latin1_swedish_ci + +EXECUTE stmt_c_1; +DATABASE() @@collation_database +mysqltest1 utf8_unicode_ci + +SELECT DATABASE(), @@collation_database; +DATABASE() @@collation_database +NULL latin1_swedish_ci + +EXECUTE stmt_c_2; +DATABASE() @@collation_database +NULL latin1_swedish_ci +Warnings: +Note 1049 Unknown database 'mysqltest2' + +SELECT DATABASE(), @@collation_database; +DATABASE() @@collation_database +NULL latin1_swedish_ci + +PREPARE stmt_c_3 FROM 'SELECT DATABASE(), @@collation_database'; + +EXECUTE stmt_c_3; +DATABASE() @@collation_database +NULL latin1_swedish_ci + +use mysqltest1; + +EXECUTE stmt_c_2; +DATABASE() @@collation_database +NULL latin1_swedish_ci +Warnings: +Note 1049 Unknown database 'mysqltest2' + +SELECT DATABASE(), @@collation_database; +DATABASE() @@collation_database +mysqltest1 utf8_unicode_ci + +EXECUTE stmt_c_3; +DATABASE() @@collation_database +NULL latin1_swedish_ci + +SELECT DATABASE(), @@collation_database; +DATABASE() @@collation_database +mysqltest1 utf8_unicode_ci + +DROP DATABASE mysqltest1; + +use test; + +######################################################################## set @@global.query_cache_size=@initial_query_cache_size; flush status; diff --git a/mysql-test/r/query_cache_ps_ps_prot.result b/mysql-test/r/query_cache_ps_ps_prot.result index ba675d57f50..dc0c4a0193a 100644 --- a/mysql-test/r/query_cache_ps_ps_prot.result +++ b/mysql-test/r/query_cache_ps_ps_prot.result @@ -371,5 +371,163 @@ Variable_name Value Qcache_hits 19 drop table t1; ---- disconnect connection con1 ---- +######################################################################## +# +# BUG#25843: Changing default database between PREPARE and EXECUTE of +# statement breaks binlog. +# +######################################################################## + +# +# Check that default database and its attributes are fixed at the +# creation time. +# + +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; + +CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci; +CREATE DATABASE mysqltest2 COLLATE utf8_general_ci; + +CREATE TABLE mysqltest1.t1(msg VARCHAR(255)); +CREATE TABLE mysqltest2.t1(msg VARCHAR(255)); + +use mysqltest1; +PREPARE stmt_a_1 FROM 'INSERT INTO t1 VALUES(DATABASE())'; +PREPARE stmt_a_2 FROM 'INSERT INTO t1 VALUES(@@collation_database)'; + +EXECUTE stmt_a_1; +EXECUTE stmt_a_2; + +use mysqltest2; +EXECUTE stmt_a_1; +EXECUTE stmt_a_2; + +SELECT * FROM mysqltest1.t1; +msg +mysqltest1 +utf8_unicode_ci +mysqltest1 +utf8_unicode_ci + +SELECT * FROM mysqltest2.t1; +msg + +DROP PREPARE stmt_a_1; +DROP PREPARE stmt_a_2; + +# +# The Query Cache test case. +# + +DELETE FROM mysqltest1.t1; +DELETE FROM mysqltest2.t1; + +INSERT INTO mysqltest1.t1 VALUES('mysqltest1.t1'); +INSERT INTO mysqltest2.t1 VALUES('mysqltest2.t1'); + +use mysqltest1; +PREPARE stmt_b_1 FROM 'SELECT * FROM t1'; + +use mysqltest2; +PREPARE stmt_b_2 FROM 'SELECT * FROM t1'; + +EXECUTE stmt_b_1; +msg +mysqltest1.t1 + +EXECUTE stmt_b_2; +msg +mysqltest2.t1 + +use mysqltest1; + +EXECUTE stmt_b_1; +msg +mysqltest1.t1 + +EXECUTE stmt_b_2; +msg +mysqltest2.t1 + +DROP PREPARE stmt_b_1; +DROP PREPARE stmt_b_2; + +use test; + +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; + +# +# Check that prepared statements work properly when there is no current +# database. +# + +CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci; +CREATE DATABASE mysqltest2 COLLATE utf8_general_ci; + +use mysqltest1; + +PREPARE stmt_c_1 FROM 'SELECT DATABASE(), @@collation_database'; + +use mysqltest2; + +PREPARE stmt_c_2 FROM 'SELECT DATABASE(), @@collation_database'; + +DROP DATABASE mysqltest2; + +SELECT DATABASE(), @@collation_database; +DATABASE() @@collation_database +NULL latin1_swedish_ci + +EXECUTE stmt_c_1; +DATABASE() @@collation_database +mysqltest1 utf8_unicode_ci + +SELECT DATABASE(), @@collation_database; +DATABASE() @@collation_database +NULL latin1_swedish_ci + +EXECUTE stmt_c_2; +DATABASE() @@collation_database +NULL latin1_swedish_ci +Warnings: +Note 1049 Unknown database 'mysqltest2' + +SELECT DATABASE(), @@collation_database; +DATABASE() @@collation_database +NULL latin1_swedish_ci + +PREPARE stmt_c_3 FROM 'SELECT DATABASE(), @@collation_database'; + +EXECUTE stmt_c_3; +DATABASE() @@collation_database +NULL latin1_swedish_ci + +use mysqltest1; + +EXECUTE stmt_c_2; +DATABASE() @@collation_database +NULL latin1_swedish_ci +Warnings: +Note 1049 Unknown database 'mysqltest2' + +SELECT DATABASE(), @@collation_database; +DATABASE() @@collation_database +mysqltest1 utf8_unicode_ci + +EXECUTE stmt_c_3; +DATABASE() @@collation_database +NULL latin1_swedish_ci + +SELECT DATABASE(), @@collation_database; +DATABASE() @@collation_database +mysqltest1 utf8_unicode_ci + +DROP DATABASE mysqltest1; + +use test; + +######################################################################## set @@global.query_cache_size=@initial_query_cache_size; flush status; diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 675a59f1fb7..2e0d437aeb6 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -969,6 +969,18 @@ CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create user 'mysqltest ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. CREATE FUNCTION bug_13627_f() returns int BEGIN create user 'mysqltest_1'; return 1; END | ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER bug21975 BEFORE INSERT ON t1 FOR EACH ROW BEGIN grant select on t1 to 'mysqltest_1'; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug21975() returns int BEGIN grant select on t1 to 'mysqltest_1'; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER bug21975 BEFORE INSERT ON t1 FOR EACH ROW BEGIN revoke select on t1 from 'mysqltest_1'; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug21975() returns int BEGIN revoke select on t1 from 'mysqltest_1'; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER bug21975 BEFORE INSERT ON t1 FOR EACH ROW BEGIN revoke all privileges on *.* from 'mysqltest_1'; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug21975() returns int BEGIN revoke all privileges on *.* from 'mysqltest_1'; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop user 'mysqltest_1'; END | ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. CREATE FUNCTION bug_13627_f() returns int BEGIN drop user 'mysqltest_1'; return 1; END | diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 163bbb4aab4..2abff35b232 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -6546,4 +6546,79 @@ DROP VIEW v1; DROP FUNCTION f1; DROP FUNCTION f2; DROP TABLE t1; +drop table if exists t1; +drop procedure if exists p1; +create table t1 (value varchar(15)); +create procedure p1() update t1 set value='updated' where value='old'; +call p1(); +insert into t1 (value) values ("old"); +select get_lock('b26162',120); +get_lock('b26162',120) +1 +select 'rl_acquirer', value from t1 where get_lock('b26162',120);; +set session low_priority_updates=on; +call p1();; +select 'rl_contender', value from t1; +rl_contender value +rl_contender old +select release_lock('b26162'); +release_lock('b26162') +1 +rl_acquirer value +rl_acquirer old +drop procedure p1; +drop table t1; +set session low_priority_updates=default; + +# Bug#13675. + +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP TABLE IF EXISTS t1; + +CREATE PROCEDURE p1(v DATETIME) CREATE TABLE t1 SELECT v; +CREATE PROCEDURE p2(v INT) CREATE TABLE t1 SELECT v; + +CALL p1(NOW()); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `v` datetime DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 + +DROP TABLE t1; + +CALL p1('text'); +Warnings: +Warning 1264 Out of range value for column 'v' at row 1 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `v` datetime DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 + +DROP TABLE t1; + +CALL p2(10); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `v` bigint(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 + +DROP TABLE t1; + +CALL p2('text'); +Warnings: +Warning 1366 Incorrect integer value: 'text' for column 'v' at row 1 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `v` bigint(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 + +DROP TABLE t1; + +DROP PROCEDURE p1; +DROP PROCEDURE p2; End of 5.0 tests diff --git a/mysql-test/suite/rpl/r/rpl_binlog_grant.result b/mysql-test/suite/rpl/r/rpl_binlog_grant.result new file mode 100644 index 00000000000..1692bcee21f --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_binlog_grant.result @@ -0,0 +1,50 @@ +drop database if exists d1; +create database d1; +use d1; +create table t (s1 int) engine=innodb; +set @@autocommit=0; +start transaction; +insert into t values (1); +grant select on t to x@y; +rollback; +show grants for x@y; +Grants for x@y +GRANT USAGE ON *.* TO 'x'@'y' +GRANT SELECT ON `d1`.`t` TO 'x'@'y' +show binlog events; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 106 Server ver: VERSION, Binlog ver: 4 +master-bin.000001 106 Query 1 193 drop database if exists d1 +master-bin.000001 193 Query 1 272 create database d1 +master-bin.000001 272 Query 1 370 use `d1`; create table t (s1 int) engine=innodb +master-bin.000001 370 Query 1 436 use `d1`; BEGIN +master-bin.000001 436 Query 1 521 use `d1`; insert into t values (1) +master-bin.000001 521 Xid 1 548 COMMIT /* xid=12 */ +master-bin.000001 548 Query 1 633 use `d1`; grant select on t to x@y +start transaction; +insert into t values (2); +revoke select on t from x@y; +commit; +select * from t; +s1 +1 +2 +show grants for x@y; +Grants for x@y +GRANT USAGE ON *.* TO 'x'@'y' +show binlog events; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 106 Server ver: VERSION, Binlog ver: 4 +master-bin.000001 106 Query 1 193 drop database if exists d1 +master-bin.000001 193 Query 1 272 create database d1 +master-bin.000001 272 Query 1 370 use `d1`; create table t (s1 int) engine=innodb +master-bin.000001 370 Query 1 436 use `d1`; BEGIN +master-bin.000001 436 Query 1 521 use `d1`; insert into t values (1) +master-bin.000001 521 Xid 1 548 COMMIT /* xid=12 */ +master-bin.000001 548 Query 1 633 use `d1`; grant select on t to x@y +master-bin.000001 633 Query 1 699 use `d1`; BEGIN +master-bin.000001 699 Query 1 784 use `d1`; insert into t values (2) +master-bin.000001 784 Xid 1 811 COMMIT /* xid=18 */ +master-bin.000001 811 Query 1 899 use `d1`; revoke select on t from x@y +drop user x@y; +drop database d1; diff --git a/mysql-test/suite/rpl/r/rpl_ps.result b/mysql-test/suite/rpl/r/rpl_ps.result index 73c36af4862..faba43ae934 100644 --- a/mysql-test/suite/rpl/r/rpl_ps.result +++ b/mysql-test/suite/rpl/r/rpl_ps.result @@ -26,5 +26,55 @@ from-master-2-'', from-var-from-master-3 drop table t1; stop slave; + +######################################################################## +# +# BUG#25843: Changing default database between PREPARE and EXECUTE of +# statement breaks binlog. +# +######################################################################## + +# Connection: slave + + +START SLAVE; + +# Connection: master + + +CREATE DATABASE mysqltest1; +CREATE TABLE t1(db_name CHAR(32), db_col_name CHAR(32)); + +PREPARE stmt_d_1 FROM 'INSERT INTO t1 VALUES(DATABASE(), @@collation_database)'; + +EXECUTE stmt_d_1; + +use mysqltest1; + +EXECUTE stmt_d_1; + + +# Connection: slave + + +SELECT * FROM t1; +db_name db_col_name +test latin1_swedish_ci +test latin1_swedish_ci + +# Connection: master + + +DROP DATABASE mysqltest1; + +use test; + + +# Connection: slave + + +STOP SLAVE; + +######################################################################## reset master; reset slave; diff --git a/mysql-test/suite/rpl/t/rpl_binlog_grant.test b/mysql-test/suite/rpl/t/rpl_binlog_grant.test new file mode 100644 index 00000000000..b6868f7ebf8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_grant.test @@ -0,0 +1,41 @@ +-- source include/have_innodb.inc +-- source include/not_embedded.inc +-- source include/have_binlog_format_mixed_or_statement.inc + +let $VERSION=`select version()`; + +# Bug #21975: grant/revoke statements in transaction +# used to disappear from binlog upon rallback. +# Now GRANT/REVOKE do implicitly commit +# transaction + +--disable_warnings +drop database if exists d1; +--enable_warnings +create database d1; +use d1; +create table t (s1 int) engine=innodb; +set @@autocommit=0; +start transaction; +insert into t values (1); +grant select on t to x@y; +# +# There is no active transaction here +# +rollback; +show grants for x@y; +--replace_result $VERSION VERSION +show binlog events; +start transaction; +insert into t values (2); +revoke select on t from x@y; +# +# There is no active transaction here +# +commit; +select * from t; +show grants for x@y; +--replace_result $VERSION VERSION +show binlog events; +drop user x@y; +drop database d1; diff --git a/mysql-test/suite/rpl/t/rpl_ps.test b/mysql-test/suite/rpl/t/rpl_ps.test index b8792722192..27f1ac3348d 100644 --- a/mysql-test/suite/rpl/t/rpl_ps.test +++ b/mysql-test/suite/rpl/t/rpl_ps.test @@ -46,6 +46,101 @@ stop slave; # End of 4.1 tests +# +# Bug #25843 Changing default database between PREPARE and EXECUTE of statement +# breaks binlog. +# +# There were actually two problems discovered by this bug: +# +# 1. Default (current) database is not fixed at the creation time. +# That leads to wrong output of DATABASE() function. +# +# 2. Database attributes (@@collation_database) are not fixed at the creation +# time. That leads to wrong resultset. +# +# Binlog breakage and Query Cache wrong output happened because of the first +# problem. +# + +--echo +--echo ######################################################################## +--echo # +--echo # BUG#25843: Changing default database between PREPARE and EXECUTE of +--echo # statement breaks binlog. +--echo # +--echo ######################################################################## + +############################################################################### + +--echo +--echo # Connection: slave +--echo +--connection slave + +--echo +START SLAVE; + +--echo +--echo # Connection: master +--echo +--connection master + +--echo +CREATE DATABASE mysqltest1; +CREATE TABLE t1(db_name CHAR(32), db_col_name CHAR(32)); + +--echo +PREPARE stmt_d_1 FROM 'INSERT INTO t1 VALUES(DATABASE(), @@collation_database)'; + +--echo +EXECUTE stmt_d_1; + +--echo +use mysqltest1; + +--echo +EXECUTE stmt_d_1; + +--echo +--save_master_pos + +--echo +--echo # Connection: slave +--echo +--connection slave +--sync_with_master + +--echo +SELECT * FROM t1; + +--echo +--echo # Connection: master +--echo +--connection master + +--echo +DROP DATABASE mysqltest1; + +--echo +use test; + +--echo +--save_master_pos + +--echo +--echo # Connection: slave +--echo +--connection slave +--sync_with_master + +--echo +STOP SLAVE; + +--echo +--echo ######################################################################## + +############################################################################### + reset master; reset slave; disconnect master; diff --git a/mysql-test/t/comments.test b/mysql-test/t/comments.test index 8ae6ba5779e..3a18a8bd483 100644 --- a/mysql-test/t/comments.test +++ b/mysql-test/t/comments.test @@ -34,3 +34,34 @@ select 1/*!999992*/; select 1 + /*!00000 2 */ + 3 /*!99999 noise*/ + 4; +# +# Bug#28779 (mysql_query() allows execution of statements with unbalanced +# comments) +# + +--disable_warnings +drop table if exists table_28779; +--enable_warnings + +create table table_28779 (a int); + +--error 1064 +prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*' AND b = 'bar';"; + +--error 1064 +prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*' AND b = 'bar';*"; + +--error 1064 +prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*! AND 2=2;"; + +--error 1064 +prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*! AND 2=2;*"; + +--error 1064 +prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*!98765' AND b = 'bar';"; + +--error 1064 +prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*!98765' AND b = 'bar';*"; + +drop table table_28779; + diff --git a/mysql-test/t/events.test b/mysql-test/t/events.test index d7232705b81..20134765609 100644 --- a/mysql-test/t/events.test +++ b/mysql-test/t/events.test @@ -432,8 +432,11 @@ create event закачка on schedule every 10 hour do select get_lock("test_l --echo "Should return 1 row" select definer, name, db from mysql.event; ---echo "Should be only 1 process" -select /*1*/ user, host, db, command, state, info from information_schema.processlist where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info; +--echo "Should be only 0 process" +select /*1*/ user, host, db, command, state, info + from information_schema.processlist + where (user='event_scheduler') + order by info; select release_lock("test_lock1"); drop event закачка; --echo "Should have 0 events" @@ -447,14 +450,28 @@ set global event_scheduler=on; select get_lock("test_lock2", 20); --echo "Create an event which tries to acquire a mutex. The event locks on the mutex" create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20); ---echo "Let some time pass to the event starts" ---sleep 1 + --echo "Should have only 2 processes: the scheduler and the locked event" -select /*2*/ user, host, db, command, state, info from information_schema.processlist where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info;--echo "Release the mutex, the event worker should finish." +let $wait_condition= select count(*) = 2 from information_schema.processlist + where ( (state like 'User lock%' AND info like 'select get_lock%') + OR (command='Daemon' AND user='event_scheduler')); +--source include/wait_condition.inc + +select /*2*/ user, host, db, command, state, info + from information_schema.processlist + where (info like "select get_lock%" OR user='event_scheduler') + order by info; --echo "Release the mutex, the event worker should finish." select release_lock("test_lock2"); drop event закачка; +# Wait for release_lock("test_lock2") to complete, +# to avoid polluting the next test information_schema.processlist +let $wait_condition= select count(*) = 0 from information_schema.processlist + where (state like 'User lock%' AND info like 'select get_lock%'); +--source include/wait_condition.inc + + ## ## 1. get a lock ## 2. create an event @@ -466,13 +483,30 @@ drop event закачка; set global event_scheduler=1; select get_lock("test_lock2_1", 20); create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20); ---sleep 1 ---echo "Should have only 3 processes: the scheduler, our conn and the locked event" -select /*3*/ user, host, db, command, state, info from information_schema.processlist where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info; + +--echo "Should have only 2 processes: the scheduler and the locked event" +let $wait_condition= select count(*) = 2 from information_schema.processlist + where ( (state like 'User lock%' AND info like 'select get_lock%') + OR (command='Daemon' AND user='event_scheduler')); +--source include/wait_condition.inc + +select /*3*/ user, host, db, command, state, info + from information_schema.processlist + where (info like "select get_lock%" OR user='event_scheduler') + order by info; + set global event_scheduler=off; ---sleep 0.8 + +let $wait_condition= select count(*) =1 from information_schema.processlist + where (info like "select get_lock%" OR user='event_scheduler'); +--source include/wait_condition.inc + --echo "Should have only our process now:" -select /*4*/ user, host, db, command, state, info from information_schema.processlist where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info; +select /*4*/ user, host, db, command, state, info + from information_schema.processlist + where (info like "select get_lock%" OR user='event_scheduler') + order by info; +select release_lock("test_lock2_1"); drop event закачка21; let $wait_condition= select count(*) = 0 from information_schema.processlist diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index 67f21731afe..aad241e031f 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -306,3 +306,38 @@ insert into t1(f1) values(1) on duplicate key update f1=1; select @stamp2:=f2 from t1; select if( @stamp1 = @stamp2, "correct", "wrong"); drop table t1; + +# +# Bug#28587 SELECT is blocked by INSERT waiting on read lock, even with low_priority_updates +# +--echo connection: default +set low_priority_updates=1; +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int, b int, unique key t1$a (a)); +lock table t1 read; +connect (update,localhost,root,,); +connection update; +--echo connection: update +set low_priority_updates=1; +show variables like 'low_priority_updates'; +let $ID= `select connection_id()`; +--send insert into t1 values (1, 2) ON DUPLICATE KEY UPDATE b = 2; +connection default; +# we must wait till the insert opens and locks the table +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Locked" and id = $ID; +--source include/wait_condition.inc +connect (select,localhost,root,,); +--echo connection: select +select * from t1; +connection default; +--echo connection: default +select * from t1; +connection default; +disconnect update; +disconnect select; +drop table t1; +set low_priority_updates=default; diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index ac713d49b92..3ee04f32640 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -277,6 +277,11 @@ remove_file $MYSQLTEST_VARDIR/tmp/bug21412.sql; --exec $MYSQL --pager="540bytelengthstringxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -e "select 1" > /dev/null 2>&1 --exec $MYSQL --character-sets-dir="540bytelengthstringxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -e "select 1" 2>&1 +# +# bug #30164: Using client side macro inside server side comments generates broken queries +# +--exec $MYSQL test -e "/*! \C latin1 */ select 1;" + --echo End of 5.0 tests # diff --git a/mysql-test/t/parser_precedence.test b/mysql-test/t/parser_precedence.test new file mode 100644 index 00000000000..484c8759779 --- /dev/null +++ b/mysql-test/t/parser_precedence.test @@ -0,0 +1,333 @@ + +--disable_warnings +drop table if exists t1_30237_bool; +--enable_warnings + +create table t1_30237_bool(A boolean, B boolean, C boolean); + +insert into t1_30237_bool values +(FALSE, FALSE, FALSE), +(FALSE, FALSE, NULL), +(FALSE, FALSE, TRUE), +(FALSE, NULL, FALSE), +(FALSE, NULL, NULL), +(FALSE, NULL, TRUE), +(FALSE, TRUE, FALSE), +(FALSE, TRUE, NULL), +(FALSE, TRUE, TRUE), +(NULL, FALSE, FALSE), +(NULL, FALSE, NULL), +(NULL, FALSE, TRUE), +(NULL, NULL, FALSE), +(NULL, NULL, NULL), +(NULL, NULL, TRUE), +(NULL, TRUE, FALSE), +(NULL, TRUE, NULL), +(NULL, TRUE, TRUE), +(TRUE, FALSE, FALSE), +(TRUE, FALSE, NULL), +(TRUE, FALSE, TRUE), +(TRUE, NULL, FALSE), +(TRUE, NULL, NULL), +(TRUE, NULL, TRUE), +(TRUE, TRUE, FALSE), +(TRUE, TRUE, NULL), +(TRUE, TRUE, TRUE) ; + +--echo Testing OR, XOR, AND +select A, B, A OR B, A XOR B, A AND B + from t1_30237_bool where C is null order by A, B; + +--echo Testing that OR is associative +select A, B, C, (A OR B) OR C, A OR (B OR C), A OR B OR C + from t1_30237_bool order by A, B, C; + +select count(*) from t1_30237_bool + where ((A OR B) OR C) != (A OR (B OR C)); + +--echo Testing that XOR is associative +select A, B, C, (A XOR B) XOR C, A XOR (B XOR C), A XOR B XOR C + from t1_30237_bool order by A, B, C; + +select count(*) from t1_30237_bool + where ((A XOR B) XOR C) != (A XOR (B XOR C)); + +--echo Testing that AND is associative +select A, B, C, (A AND B) AND C, A AND (B AND C), A AND B AND C + from t1_30237_bool order by A, B, C; + +select count(*) from t1_30237_bool + where ((A AND B) AND C) != (A AND (B AND C)); + +--echo Testing that AND has precedence over OR +select A, B, C, (A OR B) AND C, A OR (B AND C), A OR B AND C + from t1_30237_bool order by A, B, C; +select count(*) from t1_30237_bool + where (A OR (B AND C)) != (A OR B AND C); +select A, B, C, (A AND B) OR C, A AND (B OR C), A AND B OR C + from t1_30237_bool order by A, B, C; +select count(*) from t1_30237_bool + where ((A AND B) OR C) != (A AND B OR C); + +--echo Testing that AND has precedence over XOR +select A, B, C, (A XOR B) AND C, A XOR (B AND C), A XOR B AND C + from t1_30237_bool order by A, B, C; +select count(*) from t1_30237_bool + where (A XOR (B AND C)) != (A XOR B AND C); +select A, B, C, (A AND B) XOR C, A AND (B XOR C), A AND B XOR C + from t1_30237_bool order by A, B, C; +select count(*) from t1_30237_bool + where ((A AND B) XOR C) != (A AND B XOR C); + +--echo Testing that XOR has precedence over OR +select A, B, C, (A XOR B) OR C, A XOR (B OR C), A XOR B OR C + from t1_30237_bool order by A, B, C; +select count(*) from t1_30237_bool + where ((A XOR B) OR C) != (A XOR B OR C); +select A, B, C, (A OR B) XOR C, A OR (B XOR C), A OR B XOR C + from t1_30237_bool order by A, B, C; +select count(*) from t1_30237_bool + where (A OR (B XOR C)) != (A OR B XOR C); + +drop table t1_30237_bool; + +--echo Testing that NOT has precedence over OR +select (NOT FALSE) OR TRUE, NOT (FALSE OR TRUE), NOT FALSE OR TRUE; + +--echo Testing that NOT has precedence over XOR +select (NOT FALSE) XOR FALSE, NOT (FALSE XOR FALSE), NOT FALSE XOR FALSE; + +--echo Testing that NOT has precedence over AND +select (NOT FALSE) AND FALSE, NOT (FALSE AND FALSE), NOT FALSE AND FALSE; + +--echo Testing that NOT is associative +select NOT NOT TRUE, NOT NOT NOT FALSE; + +--echo Testing that IS has precedence over NOT +select (NOT NULL) IS TRUE, NOT (NULL IS TRUE), NOT NULL IS TRUE; +select (NOT NULL) IS NOT TRUE, NOT (NULL IS NOT TRUE), NOT NULL IS NOT TRUE; +select (NOT NULL) IS FALSE, NOT (NULL IS FALSE), NOT NULL IS FALSE; +select (NOT NULL) IS NOT FALSE, NOT (NULL IS NOT FALSE), NOT NULL IS NOT FALSE; +select (NOT TRUE) IS UNKNOWN, NOT (TRUE IS UNKNOWN), NOT TRUE IS UNKNOWN; +select (NOT TRUE) IS NOT UNKNOWN, NOT (TRUE IS NOT UNKNOWN), NOT TRUE IS NOT UNKNOWN; +select (NOT TRUE) IS NULL, NOT (TRUE IS NULL), NOT TRUE IS NULL; +select (NOT TRUE) IS NOT NULL, NOT (TRUE IS NOT NULL), NOT TRUE IS NOT NULL; + +--echo Testing that IS [NOT] TRUE/FALSE/UNKNOWN predicates are not associative +# Documenting existing behavior in 5.0.48 +-- error ER_PARSE_ERROR +select TRUE IS TRUE IS TRUE IS TRUE; +-- error ER_PARSE_ERROR +select FALSE IS NOT TRUE IS NOT TRUE IS NOT TRUE; +-- error ER_PARSE_ERROR +select NULL IS FALSE IS FALSE IS FALSE; +-- error ER_PARSE_ERROR +select TRUE IS NOT FALSE IS NOT FALSE IS NOT FALSE; +-- error ER_PARSE_ERROR +select FALSE IS UNKNOWN IS UNKNOWN IS UNKNOWN; +-- error ER_PARSE_ERROR +select TRUE IS NOT UNKNOWN IS NOT UNKNOWN IS NOT UNKNOWN; + +--echo Testing that IS [NOT] NULL predicates are associative +# Documenting existing behavior in 5.0.48 +select FALSE IS NULL IS NULL IS NULL; +select TRUE IS NOT NULL IS NOT NULL IS NOT NULL; + +--echo Testing that comparison operators are left associative +select 1 <=> 2 <=> 2, (1 <=> 2) <=> 2, 1 <=> (2 <=> 2); +select 1 = 2 = 2, (1 = 2) = 2, 1 = (2 = 2); +select 1 != 2 != 3, (1 != 2) != 3, 1 != (2 != 3); +select 1 <> 2 <> 3, (1 <> 2) <> 3, 1 <> (2 <> 3); +select 1 < 2 < 3, (1 < 2) < 3, 1 < (2 < 3); +select 3 <= 2 <= 1, (3 <= 2) <= 1, 3 <= (2 <= 1); +select 1 > 2 > 3, (1 > 2) > 3, 1 > (2 > 3); +select 1 >= 2 >= 3, (1 >= 2) >= 3, 1 >= (2 >= 3); + +-- echo Testing that | is associative +select 0xF0 | 0x0F | 0x55, (0xF0 | 0x0F) | 0x55, 0xF0 | (0x0F | 0x55); + +-- echo Testing that & is associative +select 0xF5 & 0x5F & 0x55, (0xF5 & 0x5F) & 0x55, 0xF5 & (0x5F & 0x55); + +-- echo Testing that << is left associative +select 4 << 3 << 2, (4 << 3) << 2, 4 << (3 << 2); + +-- echo Testing that >> is left associative +select 256 >> 3 >> 2, (256 >> 3) >> 2, 256 >> (3 >> 2); + +--echo Testing that & has precedence over | +select 0xF0 & 0x0F | 0x55, (0xF0 & 0x0F) | 0x55, 0xF0 & (0x0F | 0x55); +select 0x55 | 0xF0 & 0x0F, (0x55 | 0xF0) & 0x0F, 0x55 | (0xF0 & 0x0F); + +--echo Testing that << has precedence over | +select 0x0F << 4 | 0x0F, (0x0F << 4) | 0x0F, 0x0F << (4 | 0x0F); +select 0x0F | 0x0F << 4, (0x0F | 0x0F) << 4, 0x0F | (0x0F << 4); + +--echo Testing that >> has precedence over | +select 0xF0 >> 4 | 0xFF, (0xF0 >> 4) | 0xFF, 0xF0 >> (4 | 0xFF); +select 0xFF | 0xF0 >> 4, (0xFF | 0xF0) >> 4, 0xFF | (0xF0 >> 4); + +--echo Testing that << has precedence over & +select 0x0F << 4 & 0xF0, (0x0F << 4) & 0xF0, 0x0F << (4 & 0xF0); +select 0xF0 & 0x0F << 4, (0xF0 & 0x0F) << 4, 0xF0 & (0x0F << 4); + +--echo Testing that >> has precedence over & +select 0xF0 >> 4 & 0x55, (0xF0 >> 4) & 0x55, 0xF0 >> (4 & 0x55); +select 0x0F & 0xF0 >> 4, (0x0F & 0xF0) >> 4, 0x0F & (0xF0 >> 4); + +--echo Testing that >> and << have the same precedence +select 0xFF >> 4 << 2, (0xFF >> 4) << 2, 0xFF >> (4 << 2); +select 0x0F << 4 >> 2, (0x0F << 4) >> 2, 0x0F << (4 >> 2); + +--echo Testing that binary + is associative +select 1 + 2 + 3, (1 + 2) + 3, 1 + (2 + 3); + +--echo Testing that binary - is left associative +select 1 - 2 - 3, (1 - 2) - 3, 1 - (2 - 3); + +--echo Testing that binary + and binary - have the same precedence +# evaluated left to right +select 1 + 2 - 3, (1 + 2) - 3, 1 + (2 - 3); +select 1 - 2 + 3, (1 - 2) + 3, 1 - (2 + 3); + +--echo Testing that binary + has precedence over | +select 0xF0 + 0x0F | 0x55, (0xF0 + 0x0F) | 0x55, 0xF0 + (0x0F | 0x55); +select 0x55 | 0xF0 + 0x0F, (0x55 | 0xF0) + 0x0F, 0x55 | (0xF0 + 0x0F); + +--echo Testing that binary + has precedence over & +select 0xF0 + 0x0F & 0x55, (0xF0 + 0x0F) & 0x55, 0xF0 + (0x0F & 0x55); +select 0x55 & 0xF0 + 0x0F, (0x55 & 0xF0) + 0x0F, 0x55 & (0xF0 + 0x0F); + +--echo Testing that binary + has precedence over << +select 2 + 3 << 4, (2 + 3) << 4, 2 + (3 << 4); +select 3 << 4 + 2, (3 << 4) + 2, 3 << (4 + 2); + +--echo Testing that binary + has precedence over >> +select 4 + 3 >> 2, (4 + 3) >> 2, 4 + (3 >> 2); +select 3 >> 2 + 1, (3 >> 2) + 1, 3 >> (2 + 1); + +--echo Testing that binary - has precedence over | +select 0xFF - 0x0F | 0x55, (0xFF - 0x0F) | 0x55, 0xFF - (0x0F | 0x55); +select 0x55 | 0xFF - 0xF0, (0x55 | 0xFF) - 0xF0, 0x55 | (0xFF - 0xF0); + +--echo Testing that binary - has precedence over & +select 0xFF - 0xF0 & 0x55, (0xFF - 0xF0) & 0x55, 0xFF - (0xF0 & 0x55); +select 0x55 & 0xFF - 0xF0, (0x55 & 0xFF) - 0xF0, 0x55 & (0xFF - 0xF0); + +--echo Testing that binary - has precedence over << +select 16 - 3 << 2, (16 - 3) << 2, 16 - (3 << 2); +select 4 << 3 - 2, (4 << 3) - 2, 4 << (3 - 2); + +--echo Testing that binary - has precedence over >> +select 16 - 3 >> 2, (16 - 3) >> 2, 16 - (3 >> 2); +select 16 >> 3 - 2, (16 >> 3) - 2, 16 >> (3 - 2); + +--echo Testing that * is associative +select 2 * 3 * 4, (2 * 3) * 4, 2 * (3 * 4); + +--echo Testing that * has precedence over | +select 2 * 0x40 | 0x0F, (2 * 0x40) | 0x0F, 2 * (0x40 | 0x0F); +select 0x0F | 2 * 0x40, (0x0F | 2) * 0x40, 0x0F | (2 * 0x40); + +--echo Testing that * has precedence over & +select 2 * 0x40 & 0x55, (2 * 0x40) & 0x55, 2 * (0x40 & 0x55); +select 0xF0 & 2 * 0x40, (0xF0 & 2) * 0x40, 0xF0 & (2 * 0x40); + +--echo Testing that * has precedence over << +# Actually, can't prove it for the first case, +# since << is a multiplication by a power of 2, +# and * is associative +select 5 * 3 << 4, (5 * 3) << 4, 5 * (3 << 4); +select 2 << 3 * 4, (2 << 3) * 4, 2 << (3 * 4); + +--echo Testing that * has precedence over >> +# >> is a multiplication by a (negative) power of 2, +# see above. +select 3 * 4 >> 2, (3 * 4) >> 2, 3 * (4 >> 2); +select 4 >> 2 * 3, (4 >> 2) * 3, 4 >> (2 * 3); + +--echo Testing that * has precedence over binary + +select 2 * 3 + 4, (2 * 3) + 4, 2 * (3 + 4); +select 2 + 3 * 4, (2 + 3) * 4, 2 + (3 * 4); + +--echo Testing that * has precedence over binary - +select 4 * 3 - 2, (4 * 3) - 2, 4 * (3 - 2); +select 4 - 3 * 2, (4 - 3) * 2, 4 - (3 * 2); + +--echo Testing that / is left associative +select 15 / 5 / 3, (15 / 5) / 3, 15 / (5 / 3); + +--echo Testing that / has precedence over | +select 105 / 5 | 2, (105 / 5) | 2, 105 / (5 | 2); +select 105 | 2 / 5, (105 | 2) / 5, 105 | (2 / 5); + +--echo Testing that / has precedence over & +select 105 / 5 & 0x0F, (105 / 5) & 0x0F, 105 / (5 & 0x0F); +select 0x0F & 105 / 5, (0x0F & 105) / 5, 0x0F & (105 / 5); + +--echo Testing that / has precedence over << +select 0x80 / 4 << 2, (0x80 / 4) << 2, 0x80 / (4 << 2); +select 0x80 << 4 / 2, (0x80 << 4) / 2, 0x80 << (4 / 2); + +--echo Testing that / has precedence over >> +select 0x80 / 4 >> 2, (0x80 / 4) >> 2, 0x80 / (4 >> 2); +select 0x80 >> 4 / 2, (0x80 >> 4) / 2, 0x80 >> (4 / 2); + +--echo Testing that / has precedence over binary + +select 0x80 / 2 + 2, (0x80 / 2) + 2, 0x80 / (2 + 2); +select 0x80 + 2 / 2, (0x80 + 2) / 2, 0x80 + (2 / 2); + +--echo Testing that / has precedence over binary - +select 0x80 / 4 - 2, (0x80 / 4) - 2, 0x80 / (4 - 2); +select 0x80 - 4 / 2, (0x80 - 4) / 2, 0x80 - (4 / 2); + +# TODO: %, DIV, MOD + +--echo Testing that ^ is associative +select 0xFF ^ 0xF0 ^ 0x0F, (0xFF ^ 0xF0) ^ 0x0F, 0xFF ^ (0xF0 ^ 0x0F); +select 0xFF ^ 0xF0 ^ 0x55, (0xFF ^ 0xF0) ^ 0x55, 0xFF ^ (0xF0 ^ 0x55); + +--echo Testing that ^ has precedence over | +select 0xFF ^ 0xF0 | 0x0F, (0xFF ^ 0xF0) | 0x0F, 0xFF ^ (0xF0 | 0x0F); +select 0xF0 | 0xFF ^ 0xF0, (0xF0 | 0xFF) ^ 0xF0, 0xF0 | (0xFF ^ 0xF0); + +--echo Testing that ^ has precedence over & +select 0xFF ^ 0xF0 & 0x0F, (0xFF ^ 0xF0) & 0x0F, 0xFF ^ (0xF0 & 0x0F); +select 0x0F & 0xFF ^ 0xF0, (0x0F & 0xFF) ^ 0xF0, 0x0F & (0xFF ^ 0xF0); + +--echo Testing that ^ has precedence over << +select 0xFF ^ 0xF0 << 2, (0xFF ^ 0xF0) << 2, 0xFF ^ (0xF0 << 2); +select 0x0F << 2 ^ 0xFF, (0x0F << 2) ^ 0xFF, 0x0F << (2 ^ 0xFF); + +--echo Testing that ^ has precedence over >> +select 0xFF ^ 0xF0 >> 2, (0xFF ^ 0xF0) >> 2, 0xFF ^ (0xF0 >> 2); +select 0xFF >> 2 ^ 0xF0, (0xFF >> 2) ^ 0xF0, 0xFF >> (2 ^ 0xF0); + +--echo Testing that ^ has precedence over binary + +select 0xFF ^ 0xF0 + 0x0F, (0xFF ^ 0xF0) + 0x0F, 0xFF ^ (0xF0 + 0x0F); +select 0x0F + 0xFF ^ 0xF0, (0x0F + 0xFF) ^ 0xF0, 0x0F + (0xFF ^ 0xF0); + +--echo Testing that ^ has precedence over binary - +select 0xFF ^ 0xF0 - 1, (0xFF ^ 0xF0) - 1, 0xFF ^ (0xF0 - 1); +select 0x55 - 0x0F ^ 0x55, (0x55 - 0x0F) ^ 0x55, 0x55 - (0x0F ^ 0x55); + +--echo Testing that ^ has precedence over * +select 0xFF ^ 0xF0 * 2, (0xFF ^ 0xF0) * 2, 0xFF ^ (0xF0 * 2); +select 2 * 0xFF ^ 0xF0, (2 * 0xFF) ^ 0xF0, 2 * (0xFF ^ 0xF0); + +--echo Testing that ^ has precedence over / +select 0xFF ^ 0xF0 / 2, (0xFF ^ 0xF0) / 2, 0xFF ^ (0xF0 / 2); +select 0xF2 / 2 ^ 0xF0, (0xF2 / 2) ^ 0xF0, 0xF2 / (2 ^ 0xF0); + +--echo Testing that ^ has precedence over % +select 0xFF ^ 0xF0 % 0x20, (0xFF ^ 0xF0) % 0x20, 0xFF ^ (0xF0 % 0x20); +select 0xFF % 0x20 ^ 0xF0, (0xFF % 0x20) ^ 0xF0, 0xFF % (0x20 ^ 0xF0); + +--echo Testing that ^ has precedence over DIV +select 0xFF ^ 0xF0 DIV 2, (0xFF ^ 0xF0) DIV 2, 0xFF ^ (0xF0 DIV 2); +select 0xF2 DIV 2 ^ 0xF0, (0xF2 DIV 2) ^ 0xF0, 0xF2 DIV (2 ^ 0xF0); + +--echo Testing that ^ has precedence over MOD +select 0xFF ^ 0xF0 MOD 0x20, (0xFF ^ 0xF0) MOD 0x20, 0xFF ^ (0xF0 MOD 0x20); +select 0xFF MOD 0x20 ^ 0xF0, (0xFF MOD 0x20) ^ 0xF0, 0xFF MOD (0x20 ^ 0xF0); + diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index ef9bed8b789..012f2b33225 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1387,6 +1387,21 @@ CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create user 'mysqltest CREATE FUNCTION bug_13627_f() returns int BEGIN create user 'mysqltest_1'; return 1; END | -- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER bug21975 BEFORE INSERT ON t1 FOR EACH ROW BEGIN grant select on t1 to 'mysqltest_1'; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug21975() returns int BEGIN grant select on t1 to 'mysqltest_1'; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER bug21975 BEFORE INSERT ON t1 FOR EACH ROW BEGIN revoke select on t1 from 'mysqltest_1'; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug21975() returns int BEGIN revoke select on t1 from 'mysqltest_1'; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER bug21975 BEFORE INSERT ON t1 FOR EACH ROW BEGIN revoke all privileges on *.* from 'mysqltest_1'; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug21975() returns int BEGIN revoke all privileges on *.* from 'mysqltest_1'; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop user 'mysqltest_1'; END | -- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG CREATE FUNCTION bug_13627_f() returns int BEGIN drop user 'mysqltest_1'; return 1; END | diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 46ef6bc6ddd..1c8f1ca51c2 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -7494,4 +7494,123 @@ DROP FUNCTION f1; DROP FUNCTION f2; DROP TABLE t1; +# +# Bug#29936 Stored Procedure DML ignores low_priority_updates setting +# + +--disable_warnings +drop table if exists t1; +drop procedure if exists p1; +--enable_warnings + +create table t1 (value varchar(15)); +create procedure p1() update t1 set value='updated' where value='old'; + +# load the procedure into sp cache and execute once +call p1(); + +insert into t1 (value) values ("old"); + +connect (rl_holder, localhost, root,,); +connect (rl_acquirer, localhost, root,,); +connect (rl_contender, localhost, root,,); +connect (rl_wait, localhost, root,,); + +connection rl_holder; +select get_lock('b26162',120); + +connection rl_acquirer; +--send select 'rl_acquirer', value from t1 where get_lock('b26162',120); + +# we must wait till this select opens and locks the tables +connection rl_wait; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "User lock" and + info = "select 'rl_acquirer', value from t1 where get_lock('b26162',120)"; +--source include/wait_condition.inc + +connection default; +set session low_priority_updates=on; +--send call p1(); + +connection rl_wait; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Locked" and + info = "update t1 set value='updated' where value='old'"; +--source include/wait_condition.inc + +connection rl_contender; +select 'rl_contender', value from t1; + +connection rl_holder; +select release_lock('b26162'); + +connection rl_acquirer; +--reap +connection default; +--reap + +disconnect rl_holder; +disconnect rl_acquirer; +disconnect rl_wait; +drop procedure p1; +drop table t1; +set session low_priority_updates=default; + +# +# Bug#13675: DATETIME/DATE type in store proc param seems to be converted as +# varbinary +# + +--echo +--echo # Bug#13675. +--echo + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; + +DROP TABLE IF EXISTS t1; +--enable_warnings + +--echo + +CREATE PROCEDURE p1(v DATETIME) CREATE TABLE t1 SELECT v; + +CREATE PROCEDURE p2(v INT) CREATE TABLE t1 SELECT v; + +--echo +CALL p1(NOW()); +SHOW CREATE TABLE t1; + +--echo +DROP TABLE t1; + +--echo +CALL p1('text'); +SHOW CREATE TABLE t1; + +--echo +DROP TABLE t1; + +--echo +CALL p2(10); +SHOW CREATE TABLE t1; + +--echo +DROP TABLE t1; + +--echo +CALL p2('text'); +SHOW CREATE TABLE t1; + +--echo +DROP TABLE t1; + +--echo +DROP PROCEDURE p1; +DROP PROCEDURE p2; + --echo End of 5.0 tests diff --git a/sql/ha_ndbcluster_binlog.h b/sql/ha_ndbcluster_binlog.h index b5b8d0d9745..53852028f08 100644 --- a/sql/ha_ndbcluster_binlog.h +++ b/sql/ha_ndbcluster_binlog.h @@ -216,10 +216,12 @@ inline void free_share(NDB_SHARE **share, bool have_lock= FALSE) inline Thd_ndb * -get_thd_ndb(THD *thd) { return (Thd_ndb *) thd->ha_data[ndbcluster_hton->slot]; } +get_thd_ndb(THD *thd) +{ return (Thd_ndb *) thd_get_ha_data(thd, ndbcluster_hton); } inline void -set_thd_ndb(THD *thd, Thd_ndb *thd_ndb) { thd->ha_data[ndbcluster_hton->slot]= thd_ndb; } +set_thd_ndb(THD *thd, Thd_ndb *thd_ndb) +{ thd_set_ha_data(thd, ndbcluster_hton, thd_ndb); } Ndb* check_ndb_in_thd(THD* thd); diff --git a/sql/handler.cc b/sql/handler.cc index 2cb3c5aa348..75c3a64bc27 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -561,7 +561,7 @@ static my_bool closecon_handlerton(THD *thd, plugin_ref plugin, be rolled back already */ if (hton->state == SHOW_OPTION_YES && hton->close_connection && - thd->ha_data[hton->slot]) + thd_get_ha_data(thd, hton)) hton->close_connection(hton, thd); return FALSE; } @@ -1509,7 +1509,7 @@ void handler::ha_statistic_increment(ulong SSV::*offset) const void **handler::ha_data(THD *thd) const { - return (void **) thd->ha_data + ht->slot; + return thd_ha_data(thd, ht); } THD *handler::ha_thd(void) const diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 4015e5618e8..40d0c2dfe91 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1424,6 +1424,7 @@ public: Item_cond(List<Item> &nlist) :Item_bool_func(), list(nlist), abort_on_null(0) {} bool add(Item *item) { return list.push_back(item); } + bool add_at_head(Item *item) { return list.push_front(item); } void add_at_head(List<Item> *nlist) { list.prepand(nlist); } bool fix_fields(THD *, Item **ref); @@ -1616,6 +1617,15 @@ public: Item *neg_transformer(THD *thd); }; +inline bool is_cond_and(Item *item) +{ + if (item->type() != Item::COND_ITEM) + return FALSE; + + Item_cond *cond_item= (Item_cond*) item; + return (cond_item->functype() == Item_func::COND_AND_FUNC); +} + class Item_cond_or :public Item_cond { public: @@ -1637,6 +1647,14 @@ public: Item *neg_transformer(THD *thd); }; +inline bool is_cond_or(Item *item) +{ + if (item->type() != Item::COND_ITEM) + return FALSE; + + Item_cond *cond_item= (Item_cond*) item; + return (cond_item->functype() == Item_func::COND_OR_FUNC); +} /* XOR is Item_cond, not an Item_int_func because we could like to diff --git a/sql/lock.cc b/sql/lock.cc index d9e9dd31f81..29a07858bc1 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -276,6 +276,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, thd->lock_id)]; if (rc > 1) /* a timeout or a deadlock */ { + if (sql_lock->table_count) + VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count)); my_error(rc, MYF(0)); my_free((uchar*) sql_lock,MYF(0)); sql_lock= 0; diff --git a/sql/log.cc b/sql/log.cc index 74a210a35b3..95204e89d0e 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -656,8 +656,14 @@ int Log_to_csv_event_handler:: table= open_performance_schema_table(thd, & table_list, & open_tables_backup); - result= (table ? 0 : 1); - close_performance_schema_table(thd, & open_tables_backup); + if (table) + { + result= 0; + close_performance_schema_table(thd, & open_tables_backup); + } + else + result= 1; + DBUG_RETURN(result); } @@ -1215,10 +1221,10 @@ binlog_trans_log_savepos(THD *thd, my_off_t *pos) { DBUG_ENTER("binlog_trans_log_savepos"); DBUG_ASSERT(pos != NULL); - if (thd->ha_data[binlog_hton->slot] == NULL) + if (thd_get_ha_data(thd, binlog_hton) == NULL) thd->binlog_setup_trx_data(); binlog_trx_data *const trx_data= - (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; + (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); DBUG_ASSERT(mysql_bin_log.is_open()); *pos= trx_data->position(); DBUG_PRINT("return", ("*pos: %lu", (ulong) *pos)); @@ -1247,12 +1253,12 @@ binlog_trans_log_truncate(THD *thd, my_off_t pos) DBUG_ENTER("binlog_trans_log_truncate"); DBUG_PRINT("enter", ("pos: %lu", (ulong) pos)); - DBUG_ASSERT(thd->ha_data[binlog_hton->slot] != NULL); + DBUG_ASSERT(thd_get_ha_data(thd, binlog_hton) != NULL); /* Only true if binlog_trans_log_savepos() wasn't called before */ DBUG_ASSERT(pos != ~(my_off_t) 0); binlog_trx_data *const trx_data= - (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; + (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); trx_data->truncate(pos); DBUG_VOID_RETURN; } @@ -1283,9 +1289,9 @@ int binlog_init(void *p) static int binlog_close_connection(handlerton *hton, THD *thd) { binlog_trx_data *const trx_data= - (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; + (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); DBUG_ASSERT(trx_data->empty()); - thd->ha_data[binlog_hton->slot]= 0; + thd_set_ha_data(thd, binlog_hton, NULL); trx_data->~binlog_trx_data(); my_free((uchar*)trx_data, MYF(0)); return 0; @@ -1408,7 +1414,7 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) { DBUG_ENTER("binlog_commit"); binlog_trx_data *const trx_data= - (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; + (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); if (trx_data->empty()) { @@ -1435,7 +1441,7 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) DBUG_ENTER("binlog_rollback"); int error=0; binlog_trx_data *const trx_data= - (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; + (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); if (trx_data->empty()) { trx_data->reset(); @@ -3251,23 +3257,22 @@ int THD::binlog_setup_trx_data() { DBUG_ENTER("THD::binlog_setup_trx_data"); binlog_trx_data *trx_data= - (binlog_trx_data*) ha_data[binlog_hton->slot]; + (binlog_trx_data*) thd_get_ha_data(this, binlog_hton); if (trx_data) DBUG_RETURN(0); // Already set up - ha_data[binlog_hton->slot]= trx_data= - (binlog_trx_data*) my_malloc(sizeof(binlog_trx_data), MYF(MY_ZEROFILL)); + trx_data= (binlog_trx_data*) my_malloc(sizeof(binlog_trx_data), MYF(MY_ZEROFILL)); if (!trx_data || open_cached_file(&trx_data->trans_log, mysql_tmpdir, LOG_PREFIX, binlog_cache_size, MYF(MY_WME))) { my_free((uchar*)trx_data, MYF(MY_ALLOW_ZERO_PTR)); - ha_data[binlog_hton->slot]= 0; DBUG_RETURN(1); // Didn't manage to set it up } + thd_set_ha_data(this, binlog_hton, trx_data); - trx_data= new (ha_data[binlog_hton->slot]) binlog_trx_data; + trx_data= new (thd_get_ha_data(this, binlog_hton)) binlog_trx_data; DBUG_RETURN(0); } @@ -3303,7 +3308,7 @@ int THD::binlog_setup_trx_data() void THD::binlog_start_trans_and_stmt() { - binlog_trx_data *trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; + binlog_trx_data *trx_data= (binlog_trx_data*) thd_get_ha_data(this, binlog_hton); DBUG_ENTER("binlog_start_trans_and_stmt"); DBUG_PRINT("enter", ("trx_data: 0x%lx trx_data->before_stmt_pos: %lu", (long) trx_data, @@ -3323,7 +3328,7 @@ THD::binlog_start_trans_and_stmt() void THD::binlog_set_stmt_begin() { binlog_trx_data *trx_data= - (binlog_trx_data*) ha_data[binlog_hton->slot]; + (binlog_trx_data*) thd_get_ha_data(this, binlog_hton); /* The call to binlog_trans_log_savepos() might create the trx_data @@ -3333,14 +3338,15 @@ void THD::binlog_set_stmt_begin() { */ my_off_t pos= 0; binlog_trans_log_savepos(this, &pos); - trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; + trx_data= (binlog_trx_data*) thd_get_ha_data(this, binlog_hton); trx_data->before_stmt_pos= pos; } int THD::binlog_flush_transaction_cache() { DBUG_ENTER("binlog_flush_transaction_cache"); - binlog_trx_data *trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; + binlog_trx_data *trx_data= (binlog_trx_data*) + thd_get_ha_data(this, binlog_hton); DBUG_PRINT("enter", ("trx_data=0x%lu", (ulong) trx_data)); if (trx_data) DBUG_PRINT("enter", ("trx_data->before_stmt_pos=%lu", @@ -3403,7 +3409,7 @@ Rows_log_event* THD::binlog_get_pending_rows_event() const { binlog_trx_data *const trx_data= - (binlog_trx_data*) ha_data[binlog_hton->slot]; + (binlog_trx_data*) thd_get_ha_data(this, binlog_hton); /* This is less than ideal, but here's the story: If there is no trx_data, prepare_pending_rows_event() has never been called @@ -3416,11 +3422,11 @@ THD::binlog_get_pending_rows_event() const void THD::binlog_set_pending_rows_event(Rows_log_event* ev) { - if (ha_data[binlog_hton->slot] == NULL) + if (thd_get_ha_data(this, binlog_hton) == NULL) binlog_setup_trx_data(); binlog_trx_data *const trx_data= - (binlog_trx_data*) ha_data[binlog_hton->slot]; + (binlog_trx_data*) thd_get_ha_data(this, binlog_hton); DBUG_ASSERT(trx_data); trx_data->set_pending(ev); @@ -3443,7 +3449,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, int error= 0; binlog_trx_data *const trx_data= - (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; + (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); DBUG_ASSERT(trx_data); @@ -3594,7 +3600,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) goto err; binlog_trx_data *const trx_data= - (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; + (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); IO_CACHE *trans_log= &trx_data->trans_log; my_off_t trans_log_pos= my_b_tell(trans_log); if (event_info->get_cache_stmt() || trans_log_pos != 0) @@ -5031,7 +5037,7 @@ int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid) DBUG_ENTER("TC_LOG_BINLOG::log"); Xid_log_event xle(thd, xid); binlog_trx_data *trx_data= - (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; + (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); /* We always commit the entire transaction when writing an XID. Also note that the return value is inverted. diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 375782787a3..47a42354423 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -937,9 +937,16 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent); bool do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name, char *new_table_alias, bool skip_error); + bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch); +bool mysql_opt_change_db(THD *thd, + const LEX_STRING *new_db_name, + LEX_STRING *saved_db_name, + bool force_switch, + bool *cur_db_changed); + void mysql_parse(THD *thd, const char *inBuf, uint length, const char ** semicolon); diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 4fd38022da0..26edbdd1405 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -241,8 +241,8 @@ public: private: ulong m_size; // Number of elements in the types array field_type *m_type; // Array of type descriptors - uint16 *m_field_metadata; uint m_field_metadata_size; + uint16 *m_field_metadata; uchar *m_null_bits; uchar *m_memory; }; diff --git a/sql/sp.cc b/sql/sp.cc index 437ffb3b484..6032688f7f1 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -520,9 +520,10 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, { LEX *old_lex= thd->lex, newlex; String defstr; - char old_db_buf[NAME_LEN+1]; - LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; - bool dbchanged; + char saved_cur_db_name_buf[NAME_LEN+1]; + LEX_STRING saved_cur_db_name= + { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) }; + bool cur_db_changed; ulong old_sql_mode= thd->variables.sql_mode; ha_rows old_select_limit= thd->variables.select_limit; sp_rcontext *old_spcont= thd->spcont; @@ -567,16 +568,17 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, } /* - Change current database if needed. + Change the current database (if needed). - collation_database will be updated here. However, it can be wrong, - because it will contain the current value of the database collation. - We need collation_database to be fixed at the creation time -- so - we'll update it later in switch_query_ctx(). + TODO: why do we force switch here? */ - if ((ret= sp_use_new_db(thd, name->m_db, &old_db, 1, &dbchanged))) + if (mysql_opt_change_db(thd, &name->m_db, &saved_cur_db_name, TRUE, + &cur_db_changed)) + { + ret= SP_INTERNAL_ERROR; goto end; + } thd->spcont= NULL; @@ -585,34 +587,42 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, lex_start(thd); - if (parse_sql(thd, &lip, creation_ctx) || newlex.sphead == NULL) - { - sp_head *sp= newlex.sphead; + ret= parse_sql(thd, &lip, creation_ctx) || newlex.sphead == NULL; - if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE))) - goto end; - delete sp; - ret= SP_PARSE_ERROR; + /* + Force switching back to the saved current database (if changed), + because it may be NULL. In this case, mysql_change_db() would + generate an error. + */ + + if (cur_db_changed && mysql_change_db(thd, &saved_cur_db_name, TRUE)) + { + delete newlex.sphead; + ret= SP_INTERNAL_ERROR; + goto end; } - else + + if (ret) { - if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE))) - goto end; - *sphp= newlex.sphead; - (*sphp)->set_definer(&definer_user_name, &definer_host_name); - (*sphp)->set_info(created, modified, &chistics, sql_mode); - (*sphp)->set_creation_ctx(creation_ctx); - (*sphp)->optimize(); - /* - Not strictly necessary to invoke this method here, since we know - that we've parsed CREATE PROCEDURE/FUNCTION and not an - UPDATE/DELETE/INSERT/REPLACE/LOAD/CREATE TABLE, but we try to - maintain the invariant that this method is called for each - distinct statement, in case its logic is extended with other - types of analyses in future. - */ - newlex.set_trg_event_type_for_tables(); + delete newlex.sphead; + ret= SP_PARSE_ERROR; + goto end; } + + *sphp= newlex.sphead; + (*sphp)->set_definer(&definer_user_name, &definer_host_name); + (*sphp)->set_info(created, modified, &chistics, sql_mode); + (*sphp)->set_creation_ctx(creation_ctx); + (*sphp)->optimize(); + /* + Not strictly necessary to invoke this method here, since we know + that we've parsed CREATE PROCEDURE/FUNCTION and not an + UPDATE/DELETE/INSERT/REPLACE/LOAD/CREATE TABLE, but we try to + maintain the invariant that this method is called for each + distinct statement, in case its logic is extended with other + types of analyses in future. + */ + newlex.set_trg_event_type_for_tables(); } end: @@ -2025,69 +2035,3 @@ create_string(THD *thd, String *buf, buf->append(body, bodylen); return TRUE; } - - - -/* - Change the current database if needed. - - SYNOPSIS - sp_use_new_db() - thd thread handle - new_db new database name (a string and its length) - old_db [IN] str points to a buffer where to store the old - database, length contains the size of the buffer - [OUT] if old db was not NULL, its name is copied - to the buffer pointed at by str and length is updated - accordingly. Otherwise str[0] is set to '\0' and length - is set to 0. The out parameter should be used only if - the database name has been changed (see dbchangedp). - dbchangedp [OUT] is set to TRUE if the current database is changed, - FALSE otherwise. A database is not changed if the old - name is the same as the new one, both names are empty, - or an error has occurred. - - RETURN VALUE - 0 success - 1 access denied or out of memory (the error message is - set in THD) -*/ - -int -sp_use_new_db(THD *thd, LEX_STRING new_db, LEX_STRING *old_db, - bool no_access_check, bool *dbchangedp) -{ - int ret; - DBUG_ENTER("sp_use_new_db"); - DBUG_PRINT("enter", ("newdb: %s", new_db.str)); - - /* - A stored routine always belongs to some database. The - old database (old_db) might be NULL, but to restore the - old database we will use mysql_change_db. - */ - DBUG_ASSERT(new_db.str && new_db.length); - - if (thd->db) - { - old_db->length= (strmake(old_db->str, thd->db, old_db->length) - - old_db->str); - } - else - { - old_db->str[0]= '\0'; - old_db->length= 0; - } - - /* Don't change the database if the new name is the same as the old one. */ - if (my_strcasecmp(system_charset_info, old_db->str, new_db.str) == 0) - { - *dbchangedp= FALSE; - DBUG_RETURN(0); - } - - ret= mysql_change_db(thd, &new_db, no_access_check); - - *dbchangedp= ret == 0; - DBUG_RETURN(ret); -} @@ -85,15 +85,4 @@ extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen, */ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup); - -/* - Do a "use new_db". The current db is stored at old_db. If new_db is the - same as the current one, nothing is changed. dbchangedp is set to true if - the db was actually changed. -*/ - -int -sp_use_new_db(THD *thd, LEX_STRING new_db, LEX_STRING *old_db, - bool no_access_check, bool *dbchangedp); - #endif /* _SP_H_ */ diff --git a/sql/sp_head.cc b/sql/sp_head.cc index b8535ee9958..828517011d5 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -249,11 +249,14 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_CREATE_TRIGGER: case SQLCOM_CREATE_USER: case SQLCOM_ALTER_TABLE: + case SQLCOM_GRANT: + case SQLCOM_REVOKE: case SQLCOM_BEGIN: case SQLCOM_RENAME_TABLE: case SQLCOM_RENAME_USER: case SQLCOM_DROP_INDEX: case SQLCOM_DROP_DB: + case SQLCOM_REVOKE_ALL: case SQLCOM_DROP_USER: case SQLCOM_DROP_VIEW: case SQLCOM_DROP_TRIGGER: @@ -1013,9 +1016,10 @@ bool sp_head::execute(THD *thd) { DBUG_ENTER("sp_head::execute"); - char old_db_buf[NAME_LEN+1]; - LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; - bool dbchanged; + char saved_cur_db_name_buf[NAME_LEN+1]; + LEX_STRING saved_cur_db_name= + { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) }; + bool cur_db_changed= FALSE; sp_rcontext *ctx; bool err_status= FALSE; uint ip= 0; @@ -1070,8 +1074,11 @@ sp_head::execute(THD *thd) */ if (m_db.length && - (err_status= sp_use_new_db(thd, m_db, &old_db, 0, &dbchanged))) + (err_status= mysql_opt_change_db(thd, &m_db, &saved_cur_db_name, FALSE, + &cur_db_changed))) + { goto done; + } if ((ctx= thd->spcont)) ctx->clear_handler(); @@ -1252,14 +1259,14 @@ sp_head::execute(THD *thd) If the DB has changed, the pointer has changed too, but the original thd->db will then have been freed */ - if (dbchanged) + if (cur_db_changed && !thd->killed) { /* - No access check when changing back to where we came from. - (It would generate an error from mysql_change_db() when old_db=="") + Force switching back to the saved current database, because it may be + NULL. In this case, mysql_change_db() would generate an error. */ - if (! thd->killed) - err_status|= mysql_change_db(thd, &old_db, TRUE); + + err_status|= mysql_change_db(thd, &saved_cur_db_name, TRUE); } m_flags&= ~IS_INVOKED; DBUG_PRINT("info", diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 309d3061a2f..337fde53dac 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7747,6 +7747,9 @@ open_performance_schema_table(THD *thd, TABLE_LIST *one_table, */ table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; } + else + thd->restore_backup_open_tables_state(backup); + thd->utime_after_lock= save_utime_after_lock; DBUG_RETURN(table); } @@ -7762,24 +7765,25 @@ void close_performance_schema_table(THD *thd, Open_tables_state *backup) { bool found_old_table; - if (thd->lock) - { - /* - Note: - We do not create explicitly a separate transaction for the - performance table I/O, but borrow the current transaction. - lock + unlock will autocommit the change done in the - performance schema table: this is the expected result. - The current transaction should not be affected by this code. - TODO: Note that if a transactional engine is used for log tables, - this code will need to be revised, as a separate transaction - might be needed. - */ - mysql_unlock_tables(thd, thd->lock); - thd->lock= 0; - } + /* + If open_performance_schema_table() fails, + this function should not be called. + */ + DBUG_ASSERT(thd->lock != NULL); - safe_mutex_assert_not_owner(&LOCK_open); + /* + Note: + We do not create explicitly a separate transaction for the + performance table I/O, but borrow the current transaction. + lock + unlock will autocommit the change done in the + performance schema table: this is the expected result. + The current transaction should not be affected by this code. + TODO: Note that if a transactional engine is used for log tables, + this code will need to be revised, as a separate transaction + might be needed. + */ + mysql_unlock_tables(thd, thd->lock); + thd->lock= 0; pthread_mutex_lock(&LOCK_open); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 55789a3a233..66a51d5bb00 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -387,7 +387,6 @@ THD::THD() init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); stmt_arena= this; thread_stack= 0; - db= 0; catalog= (char*)"std"; // the only catalog we have for now main_security_ctx.init(); security_ctx= &main_security_ctx; @@ -395,7 +394,7 @@ THD::THD() query_start_used= 0; count_cuted_fields= CHECK_FIELD_IGNORE; killed= NOT_KILLED; - db_length= col_access=0; + col_access=0; query_error= thread_specific_used= FALSE; hash_clear(&handler_tables_hash); tmp_table=0; @@ -2040,7 +2039,9 @@ Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg, lex(lex_arg), query(0), query_length(0), - cursor(0) + cursor(0), + db(NULL), + db_length(0) { name.str= NULL; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 7117c08a7e1..7875870bd1a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -593,6 +593,22 @@ public: uint32 query_length; // current query length Server_side_cursor *cursor; + /** + Name of the current (default) database. + + If there is the current (default) database, "db" contains its name. If + there is no current (default) database, "db" is NULL and "db_length" is + 0. In other words, "db", "db_length" must either be NULL, or contain a + valid database name. + + @note this attribute is set and alloced by the slave SQL thread (for + the THD of that thread); that thread is (and must remain, for now) the + only responsible for freeing this member. + */ + + char *db; + uint db_length; + public: /* This constructor is called for backup statements */ @@ -1024,18 +1040,21 @@ public: */ char *thread_stack; + /** + Currently selected catalog. + */ + char *catalog; + /* - db - currently selected database - catalog - currently selected catalog - WARNING: some members of THD (currently 'db', 'catalog' and 'query') are - set and alloced by the slave SQL thread (for the THD of that thread); that - thread is (and must remain, for now) the only responsible for freeing these - 3 members. If you add members here, and you add code to set them in - replication, don't forget to free_them_and_set_them_to_0 in replication - properly. For details see the 'err:' label of the handle_slave_sql() - in sql/slave.cc. - */ - char *db, *catalog; + WARNING: some members of THD (currently 'Statement::db', + 'catalog' and 'query') are set and alloced by the slave SQL thread + (for the THD of that thread); that thread is (and must remain, for now) + the only responsible for freeing these 3 members. If you add members + here, and you add code to set them in replication, don't forget to + free_them_and_set_them_to_0 in replication properly. For details see + the 'err:' label of the handle_slave_sql() in sql/slave.cc. + */ + Security_context main_security_ctx; Security_context *security_ctx; @@ -1390,7 +1409,6 @@ public: uint tmp_table, global_read_lock; uint server_status,open_options; enum enum_thread_type system_thread; - uint db_length; uint select_number; //number of select (used for EXPLAIN) /* variables.transaction_isolation is reset to this after each commit */ enum_tx_isolation session_tx_isolation; @@ -1802,11 +1820,26 @@ public: } } - /* - Initialize the current database from a NULL-terminated string with length - If we run out of memory, we free the current database and return TRUE. - This way the user will notice the error as there will be no current - database selected (in addition to the error message set by malloc). + /** + Set the current database; use deep copy of C-string. + + @param new_db a pointer to the new database name. + @param new_db_len length of the new database name. + + Initialize the current database from a NULL-terminated string with + length. If we run out of memory, we free the current database and + return TRUE. This way the user will notice the error as there will be + no current database selected (in addition to the error message set by + malloc). + + @note This operation just sets {db, db_length}. Switching the current + database usually involves other actions, like switching other database + attributes including security context. In the future, this operation + will be made private and more convenient interface will be provided. + + @return Operation status + @retval FALSE Success + @retval TRUE Out-of-memory error */ bool set_db(const char *new_db, size_t new_db_len) { @@ -1821,6 +1854,18 @@ public: db_length= db ? new_db_len : 0; return new_db && !db; } + + /** + Set the current database; use shallow copy of C-string. + + @param new_db a pointer to the new database name. + @param new_db_len length of the new database name. + + @note This operation just sets {db, db_length}. Switching the current + database usually involves other actions, like switching other database + attributes including security context. In the future, this operation + will be made private and more convenient interface will be provided. + */ void reset_db(char *new_db, size_t new_db_len) { db= new_db; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 15506fcbc80..cd7ad048802 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -39,6 +39,10 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, static long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path); static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error); +static void mysql_change_db_impl(THD *thd, + LEX_STRING *new_db_name, + ulong new_db_access, + CHARSET_INFO *new_db_charset); /* Database lock hash */ @@ -997,7 +1001,7 @@ exit: it to 0. */ if (thd->db && !strcmp(thd->db, db)) - thd->set_db(NULL, 0); + mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); VOID(pthread_mutex_unlock(&LOCK_mysql_create_db)); start_waiting_global_read_lock(thd); exit2: @@ -1355,22 +1359,108 @@ static void mysql_change_db_impl(THD *thd, } + /** - @brief Change the current database. + Backup the current database name before switch. + + @param[in] thd thread handle + @param[in, out] saved_db_name IN: "str" points to a buffer where to store + the old database name, "length" contains the + buffer size + OUT: if the current (default) database is + not NULL, its name is copied to the + buffer pointed at by "str" + and "length" is updated accordingly. + Otherwise "str" is set to NULL and + "length" is set to 0. +*/ + +static void backup_current_db_name(THD *thd, + LEX_STRING *saved_db_name) +{ + if (!thd->db) + { + /* No current (default) database selected. */ + + saved_db_name->str= NULL; + saved_db_name->length= 0; + } + else + { + strmake(saved_db_name->str, thd->db, saved_db_name->length); + saved_db_name->length= thd->db_length; + } +} + + +/** + Return TRUE if db1_name is equal to db2_name, FALSE otherwise. + + The function allows to compare database names according to the MySQL + rules. The database names db1 and db2 are equal if: + - db1 is NULL and db2 is NULL; + or + - db1 is not-NULL, db2 is not-NULL, db1 is equal (ignoring case) to + db2 in system character set (UTF8). +*/ + +static inline bool +cmp_db_names(const char *db1_name, + const char *db2_name) +{ + return + /* db1 is NULL and db2 is NULL */ + !db1_name && !db2_name || + + /* db1 is not-NULL, db2 is not-NULL, db1 == db2. */ + db1_name && db2_name && + my_strcasecmp(system_charset_info, db1_name, db2_name) == 0; +} + + +/** + @brief Change the current database and its attributes unconditionally. @param thd thread handle @param new_db_name database name - @param force_switch if this flag is set (TRUE), mysql_change_db() will - switch to NULL db if the specified database is not - available anymore. Corresponding warning will be - thrown in this case. This flag is used to change - database in stored-routine-execution code. - - @details Check that the database name corresponds to a valid and existent - database, check access rights (unless called with no_access_check), and - set the current database. This function is called to change the current - database upon user request (COM_CHANGE_DB command) or temporarily, to - execute a stored routine. + @param force_switch if force_switch is FALSE, then the operation will fail if + + - new_db_name is NULL or empty; + + - OR new database name is invalid + (check_db_name() failed); + + - OR user has no privilege on the new database; + + - OR new database does not exist; + + if force_switch is TRUE, then + + - if new_db_name is NULL or empty, the current + database will be NULL, @@collation_database will + be set to @@collation_server, the operation will + succeed. + + - if new database name is invalid + (check_db_name() failed), the current database + will be NULL, @@collation_database will be set to + @@collation_server, but the operation will fail; + + - user privileges will not be checked + (THD::db_access however is updated); + + TODO: is this really the intention? + (see sp-security.test). + + - if new database does not exist,the current database + will be NULL, @@collation_database will be set to + @@collation_server, a warning will be thrown, the + operation will succeed. + + @details The function checks that the database name corresponds to a + valid and existent database, checks access rights and changes the current + database with database attributes (@@collation_database session variable, + THD::db_access). This function is not the only way to switch the database that is currently employed. When the replication slave thread switches the @@ -1407,8 +1497,13 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) if (force_switch) { /* - This can only happen when we restore the old db in THD after - execution of a routine is complete. Change db to NULL. + This can happen only if we're switching the current database back + after loading stored program. The thing is that loading of stored + program can happen when there is no current database. + + TODO: actually, new_db_name and new_db_name->str seem to be always + non-NULL. In case of stored program, new_db_name->str == "" and + new_db_name->length == 0. */ mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); @@ -1426,7 +1521,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) if (my_strcasecmp(system_charset_info, new_db_name->str, INFORMATION_SCHEMA_NAME.str) == 0) { - /* Switch database to INFORMATION_SCHEMA. */ + /* Switch the current database to INFORMATION_SCHEMA. */ mysql_change_db_impl(thd, &INFORMATION_SCHEMA_NAME, SELECT_ACL, system_charset_info); @@ -1453,8 +1548,8 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) even if we are called from sp_head::execute(). It's next to impossible however to get this error when we are called - from sp_head::execute(). But let's switch database to NULL in this case - to be sure. + from sp_head::execute(). But let's switch the current database to NULL + in this case to be sure. */ if (check_db_name(&new_db_file_name)) @@ -1463,10 +1558,8 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) my_free(new_db_file_name.str, MYF(0)); if (force_switch) - { - /* Change db to NULL. */ mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); - } + DBUG_RETURN(TRUE); } @@ -1501,6 +1594,8 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) { if (force_switch) { + /* Throw a warning and free new_db_file_name. */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR), new_db_file_name.str); @@ -1511,12 +1606,19 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); + /* The operation succeed. */ + DBUG_RETURN(FALSE); } else { + /* Report an error and free new_db_file_name. */ + my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str); my_free(new_db_file_name.str, MYF(0)); + + /* The operation failed. */ + DBUG_RETURN(TRUE); } } @@ -1534,6 +1636,43 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) } +/** + Change the current database and its attributes if needed. + + @param thd thread handle + @param new_db_name database name + @param[in, out] saved_db_name IN: "str" points to a buffer where to store + the old database name, "length" contains the + buffer size + OUT: if the current (default) database is + not NULL, its name is copied to the + buffer pointed at by "str" + and "length" is updated accordingly. + Otherwise "str" is set to NULL and + "length" is set to 0. + @param force_switch @see mysql_change_db() + @param[out] cur_db_changed out-flag to indicate whether the current + database has been changed (valid only if + the function suceeded) +*/ + +bool mysql_opt_change_db(THD *thd, + const LEX_STRING *new_db_name, + LEX_STRING *saved_db_name, + bool force_switch, + bool *cur_db_changed) +{ + *cur_db_changed= !cmp_db_names(thd->db, new_db_name->str); + + if (!*cur_db_changed) + return FALSE; + + backup_current_db_name(thd, saved_db_name); + + return mysql_change_db(thd, new_db_name, force_switch); +} + + static int lock_databases(THD *thd, const char *db1, uint length1, const char *db2, uint length2) @@ -1829,7 +1968,7 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db) /* Step9: Let's do "use newdb" if we renamed the current database */ if (change_to_newdb) - error|= mysql_change_db(thd, new_db, 0); + error|= mysql_change_db(thd, new_db, FALSE); exit: pthread_mutex_lock(&LOCK_lock_db); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 8b9896870c0..1adce48c539 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -444,7 +444,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, cond->cleanup(); // File was reopened if ((!cond->fixed && cond->fix_fields(thd, &cond)) || cond->check_cols(1)) - goto err0; + goto err; } if (keyname) @@ -452,13 +452,13 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, if ((keyno=find_type(keyname, &table->s->keynames, 1+2)-1)<0) { my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), keyname, tables->alias); - goto err0; + goto err; } } if (insert_fields(thd, &thd->lex->select_lex.context, tables->db, tables->alias, &it, 0)) - goto err0; + goto err; protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 157309a3366..ebbf4cafb19 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -397,7 +397,7 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type, if (duplic == DUP_UPDATE || duplic == DUP_REPLACE && *lock_type == TL_WRITE_CONCURRENT_INSERT) { - *lock_type= TL_WRITE; + *lock_type= TL_WRITE_DEFAULT; return; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 66f5540d286..6b94505e46e 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -323,7 +323,6 @@ void lex_start(THD *thd) lex->length=0; lex->part_info= 0; lex->select_lex.in_sum_expr=0; - lex->select_lex.expr_list.empty(); lex->select_lex.ftfunc_list_alloc.empty(); lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc; lex->select_lex.group_list.empty(); @@ -720,6 +719,7 @@ static inline uint int_token(const char *str,uint length) int MYSQLlex(void *arg, void *yythd) { reg1 uchar c; + bool comment_closed; int tokval, result_state; uint length; enum my_lex_states state; @@ -1212,7 +1212,10 @@ int MYSQLlex(void *arg, void *yythd) /* The special comment format is very strict: '/' '*' '!', followed by exactly - 2 digits (major), then 3 digits (minor). + 1 digit (major), 2 digits (minor), then 2 digits (dot). + 32302 -> 3.23.02 + 50032 -> 5.0.32 + 50114 -> 5.1.14 */ char version_str[6]; version_str[0]= lip->yyPeekn(0); @@ -1231,7 +1234,7 @@ int MYSQLlex(void *arg, void *yythd) ulong version; version=strtol(version_str, NULL, 10); - /* Accept 'M' 'M' 'm' 'm' 'm' */ + /* Accept 'M' 'm' 'm' 'd' 'd' */ lip->yySkipn(5); if (version <= MYSQL_VERSION_ID) @@ -1255,16 +1258,36 @@ int MYSQLlex(void *arg, void *yythd) lip->yySkip(); // Accept / lip->yySkip(); // Accept * } - - while (! lip->eof() && - ((c=lip->yyGet()) != '*' || lip->yyPeek() != '/')) + /* + Discard: + - regular '/' '*' comments, + - special comments '/' '*' '!' for a future version, + by scanning until we find a closing '*' '/' marker. + Note: There is no such thing as nesting comments, + the first '*' '/' sequence seen will mark the end. + */ + comment_closed= FALSE; + while (! lip->eof()) { - if (c == '\n') + c= lip->yyGet(); + if (c == '*') + { + if (lip->yyPeek() == '/') + { + lip->yySkip(); + comment_closed= TRUE; + state = MY_LEX_START; + break; + } + } + else if (c == '\n') lip->yylineno++; } - if (! lip->eof()) - lip->yySkip(); // remove last '/' + /* Unbalanced comments with a missing '*' '/' are a syntax error */ + if (! comment_closed) + return (ABORT_SYM); state = MY_LEX_START; // Try again + lip->in_comment= NO_COMMENT; lip->set_echo(TRUE); break; case MY_LEX_END_LONG_COMMENT: @@ -1316,6 +1339,9 @@ int MYSQLlex(void *arg, void *yythd) lip->set_echo(FALSE); lip->yySkip(); lip->set_echo(TRUE); + /* Unbalanced comments with a missing '*' '/' are a syntax error */ + if (lip->in_comment != NO_COMMENT) + return (ABORT_SYM); lip->next_state=MY_LEX_END; // Mark for next loop return(END_OF_INPUT); } @@ -1556,7 +1582,6 @@ void st_select_lex::init_select() options= 0; sql_cache= SQL_CACHE_UNSPECIFIED; braces= 0; - expr_list.empty(); interval_list.empty(); ftfunc_list_alloc.empty(); inner_sum_func_list= 0; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 057d59d3ccf..da0134a7f72 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -596,7 +596,6 @@ public: const char *type; /* type of select for EXPLAIN */ SQL_LIST order_list; /* ORDER clause */ - List<List_item> expr_list; SQL_LIST *gorder_list; Item *select_limit, *offset_limit; /* LIMIT clause parameters */ // Arrays of pointers to top elements of all_fields list diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2e4ce65f1c4..bbd6cb16d11 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3381,6 +3381,8 @@ end_with_restore_list: } case SQLCOM_REVOKE_ALL: { + if (end_active_trans(thd)) + goto error; if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) && check_global_access(thd,CREATE_USER_ACL)) break; @@ -3392,6 +3394,9 @@ end_with_restore_list: case SQLCOM_REVOKE: case SQLCOM_GRANT: { + if (end_active_trans(thd)) + goto error; + if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL, first_table ? first_table->db : select_lex->db, first_table ? &first_table->grant.privilege : 0, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 6b60f89b8e3..9337a2aa329 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2868,6 +2868,19 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) init_param_array(this); lex->set_trg_event_type_for_tables(); + /* Remember the current database. */ + + if (thd->db && thd->db_length) + { + db= this->strmake(thd->db, thd->db_length); + db_length= thd->db_length; + } + else + { + db= NULL; + db_length= 0; + } + /* While doing context analysis of the query (in check_prepared_statement) we allocate a lot of additional memory: for open tables, JOINs, derived @@ -2974,6 +2987,13 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) Query_arena *old_stmt_arena; bool error= TRUE; + char saved_cur_db_name_buf[NAME_LEN+1]; + LEX_STRING saved_cur_db_name= + { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) }; + bool cur_db_changed; + + LEX_STRING stmt_db_name= { db, db_length }; + status_var_increment(thd->status_var.com_stmt_execute); /* Check if we got an error when sending long data */ @@ -3022,6 +3042,21 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) */ thd->set_n_backup_statement(this, &stmt_backup); + + /* + Change the current database (if needed). + + Force switching, because the database of the prepared statement may be + NULL (prepared statements can be created while no current database + selected). + */ + + if (mysql_opt_change_db(thd, &stmt_db_name, &saved_cur_db_name, TRUE, + &cur_db_changed)) + goto error; + + /* Allocate query. */ + if (expanded_query->length() && alloc_query(thd, (char*) expanded_query->ptr(), expanded_query->length()+1)) @@ -3050,6 +3085,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) thd->protocol= protocol; /* activate stmt protocol */ + /* Go! */ + if (open_cursor) error= mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR, &result, &cursor); @@ -3068,6 +3105,17 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) } } + /* + Restore the current database (if changed). + + Force switching back to the saved current database (if changed), + because it may be NULL. In this case, mysql_change_db() would generate + an error. + */ + + if (cur_db_changed) + mysql_change_db(thd, &saved_cur_db_name, TRUE); + thd->protocol= &thd->protocol_text; /* use normal protocol */ /* Assert that if an error, no cursor is open */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 2d6baf5b846..efd8c20e6d7 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -31,7 +31,7 @@ #define MYSQL_YACC #define YYINITDEPTH 100 -#define YYMAXDEPTH 3200 /* Because of 64K stack */ +#define YYMAXDEPTH 3200 /* Because of 64K stack */ #define Lex (YYTHD->lex) #define Select Lex->current_select #include "mysql_priv.h" @@ -506,12 +506,12 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %} -%pure_parser /* We have threads */ +%pure_parser /* We have threads */ /* - Currently there is 286 shift/reduce conflict. We should not introduce - new conflicts any more. + Currently there are 280 shift/reduce conflicts. + We should not introduce new conflicts any more. */ -%expect 286 +%expect 280 /* Comments for TOKENS. @@ -1091,7 +1091,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); /* A dummy token to force the priority of table_ref production in a join. */ %left TABLE_REF_PRIORITY %left SET_VAR -%left OR_OR_SYM OR_SYM OR2_SYM XOR +%left OR_OR_SYM OR_SYM OR2_SYM +%left XOR %left AND_SYM AND_AND_SYM %left BETWEEN_SYM CASE_SYM WHEN_SYM THEN_SYM ELSE %left EQ EQUAL_SYM GE GT_SYM LE LT NE IS LIKE REGEXP IN_SYM @@ -1104,6 +1105,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %left NEG '~' %right NOT_SYM NOT2_SYM %right BINARY COLLATE_SYM +%left INTERVAL_SYM %type <lex_str> IDENT IDENT_QUOTED TEXT_STRING DECIMAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM @@ -1152,8 +1154,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <item> literal text_literal insert_ident order_ident simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr - variable variable_aux bool_term bool_factor bool_test bool_pri - predicate bit_expr bit_term bit_factor value_expr term factor + variable variable_aux bool_pri + predicate bit_expr table_wild simple_expr udf_expr expr_or_default set_expr_or_default interval_expr param_marker geometry_function @@ -1171,7 +1173,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); NUM_literal %type <item_list> - expr_list udf_expr_list udf_expr_list2 when_list + expr_list opt_udf_expr_list udf_expr_list when_list ident_list ident_list_arg opt_expr_list %type <var_type> @@ -1245,7 +1247,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); select_item_list select_item values_list no_braces opt_limit_clause delete_limit_clause fields opt_values values procedure_list procedure_list2 procedure_item - expr_list2 udf_expr_list3 handler + handler opt_precision opt_ignore opt_column opt_restrict grant revoke set lock unlock string_list field_options field_option field_opt_list opt_binary table_lock_list table_lock @@ -1315,10 +1317,11 @@ rule: <-- starts at col 1 } ; <-- on a line by itself, starts at col 9 -Also, please do not use any <TAB>, but spaces. -Having a uniform indentation in this file helps -code reviews, patches, merges, and make maintenance easier. -Thanks. + Also, please do not use any <TAB>, but spaces. + Having a uniform indentation in this file helps + code reviews, patches, merges, and make maintenance easier. + Tip: grep [[:cntrl:]] sql_yacc.yy + Thanks. */ query: @@ -5157,7 +5160,7 @@ opt_bin_charset: MYSQL_YYABORT; } } - | charset charset_name { Lex->charset=$2; } + | charset charset_name { Lex->charset=$2; } ; opt_primary: @@ -5379,7 +5382,7 @@ alter: lex->create_info.row_type= ROW_TYPE_NOT_USED; lex->alter_info.reset(); lex->no_write_to_binlog= 0; - lex->create_info.storage_media= HA_SM_DEFAULT; + lex->create_info.storage_media= HA_SM_DEFAULT; } alter_commands {} @@ -6564,83 +6567,131 @@ optional_braces: ; /* all possible expressions */ -expr: - bool_term { Select->expr_list.push_front(new List<Item>); } - bool_or_expr +expr: + expr or expr %prec OR_SYM { - List<Item> *list= Select->expr_list.pop(); - if (list->elements) + /* + Design notes: + Do not use a manually maintained stack like thd->lex->xxx_list, + but use the internal bison stack ($$, $1 and $3) instead. + Using the bison stack is: + - more robust to changes in the grammar, + - guaranteed to be in sync with the parser state, + - better for performances (no memory allocation). + */ + Item_cond_or *item1; + Item_cond_or *item3; + if (is_cond_or($1)) { - list->push_front($1); - $$= new Item_cond_or(*list); - /* optimize construction of logical OR to reduce - amount of objects for complex expressions */ + item1= (Item_cond_or*) $1; + if (is_cond_or($3)) + { + item3= (Item_cond_or*) $3; + /* + (X1 OR X2) OR (Y1 OR Y2) ==> OR (X1, X2, Y1, Y2) + */ + item3->add_at_head(item1->argument_list()); + $$ = $3; + } + else + { + /* + (X1 OR X2) OR Y ==> OR (X1, X2, Y) + */ + item1->add($3); + $$ = $1; + } + } + else if (is_cond_or($3)) + { + item3= (Item_cond_or*) $3; + /* + X OR (Y1 OR Y2) ==> OR (X, Y1, Y2) + */ + item3->add_at_head($1); + $$ = $3; } else - $$= $1; - delete list; + { + /* X OR Y */ + $$ = new (YYTHD->mem_root) Item_cond_or($1, $3); + } } - ; - -bool_or_expr: - /* empty */ - | bool_or_expr or bool_term - { Select->expr_list.head()->push_back($3); } - ; - -bool_term: - bool_term XOR bool_term { $$= new Item_cond_xor($1,$3); } - | bool_factor { Select->expr_list.push_front(new List<Item>); } - bool_and_expr + | expr XOR expr %prec XOR + { + /* XOR is a proprietary extension */ + $$ = new (YYTHD->mem_root) Item_cond_xor($1, $3); + } + | expr and expr %prec AND_SYM { - List<Item> *list= Select->expr_list.pop(); - if (list->elements) + /* See comments in rule expr: expr or expr */ + Item_cond_and *item1; + Item_cond_and *item3; + if (is_cond_and($1)) { - list->push_front($1); - $$= new Item_cond_and(*list); - /* optimize construction of logical AND to reduce - amount of objects for complex expressions */ + item1= (Item_cond_and*) $1; + if (is_cond_and($3)) + { + item3= (Item_cond_and*) $3; + /* + (X1 AND X2) AND (Y1 AND Y2) ==> AND (X1, X2, Y1, Y2) + */ + item3->add_at_head(item1->argument_list()); + $$ = $3; + } + else + { + /* + (X1 AND X2) AND Y ==> AND (X1, X2, Y) + */ + item1->add($3); + $$ = $1; + } + } + else if (is_cond_and($3)) + { + item3= (Item_cond_and*) $3; + /* + X AND (Y1 AND Y2) ==> AND (X, Y1, Y2) + */ + item3->add_at_head($1); + $$ = $3; } else - $$= $1; - delete list; + { + /* X AND Y */ + $$ = new (YYTHD->mem_root) Item_cond_and($1, $3); + } } - ; - -bool_and_expr: - /* empty */ - | bool_and_expr and bool_factor - { Select->expr_list.head()->push_back($3); } - ; - -bool_factor: - NOT_SYM bool_factor { $$= negate_expression(YYTHD, $2); } - | bool_test - ; - -bool_test: - bool_pri IS TRUE_SYM + | NOT_SYM expr %prec NOT_SYM + { $$= negate_expression(YYTHD, $2); } + | bool_pri IS TRUE_SYM %prec IS { $$= new (YYTHD->mem_root) Item_func_istrue($1); } - | bool_pri IS not TRUE_SYM + | bool_pri IS not TRUE_SYM %prec IS { $$= new (YYTHD->mem_root) Item_func_isnottrue($1); } - | bool_pri IS FALSE_SYM + | bool_pri IS FALSE_SYM %prec IS { $$= new (YYTHD->mem_root) Item_func_isfalse($1); } - | bool_pri IS not FALSE_SYM + | bool_pri IS not FALSE_SYM %prec IS { $$= new (YYTHD->mem_root) Item_func_isnotfalse($1); } - | bool_pri IS UNKNOWN_SYM { $$= new Item_func_isnull($1); } - | bool_pri IS not UNKNOWN_SYM { $$= new Item_func_isnotnull($1); } + | bool_pri IS UNKNOWN_SYM %prec IS + { $$= new Item_func_isnull($1); } + | bool_pri IS not UNKNOWN_SYM %prec IS + { $$= new Item_func_isnotnull($1); } | bool_pri ; bool_pri: - bool_pri IS NULL_SYM { $$= new Item_func_isnull($1); } - | bool_pri IS not NULL_SYM { $$= new Item_func_isnotnull($1); } - | bool_pri EQUAL_SYM predicate { $$= new Item_func_equal($1,$3); } + bool_pri IS NULL_SYM %prec IS + { $$= new Item_func_isnull($1); } + | bool_pri IS not NULL_SYM %prec IS + { $$= new Item_func_isnotnull($1); } + | bool_pri EQUAL_SYM predicate %prec EQUAL_SYM + { $$= new Item_func_equal($1,$3); } | bool_pri comp_op predicate %prec EQ { $$= (*$2)(0)->create($1,$3); } | bool_pri comp_op all_or_any '(' subselect ')' %prec EQ { $$= all_any_subquery_creator($1, $2, $3, $5); } - | predicate + | predicate ; ; predicate: @@ -6700,44 +6751,34 @@ predicate: ; bit_expr: - bit_expr '|' bit_term { $$= new Item_func_bit_or($1,$3); } - | bit_term - ; - -bit_term: - bit_term '&' bit_factor { $$= new Item_func_bit_and($1,$3); } - | bit_factor - ; - -bit_factor: - bit_factor SHIFT_LEFT value_expr + bit_expr '|' bit_expr %prec '|' + { $$= new Item_func_bit_or($1,$3); } + | bit_expr '&' bit_expr %prec '&' + { $$= new Item_func_bit_and($1,$3); } + | bit_expr SHIFT_LEFT bit_expr %prec SHIFT_LEFT { $$= new Item_func_shift_left($1,$3); } - | bit_factor SHIFT_RIGHT value_expr + | bit_expr SHIFT_RIGHT bit_expr %prec SHIFT_RIGHT { $$= new Item_func_shift_right($1,$3); } - | value_expr - ; - -value_expr: - value_expr '+' term { $$= new Item_func_plus($1,$3); } - | value_expr '-' term { $$= new Item_func_minus($1,$3); } - | value_expr '+' interval_expr interval + | bit_expr '+' bit_expr %prec '+' + { $$= new Item_func_plus($1,$3); } + | bit_expr '-' bit_expr %prec '-' + { $$= new Item_func_minus($1,$3); } + | bit_expr '+' interval_expr interval %prec '+' { $$= new Item_date_add_interval($1,$3,$4,0); } - | value_expr '-' interval_expr interval + | bit_expr '-' interval_expr interval %prec '-' { $$= new Item_date_add_interval($1,$3,$4,1); } - | term - ; - -term: - term '*' factor { $$= new Item_func_mul($1,$3); } - | term '/' factor { $$= new Item_func_div($1,$3); } - | term '%' factor { $$= new Item_func_mod($1,$3); } - | term DIV_SYM factor { $$= new Item_func_int_div($1,$3); } - | term MOD_SYM factor { $$= new Item_func_mod($1,$3); } - | factor - ; - -factor: - factor '^' simple_expr { $$= new Item_func_bit_xor($1,$3); } + | bit_expr '*' bit_expr %prec '*' + { $$= new Item_func_mul($1,$3); } + | bit_expr '/' bit_expr %prec '/' + { $$= new Item_func_div($1,$3); } + | bit_expr '%' bit_expr %prec '%' + { $$= new Item_func_mod($1,$3); } + | bit_expr DIV_SYM bit_expr %prec DIV_SYM + { $$= new Item_func_int_div($1,$3); } + | bit_expr MOD_SYM bit_expr %prec MOD_SYM + { $$= new Item_func_mod($1,$3); } + | bit_expr '^' bit_expr + { $$= new Item_func_bit_xor($1,$3); } | simple_expr ; @@ -6776,7 +6817,8 @@ all_or_any: ; interval_expr: - INTERVAL_SYM expr { $$=$2; } + INTERVAL_SYM expr %prec INTERVAL_SYM + { $$=$2; } ; simple_expr: @@ -6799,7 +6841,7 @@ simple_expr: | sum_expr | simple_expr OR_OR_SYM simple_expr { $$= new (YYTHD->mem_root) Item_func_concat($1, $3); } - | '+' simple_expr %prec NEG { $$= $2; } + | '+' simple_expr %prec NEG { $$= $2; } | '-' simple_expr %prec NEG { $$= new (YYTHD->mem_root) Item_func_neg($2); } | '~' simple_expr %prec NEG @@ -7210,7 +7252,7 @@ function_call_generic: $<udf>$= udf; #endif } - udf_expr_list ')' + opt_udf_expr_list ')' { THD *thd= YYTHD; Create_func *builder; @@ -7307,27 +7349,23 @@ opt_query_expansion: | WITH QUERY_SYM EXPANSION_SYM { $$= FT_EXPAND; } ; +opt_udf_expr_list: + /* empty */ { $$= NULL; } + | udf_expr_list { $$= $1; } + ; + udf_expr_list: - /* empty */ { $$= NULL; } - | udf_expr_list2 { $$= $1;} - ; - -udf_expr_list2: - { Select->expr_list.push_front(new List<Item>); } - udf_expr_list3 - { $$= Select->expr_list.pop(); } - ; - -udf_expr_list3: - udf_expr - { - Select->expr_list.head()->push_back($1); - } - | udf_expr_list3 ',' udf_expr - { - Select->expr_list.head()->push_back($3); - } - ; + udf_expr + { + $$= new (YYTHD->mem_root) List<Item>; + $$->push_back($1); + } + | udf_expr_list ',' udf_expr + { + $1->push_back($3); + $$= $1; + } + ; udf_expr: remember_name expr remember_end select_alias @@ -7525,13 +7563,17 @@ opt_expr_list: ; expr_list: - { Select->expr_list.push_front(new List<Item>); } - expr_list2 - { $$= Select->expr_list.pop(); }; - -expr_list2: - expr { Select->expr_list.head()->push_back($1); } - | expr_list2 ',' expr { Select->expr_list.head()->push_back($3); }; + expr + { + $$= new (YYTHD->mem_root) List<Item>; + $$->push_back($1); + } + | expr_list ',' expr + { + $1->push_back($3); + $$= $1; + } + ; ident_list_arg: ident_list { $$= $1; } @@ -7539,13 +7581,17 @@ ident_list_arg: ; ident_list: - { Select->expr_list.push_front(new List<Item>); } - ident_list2 - { $$= Select->expr_list.pop(); }; - -ident_list2: - simple_ident { Select->expr_list.head()->push_back($1); } - | ident_list2 ',' simple_ident { Select->expr_list.head()->push_back($3); }; + simple_ident + { + $$= new (YYTHD->mem_root) List<Item>; + $$->push_back($1); + } + | ident_list ',' simple_ident + { + $1->push_back($3); + $$= $1; + } + ; opt_expr: /* empty */ { $$= NULL; } diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index ded0ce88484..edcd1127dbd 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -3169,7 +3169,7 @@ int ha_federated::external_lock(THD *thd, int lock_type) #ifdef XXX_SUPERCEDED_BY_WL2952 if (lock_type != F_UNLCK) { - ha_federated *trx= (ha_federated *)thd->ha_data[ht->slot]; + ha_federated *trx= (ha_federated *)thd_get_ha_data(thd, ht); DBUG_PRINT("info",("federated not lock F_UNLCK")); if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) @@ -3200,7 +3200,7 @@ int ha_federated::external_lock(THD *thd, int lock_type) DBUG_PRINT("info", ("error setting autocommit FALSE: %d", error)); DBUG_RETURN(error); } - thd->ha_data[ht->slot]= this; + thd_set_ha_data(thd, ht, this); trans_register_ha(thd, TRUE, ht); /* Send a lock table to the remote end. @@ -3230,7 +3230,7 @@ int ha_federated::external_lock(THD *thd, int lock_type) static int federated_commit(handlerton *hton, THD *thd, bool all) { int return_val= 0; - ha_federated *trx= (ha_federated *)thd->ha_data[hton->slot]; + ha_federated *trx= (ha_federated *) thd_get_ha_data(thd, hton); DBUG_ENTER("federated_commit"); if (all) @@ -3245,7 +3245,7 @@ static int federated_commit(handlerton *hton, THD *thd, bool all) if (error && !return_val) return_val= error; } - thd->ha_data[hton->slot]= NULL; + thd_set_ha_data(thd, hton, NULL); } DBUG_PRINT("info", ("error val: %d", return_val)); @@ -3256,7 +3256,7 @@ static int federated_commit(handlerton *hton, THD *thd, bool all) static int federated_rollback(handlerton *hton, THD *thd, bool all) { int return_val= 0; - ha_federated *trx= (ha_federated *)thd->ha_data[hton->slot]; + ha_federated *trx= (ha_federated *)thd_get_ha_data(thd, hton); DBUG_ENTER("federated_rollback"); if (all) @@ -3271,7 +3271,7 @@ static int federated_rollback(handlerton *hton, THD *thd, bool all) if (error && !return_val) return_val= error; } - thd->ha_data[hton->slot]= NULL; + thd_set_ha_data(thd, hton, NULL); } DBUG_PRINT("info", ("error val: %d", return_val)); |