summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormalff/marcsql@weblab.(none) <>2007-08-30 13:23:59 -0600
committermalff/marcsql@weblab.(none) <>2007-08-30 13:23:59 -0600
commit2482c59740ba73b62851f175fbe2b7adf70f76ae (patch)
tree8a9eb637bc86a49e83f7ac315d1483f381fea0a2
parent52ae4496c560829fe48a4a1c6145b17199492b4d (diff)
parent7ed3555c673db711db27cf645fd4aaa367402922 (diff)
downloadmariadb-git-2482c59740ba73b62851f175fbe2b7adf70f76ae.tar.gz
Merge weblab.(none):/home/marcsql/TREE/mysql-5.1-base
into weblab.(none):/home/marcsql/TREE/mysql-5.1-rt50-merge
-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--mysql-test/include/deadlock.inc27
-rw-r--r--mysql-test/include/handler.inc19
-rw-r--r--mysql-test/r/comments.result15
-rw-r--r--mysql-test/r/deadlock_innodb.result11
-rw-r--r--mysql-test/r/events.result3
-rw-r--r--mysql-test/r/handler_innodb.result13
-rw-r--r--mysql-test/r/handler_myisam.result13
-rw-r--r--mysql-test/r/mysql.result2
-rw-r--r--mysql-test/r/parser_precedence.result747
-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/t/rpl_binlog_grant.test41
-rw-r--r--mysql-test/t/comments.test31
-rw-r--r--mysql-test/t/events.test8
-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/item_cmpfunc.h18
-rw-r--r--sql/lock.cc2
-rw-r--r--sql/sp.cc57
-rw-r--r--sql/sp_head.cc3
-rw-r--r--sql/sql_class.h39
-rw-r--r--sql/sql_db.cc87
-rw-r--r--sql/sql_handler.cc6
-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_yacc.yy330
38 files changed, 2041 insertions, 241 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/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/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..be67e2acc7b 100644
--- a/mysql-test/r/events.result
+++ b/mysql-test/r/events.result
@@ -499,6 +499,9 @@ set global event_scheduler=off;
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;
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/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/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/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/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..cbb36cbd2be 100644
--- a/mysql-test/t/events.test
+++ b/mysql-test/t/events.test
@@ -466,13 +466,17 @@ 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
+let $wait_condition= select count(*) = 3 from information_schema.processlist;
+--source include/wait_condition.inc
--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;
set global event_scheduler=off;
---sleep 0.8
+let $wait_condition= select count(*) =1 from information_schema.processlist
+ where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info;
+--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 release_lock("test_lock2_1");
drop event закачка21;
let $wait_condition=
select count(*) = 0 from information_schema.processlist
diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test
index 16f5fecf051..74944b11c02 100644
--- a/mysql-test/t/mysql.test
+++ b/mysql-test/t/mysql.test
@@ -274,6 +274,11 @@ EOF
--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/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/sp.cc b/sql/sp.cc
index 437ffb3b484..4828618c0cb 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -575,7 +575,7 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
we'll update it later in switch_query_ctx().
*/
- if ((ret= sp_use_new_db(thd, name->m_db, &old_db, 1, &dbchanged)))
+ if ((ret= sp_use_new_db(thd, name->m_db, &old_db, TRUE, &dbchanged)))
goto end;
thd->spcont= NULL;
@@ -2028,34 +2028,41 @@ create_string(THD *thd, String *buf,
-/*
+/**
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)
+ @param[in] thd thread handle
+ @param[in] new_db new database name
+ @param[in, out] 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).
+ @param[in] force_switch Flag to mysql_change_db(). For more information,
+ see mysql_change_db() comment.
+ @param[out] dbchangedp is set to TRUE if the current database is
+ changed, FALSE otherwise. The current
+ database is not changed if the old name
+ is equal to the new one, both names are
+ empty, or an error has occurred.
+
+ @return Operation status.
+ @retval 0 on success
+ @retval 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)
+sp_use_new_db(THD *thd,
+ LEX_STRING new_db,
+ LEX_STRING *old_db,
+ bool force_switch,
+ bool *dbchangedp)
{
int ret;
DBUG_ENTER("sp_use_new_db");
@@ -2086,7 +2093,7 @@ sp_use_new_db(THD *thd, LEX_STRING new_db, LEX_STRING *old_db,
DBUG_RETURN(0);
}
- ret= mysql_change_db(thd, &new_db, no_access_check);
+ ret= mysql_change_db(thd, &new_db, force_switch);
*dbchangedp= ret == 0;
DBUG_RETURN(ret);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index b8535ee9958..e9275dff9e3 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:
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 7117c08a7e1..0a3aa3ed20c 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1802,11 +1802,27 @@ 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 {thd->db, thd->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 +1837,19 @@ 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 {thd->db, thd->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..9b6aa564128 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:
@@ -1356,21 +1360,48 @@ static void mysql_change_db_impl(THD *thd,
/**
- @brief Change the current database.
+ @brief Change the current database and its attributes.
@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 +1438,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 +1462,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 +1489,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 +1499,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 +1535,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 +1547,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);
}
}
@@ -1829,7 +1872,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_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_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; }