summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <malff/marcsql@weblab.(none)>2007-09-04 12:25:54 -0600
committerunknown <malff/marcsql@weblab.(none)>2007-09-04 12:25:54 -0600
commitc458f7f6a3b6cf6754c9843d6801c9b0f86ffe48 (patch)
treee709d9cce3d8a2b77acda70637623f1faf7eb64f
parent943ed8fe354734fa52417bf36920462ab23756d3 (diff)
parent6bfae914a2a0e7661c75c030b0bf88c8490323ed (diff)
downloadmariadb-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
-rwxr-xr-xBUILD/SETUP.sh27
-rwxr-xr-xBUILD/compile-amd64-gcov17
-rwxr-xr-xBUILD/compile-amd64-gprof9
-rwxr-xr-xBUILD/compile-pentium-gcov13
-rwxr-xr-xBUILD/compile-pentium-gprof4
-rwxr-xr-xBUILD/compile-pentium64-gcov17
-rwxr-xr-xBUILD/compile-pentium64-gprof9
-rw-r--r--client/mysql.cc54
-rw-r--r--include/my_global.h12
-rw-r--r--include/mysql/plugin.h23
-rw-r--r--mysql-test/include/deadlock.inc27
-rw-r--r--mysql-test/include/handler.inc19
-rw-r--r--mysql-test/include/query_cache_sql_prepare.inc218
-rw-r--r--mysql-test/r/comments.result15
-rw-r--r--mysql-test/r/deadlock_innodb.result11
-rw-r--r--mysql-test/r/events.result29
-rw-r--r--mysql-test/r/handler_innodb.result13
-rw-r--r--mysql-test/r/handler_myisam.result13
-rw-r--r--mysql-test/r/insert_update.result19
-rw-r--r--mysql-test/r/mysql.result2
-rw-r--r--mysql-test/r/parser_precedence.result747
-rw-r--r--mysql-test/r/query_cache_ps_no_prot.result158
-rw-r--r--mysql-test/r/query_cache_ps_ps_prot.result158
-rw-r--r--mysql-test/r/sp-error.result12
-rw-r--r--mysql-test/r/sp.result75
-rw-r--r--mysql-test/suite/rpl/r/rpl_binlog_grant.result50
-rw-r--r--mysql-test/suite/rpl/r/rpl_ps.result50
-rw-r--r--mysql-test/suite/rpl/t/rpl_binlog_grant.test41
-rw-r--r--mysql-test/suite/rpl/t/rpl_ps.test95
-rw-r--r--mysql-test/t/comments.test31
-rw-r--r--mysql-test/t/events.test54
-rw-r--r--mysql-test/t/insert_update.test35
-rw-r--r--mysql-test/t/mysql.test5
-rw-r--r--mysql-test/t/parser_precedence.test333
-rw-r--r--mysql-test/t/sp-error.test15
-rw-r--r--mysql-test/t/sp.test119
-rw-r--r--sql/ha_ndbcluster_binlog.h6
-rw-r--r--sql/handler.cc4
-rw-r--r--sql/item_cmpfunc.h18
-rw-r--r--sql/lock.cc2
-rw-r--r--sql/log.cc56
-rw-r--r--sql/mysql_priv.h7
-rw-r--r--sql/rpl_utility.h2
-rw-r--r--sql/sp.cc142
-rw-r--r--sql/sp.h11
-rw-r--r--sql/sp_head.cc25
-rw-r--r--sql/sql_base.cc38
-rw-r--r--sql/sql_class.cc7
-rw-r--r--sql/sql_class.h79
-rw-r--r--sql/sql_db.cc183
-rw-r--r--sql/sql_handler.cc6
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_lex.cc45
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_parse.cc5
-rw-r--r--sql/sql_prepare.cc48
-rw-r--r--sql/sql_yacc.yy330
-rw-r--r--storage/federated/ha_federated.cc12
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);
-}
diff --git a/sql/sp.h b/sql/sp.h
index 52b0344a2e2..3797eb289a4 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -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));