diff --git a/.bzrignore b/.bzrignore index 759ca4a20bf..35f5199be3c 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1345,3 +1345,8 @@ zlib/*.vcproj debian/control debian/defs.mk include/abi_check +support-files/mysqld_multi.server +tests/bug25714 +cscope.in.out +cscope.out +cscope.po.out diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 10324c22e56..532ea4eb0f1 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -138,3 +138,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 0d561d5b147..d4878dc591e 100755 --- a/BUILD/compile-pentium-gcov +++ b/BUILD/compile-pentium-gcov @@ -7,18 +7,11 @@ path=`dirname $0` CCACHE_DISABLE=1 export CCACHE_DISABLE -# 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 $debug_cflags $max_cflags -DMYSQL_SERVER_SUFFIX=-gcov -DHAVE_gcov" +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 --disable-shared $static_link" -extra_configs="$extra_configs $max_configs" +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 277b56328a6..8e1b6c2a9b4 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1245,6 +1245,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()) @@ -1293,22 +1294,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 { @@ -1368,7 +1383,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; @@ -1376,6 +1391,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/client/mysqldump.c b/client/mysqldump.c index 577e439d6a7..cc8458c7a8e 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -2898,7 +2898,7 @@ int init_dumping_tables(char *qdatabase) /* Old server version, dump generic CREATE DATABASE */ if (opt_drop_database) fprintf(md_result_file, - "\n/*!40000 DROP DATABASE IF EXISTS %s;*/\n", + "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n", qdatabase); fprintf(md_result_file, "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index 439b13af779..cbc3e754312 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -43,7 +43,9 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I.. dist-hook: mkdir -p $(distdir)/t $(distdir)/r $(distdir)/include \ - $(distdir)/std_data $(distdir)/lib + $(distdir)/std_data \ + $(distdir)/std_data/ndb_backup50_data_be $(distdir)/std_data/ndb_backup50_data_le \ + $(distdir)/lib -$(INSTALL_DATA) $(srcdir)/t/*.def $(distdir)/t $(INSTALL_DATA) $(srcdir)/t/*.test $(distdir)/t -$(INSTALL_DATA) $(srcdir)/t/*.imtest $(distdir)/t @@ -62,6 +64,8 @@ dist-hook: $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.MY* $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(distdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup50_data_be/BACKUP* $(distdir)/std_data/ndb_backup50_data_be + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup50_data_le/BACKUP* $(distdir)/std_data/ndb_backup50_data_le $(INSTALL_DATA) $(srcdir)/lib/*.pl $(distdir)/lib -rm -rf `find $(distdir)/suite -type d -name SCCS` @@ -71,6 +75,8 @@ install-data-local: $(DESTDIR)$(testdir)/r \ $(DESTDIR)$(testdir)/include \ $(DESTDIR)$(testdir)/std_data \ + $(DESTDIR)$(testdir)/std_data/ndb_backup50_data_be \ + $(DESTDIR)$(testdir)/std_data/ndb_backup50_data_le \ $(DESTDIR)$(testdir)/lib $(INSTALL_DATA) $(srcdir)/README $(DESTDIR)$(testdir) -$(INSTALL_DATA) $(srcdir)/t/*.def $(DESTDIR)$(testdir)/t @@ -95,6 +101,8 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.MY* $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(DESTDIR)$(testdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup50_data_be/BACKUP* $(DESTDIR)$(testdir)/std_data/ndb_backup50_data_be + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup50_data_le/BACKUP* $(DESTDIR)$(testdir)/std_data/ndb_backup50_data_le $(INSTALL_DATA) $(srcdir)/lib/*.pl $(DESTDIR)$(testdir)/lib for f in `(cd $(srcdir); find suite -type f | grep -v SCCS)`; \ do \ diff --git a/mysql-test/r/comments.result b/mysql-test/r/comments.result index a9106ce0538..1040c3fc8e9 100644 --- a/mysql-test/r/comments.result +++ b/mysql-test/r/comments.result @@ -26,3 +26,18 @@ select 1 # The rest of the row will be ignored 1 1 /* line with only comment */; +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/delete.result b/mysql-test/r/delete.result index 4bdf1c770d3..5084498c01c 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -183,6 +183,17 @@ select @a; @a 1 drop table t1; +CREATE TABLE t1 ( +`date` date , +`time` time , +`seq` int(10) unsigned NOT NULL auto_increment, +PRIMARY KEY (`seq`), +KEY `seq` (`seq`), +KEY `time` (`time`), +KEY `date` (`date`) +); +DELETE FROM t1 ORDER BY date ASC, time ASC LIMIT 1; +drop table t1; End of 4.1 tests CREATE TABLE t1 (a int not null,b int not null); CREATE TABLE t2 (a int not null, b int not null, primary key (a,b)); @@ -223,3 +234,40 @@ ERROR 42S22: Unknown column 't2.x' in 'order clause' DELETE FROM t1 ORDER BY (SELECT x); ERROR 42S22: Unknown column 'x' in 'field list' DROP TABLE t1; +CREATE TABLE t1 ( +a INT +); +CREATE TABLE t2 ( +a INT +); +CREATE DATABASE db1; +CREATE TABLE db1.t1 ( +a INT +); +INSERT INTO db1.t1 (a) SELECT * FROM t1; +CREATE DATABASE db2; +CREATE TABLE db2.t1 ( +a INT +); +INSERT INTO db2.t1 (a) SELECT * FROM t2; +DELETE FROM t1 alias USING t1, t2 alias WHERE t1.a = alias.a; +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 'alias USING t1, t2 alias WHERE t1.a = alias.a' at line 1 +DELETE FROM alias USING t1, t2 alias WHERE t1.a = alias.a; +DELETE FROM t1, alias USING t1, t2 alias WHERE t1.a = alias.a; +DELETE FROM t1, t2 USING t1, t2 alias WHERE t1.a = alias.a; +ERROR 42S02: Unknown table 't2' in MULTI DELETE +DELETE FROM db1.t1 alias USING db1.t1, db2.t1 alias WHERE db1.t1.a = alias.a; +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 'alias USING db1.t1, db2.t1 alias WHERE db1.t1.a = alias.a' at line 1 +DELETE FROM alias USING db1.t1, db2.t1 alias WHERE db1.t1.a = alias.a; +ERROR 42S02: Unknown table 'alias' in MULTI DELETE +DELETE FROM db2.alias USING db1.t1, db2.t1 alias WHERE db1.t1.a = alias.a; +DELETE FROM t1 USING t1 WHERE a = 1; +SELECT * FROM t1; +a +DELETE FROM t1 alias USING t1 alias WHERE a = 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 'alias USING t1 alias WHERE a = 2' at line 1 +SELECT * FROM t1; +a +DROP TABLE t1, t2; +DROP DATABASE db1; +DROP DATABASE db2; diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index 8525e0f19e4..8cfe5aa78b5 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -526,10 +526,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 3 Using index EXPLAIN SELECT a,b FROM t1 GROUP BY a,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort EXPLAIN SELECT DISTINCT a,b FROM t1 GROUP BY a,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort CREATE TABLE t2(a INT, b INT NOT NULL, c INT NOT NULL, d INT, PRIMARY KEY (a,b)); INSERT INTO t2 VALUES (1,1,1,50), (1,2,3,40), (2,1,3,4); @@ -554,7 +554,7 @@ id select_type table type possible_keys key key_len ref rows Extra CREATE UNIQUE INDEX c_b_unq ON t2 (c,b); EXPLAIN SELECT DISTINCT a,b,d FROM t2 GROUP BY c,b,d; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using filesort DROP TABLE t1,t2; create table t1 (id int, dsc varchar(50)); insert into t1 values (1, "line number one"), (2, "line number two"), (3, "line number three"); diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index d4ffbe43a91..053c2901509 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -1064,3 +1064,52 @@ select t1.f1,t.* from t1, t1 t group by 1; ERROR 42000: 'test.t.f1' isn't in GROUP BY drop table t1; SET SQL_MODE = ''; +CREATE TABLE t1( +a INT, +b INT NOT NULL, +c INT NOT NULL, +d INT, +UNIQUE KEY (c,b) +); +INSERT INTO t1 VALUES (1,1,1,50), (1,2,3,40), (2,1,3,4); +EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b,d; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort +SELECT c,b,d FROM t1 GROUP BY c,b,d; +c b d +1 1 50 +3 1 4 +3 2 40 +EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b,d ORDER BY NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +SELECT c,b,d FROM t1 GROUP BY c,b,d ORDER BY NULL; +c b d +1 1 50 +3 2 40 +3 1 4 +EXPLAIN SELECT c,b,d FROM t1 ORDER BY c,b,d; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort +SELECT c,b,d FROM t1 ORDER BY c,b,d; +c b d +1 1 50 +3 1 4 +3 2 40 +EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort +SELECT c,b,d FROM t1 GROUP BY c,b; +c b d +1 1 50 +3 1 4 +3 2 40 +EXPLAIN SELECT c,b FROM t1 GROUP BY c,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL c 8 NULL 3 Using index +SELECT c,b FROM t1 GROUP BY c,b; +c b +1 1 +3 1 +3 2 +DROP TABLE t1; diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index 5e123df9103..dc3750e16ea 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -489,3 +489,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 HY000: 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 HY000: 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/innodb-deadlock.result b/mysql-test/r/innodb-deadlock.result index 2ca82101fb4..b6a3373e8c6 100644 --- a/mysql-test/r/innodb-deadlock.result +++ b/mysql-test/r/innodb-deadlock.result @@ -94,3 +94,14 @@ id x 300 300 commit; 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/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index c93d26bbd04..be678efd0ef 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1065,4 +1065,53 @@ a b ROLLBACK; ROLLBACK; DROP TABLE t1; +CREATE TABLE t1( +a INT, +b INT NOT NULL, +c INT NOT NULL, +d INT, +UNIQUE KEY (c,b) +) engine=innodb; +INSERT INTO t1 VALUES (1,1,1,50), (1,2,3,40), (2,1,3,4); +EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b,d; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort +SELECT c,b,d FROM t1 GROUP BY c,b,d; +c b d +1 1 50 +3 1 4 +3 2 40 +EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b,d ORDER BY NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +SELECT c,b,d FROM t1 GROUP BY c,b,d ORDER BY NULL; +c b d +1 1 50 +3 1 4 +3 2 40 +EXPLAIN SELECT c,b,d FROM t1 ORDER BY c,b,d; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort +SELECT c,b,d FROM t1 ORDER BY c,b,d; +c b d +1 1 50 +3 1 4 +3 2 40 +EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL c 8 NULL 3 +SELECT c,b,d FROM t1 GROUP BY c,b; +c b d +1 1 50 +3 1 4 +3 2 40 +EXPLAIN SELECT c,b FROM t1 GROUP BY c,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL c 8 NULL 3 Using index +SELECT c,b FROM t1 GROUP BY c,b; +c b +1 1 +3 1 +3 2 +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index 843f2c7285a..74b5c42e59b 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -176,4 +176,6 @@ 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 diff --git a/mysql-test/r/mysqldump-compat.result b/mysql-test/r/mysqldump-compat.result new file mode 100644 index 00000000000..f15cc7a1d7a --- /dev/null +++ b/mysql-test/r/mysqldump-compat.result @@ -0,0 +1,4 @@ +CREATE DATABASE mysqldump_30126; +USE mysqldump_30126; +CREATE TABLE t1 (c1 int); +DROP DATABASE mysqldump_30126; diff --git a/mysql-test/r/ndb_bug26793.result b/mysql-test/r/ndb_bug26793.result new file mode 100644 index 00000000000..a9a8a798546 --- /dev/null +++ b/mysql-test/r/ndb_bug26793.result @@ -0,0 +1,8 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE `test` ( +`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , +`t` VARCHAR( 10 ) NOT NULL +) ENGINE = ndbcluster; +GRANT USAGE ON *.* TO user1@localhost IDENTIFIED BY 'pass'; +DROP TABLE `test`.`test`; +drop user user1@localhost; diff --git a/mysql-test/r/ndb_read_multi_range.result b/mysql-test/r/ndb_read_multi_range.result index 64a6749bed1..d18f4c1e65a 100644 --- a/mysql-test/r/ndb_read_multi_range.result +++ b/mysql-test/r/ndb_read_multi_range.result @@ -405,3 +405,22 @@ a b 1 1 10 10 drop table t2; +create table t1 (id int primary key) engine ndb; +insert into t1 values (1), (2), (3); +create table t2 (id int primary key) engine ndb; +insert into t2 select id from t1; +create trigger kaboom after delete on t1 +for each row begin +delete from t2 where id=old.id; +end| +select * from t1 order by id; +id +1 +2 +3 +delete from t1 where id in (1,2); +select * from t2 order by id; +id +3 +drop trigger kaboom; +drop table t1; diff --git a/mysql-test/r/ndb_restore_different_endian_data.result b/mysql-test/r/ndb_restore_different_endian_data.result new file mode 100644 index 00000000000..e1efefb751a --- /dev/null +++ b/mysql-test/r/ndb_restore_different_endian_data.result @@ -0,0 +1,200 @@ +USE test; +DROP TABLE IF EXISTS t_num,t_datetime,t_string_1,t_string_2,t_gis; +SHOW TABLES; +Tables_in_test +t_gis +t_string_1 +t_num +t_string_2 +t_datetime +SHOW CREATE TABLE t_num; +Table Create Table +t_num CREATE TABLE `t_num` ( + `t_pk` int(11) NOT NULL, + `t_bit` bit(64) default NULL, + `t_tinyint` tinyint(4) default NULL, + `t_bool` tinyint(1) default NULL, + `t_smallint` smallint(6) default NULL, + `t_mediumint` mediumint(9) default NULL, + `t_int` int(11) default NULL, + `t_bigint` bigint(20) default NULL, + `t_float` float default NULL, + `t_double` double default NULL, + `t_decimal` decimal(37,16) default NULL, + PRIMARY KEY (`t_pk`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t_datetime; +Table Create Table +t_datetime CREATE TABLE `t_datetime` ( + `t_pk` int(11) NOT NULL, + `t_date` date default NULL, + `t_datetime` datetime default NULL, + `t_timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + `t_time` time default NULL, + `t_year` year(4) default NULL, + PRIMARY KEY (`t_pk`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t_string_1; +Table Create Table +t_string_1 CREATE TABLE `t_string_1` ( + `t_pk` int(11) NOT NULL, + `t_char` char(255) default NULL, + `t_varchar` varchar(655) default NULL, + `t_binary` binary(255) default NULL, + `t_varbinary` varbinary(6553) default NULL, + PRIMARY KEY (`t_pk`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t_string_2; +Table Create Table +t_string_2 CREATE TABLE `t_string_2` ( + `t_pk` int(11) NOT NULL, + `t_tinyblob` tinyblob, + `t_tinytext` tinytext, + `t_blob` blob, + `t_text` text, + `t_mediumblob` mediumblob, + `t_mediumtext` mediumtext, + `t_longblob` longblob, + `t_longtext` longtext, + `t_enum` enum('001001','001004','001010','001018','001019','001020','001021','001027','001028','001029','001030','001031','001100','002003','002004','002005','002007') NOT NULL default '001001', + `t_set` set('a','B') default NULL, + PRIMARY KEY (`t_pk`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t_gis; +Table Create Table +t_gis CREATE TABLE `t_gis` ( + `t_pk` int(11) NOT NULL, + `t_point` point default NULL, + `t_linestring` linestring default NULL, + `t_polygon` polygon default NULL, + `t_multipoint` multipoint default NULL, + `t_multilinestring` multilinestring default NULL, + `t_multipolygon` multipolygon default NULL, + `t_geometrycollection` geometrycollection default NULL, + `t_geometry` geometry default NULL, + PRIMARY KEY (`t_pk`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SELECT * FROM t_datetime; +t_pk t_date t_datetime t_timestamp t_time t_year +1 1998-01-01 2006-08-10 10:11:12 2002-10-29 16:51:06 19:38:34 2155 +SELECT t_pk,hex(t_bit),t_tinyint,t_bool,t_smallint,t_mediumint,t_int,t_bigint,t_float,t_double,t_decimal FROM t_num; +t_pk hex(t_bit) t_tinyint t_bool t_smallint t_mediumint t_int t_bigint t_float t_double t_decimal +1 AAAAAAAAAAAAAAAA 125 1 32765 8388606 2147483647 9223372036854775807 1e+20 1e+150 331.0000000000000000 +SELECT t_pk,t_char,t_varchar,hex(t_binary),hex(t_varbinary) FROM t_string_1; +t_pk t_char t_varchar hex(t_binary) hex(t_varbinary) +1 abcdefghijklmn abcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmn 612020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 4100 +SELECT * FROM t_string_2; +t_pk t_tinyblob t_tinytext t_blob t_text t_mediumblob t_mediumtext t_longblob t_longtext t_enum t_set +1 abcdefghijklmnabcdefghijklmn abcdefghijklmnabcdefghijklmn a123456789b123456789c123456789d123456789e123456789f123456789g123456789 a123456789b123456789c123456789d123456789e123456789f123456789g123456789 a123456789b123456789c123456789d123456789e123456789f123456789g123456789 a123456789b123456789c123456789d123456789e123456789f123456789g123456789 a123456789b123456789c123456789d123456789e123456789f123456789g123456789 a123456789b123456789c123456789d123456789e123456789f123456789g123456789 001001 a +SELECT AsText(t_point), AsText(t_linestring),AsText(t_polygon) FROM t_gis ORDER by t_pk; +AsText(t_point) AsText(t_linestring) AsText(t_polygon) +POINT(10 10) LINESTRING(10 10,20 10,20 20,10 20,10 10) POLYGON((0 0,50 0,50 50,0 50,0 0),(10 10,20 10,20 20,10 20,10 10)) +POINT(10 20) LINESTRING(10 10,40 10) POLYGON((0 0,30 0,30 30,0 0)) +SELECT AsText(t_multipoint), AsText(t_multilinestring),AsText(t_multipolygon) FROM t_gis ORDER by t_pk; +AsText(t_multipoint) AsText(t_multilinestring) AsText(t_multipolygon) +MULTIPOINT(1 1,11 11,11 21,21 21) MULTILINESTRING((10 48,10 21,10 0)) MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18))) +MULTIPOINT(3 6,4 10) MULTILINESTRING((1 2,3 5),(2 5,5 8,21 7)) MULTIPOLYGON(((0 3,3 3,3 0,0 3))) +SELECT AsText(t_geometrycollection), AsText(t_geometry) FROM t_gis ORDER by t_pk; +AsText(t_geometrycollection) AsText(t_geometry) +GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10)) MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18))) +GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9)) GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9)) +DROP TABLE t_num,t_datetime,t_string_1,t_string_2,t_gis; +SHOW TABLES; +Tables_in_test +t_gis +t_string_1 +t_num +t_string_2 +t_datetime +SHOW CREATE TABLE t_num; +Table Create Table +t_num CREATE TABLE `t_num` ( + `t_pk` int(11) NOT NULL, + `t_bit` bit(64) default NULL, + `t_tinyint` tinyint(4) default NULL, + `t_bool` tinyint(1) default NULL, + `t_smallint` smallint(6) default NULL, + `t_mediumint` mediumint(9) default NULL, + `t_int` int(11) default NULL, + `t_bigint` bigint(20) default NULL, + `t_float` float default NULL, + `t_double` double default NULL, + `t_decimal` decimal(37,16) default NULL, + PRIMARY KEY (`t_pk`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t_datetime; +Table Create Table +t_datetime CREATE TABLE `t_datetime` ( + `t_pk` int(11) NOT NULL, + `t_date` date default NULL, + `t_datetime` datetime default NULL, + `t_timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + `t_time` time default NULL, + `t_year` year(4) default NULL, + PRIMARY KEY (`t_pk`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t_string_1; +Table Create Table +t_string_1 CREATE TABLE `t_string_1` ( + `t_pk` int(11) NOT NULL, + `t_char` char(255) default NULL, + `t_varchar` varchar(655) default NULL, + `t_binary` binary(255) default NULL, + `t_varbinary` varbinary(6553) default NULL, + PRIMARY KEY (`t_pk`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t_string_2; +Table Create Table +t_string_2 CREATE TABLE `t_string_2` ( + `t_pk` int(11) NOT NULL, + `t_tinyblob` tinyblob, + `t_tinytext` tinytext, + `t_blob` blob, + `t_text` text, + `t_mediumblob` mediumblob, + `t_mediumtext` mediumtext, + `t_longblob` longblob, + `t_longtext` longtext, + `t_enum` enum('001001','001004','001010','001018','001019','001020','001021','001027','001028','001029','001030','001031','001100','002003','002004','002005','002007') NOT NULL default '001001', + `t_set` set('a','B') default NULL, + PRIMARY KEY (`t_pk`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t_gis; +Table Create Table +t_gis CREATE TABLE `t_gis` ( + `t_pk` int(11) NOT NULL, + `t_point` point default NULL, + `t_linestring` linestring default NULL, + `t_polygon` polygon default NULL, + `t_multipoint` multipoint default NULL, + `t_multilinestring` multilinestring default NULL, + `t_multipolygon` multipolygon default NULL, + `t_geometrycollection` geometrycollection default NULL, + `t_geometry` geometry default NULL, + PRIMARY KEY (`t_pk`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SELECT * FROM t_datetime; +t_pk t_date t_datetime t_timestamp t_time t_year +1 1998-01-01 2006-08-10 10:11:12 2002-10-29 16:51:06 19:38:34 2155 +SELECT t_pk,hex(t_bit),t_tinyint,t_bool,t_smallint,t_mediumint,t_int,t_bigint,t_float,t_double,t_decimal FROM t_num; +t_pk hex(t_bit) t_tinyint t_bool t_smallint t_mediumint t_int t_bigint t_float t_double t_decimal +1 AAAAAAAAAAAAAAAA 125 1 32765 8388606 2147483647 9223372036854775807 1e+20 1e+150 331.0000000000000000 +SELECT t_pk,t_char,t_varchar,hex(t_binary),hex(t_varbinary) FROM t_string_1; +t_pk t_char t_varchar hex(t_binary) hex(t_varbinary) +1 abcdefghijklmn abcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmn 612020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 4100 +SELECT * FROM t_string_2; +t_pk t_tinyblob t_tinytext t_blob t_text t_mediumblob t_mediumtext t_longblob t_longtext t_enum t_set +1 abcdefghijklmnabcdefghijklmn abcdefghijklmnabcdefghijklmn a123456789b123456789c123456789d123456789e123456789f123456789g123456789 a123456789b123456789c123456789d123456789e123456789f123456789g123456789 a123456789b123456789c123456789d123456789e123456789f123456789g123456789 a123456789b123456789c123456789d123456789e123456789f123456789g123456789 a123456789b123456789c123456789d123456789e123456789f123456789g123456789 a123456789b123456789c123456789d123456789e123456789f123456789g123456789 001001 a +SELECT AsText(t_point), AsText(t_linestring),AsText(t_polygon) FROM t_gis ORDER by t_pk; +AsText(t_point) AsText(t_linestring) AsText(t_polygon) +POINT(10 10) LINESTRING(10 10,20 10,20 20,10 20,10 10) POLYGON((0 0,50 0,50 50,0 50,0 0),(10 10,20 10,20 20,10 20,10 10)) +POINT(10 20) LINESTRING(10 10,40 10) POLYGON((0 0,30 0,30 30,0 0)) +SELECT AsText(t_multipoint), AsText(t_multilinestring),AsText(t_multipolygon) FROM t_gis ORDER by t_pk; +AsText(t_multipoint) AsText(t_multilinestring) AsText(t_multipolygon) +MULTIPOINT(1 1,11 11,11 21,21 21) MULTILINESTRING((10 48,10 21,10 0)) MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18))) +MULTIPOINT(3 6,4 10) MULTILINESTRING((1 2,3 5),(2 5,5 8,21 7)) MULTIPOLYGON(((0 3,3 3,3 0,0 3))) +SELECT AsText(t_geometrycollection), AsText(t_geometry) FROM t_gis ORDER by t_pk; +AsText(t_geometrycollection) AsText(t_geometry) +GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10)) MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18))) +GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9)) GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9)) +DROP TABLE t_num,t_datetime,t_string_1,t_string_2,t_gis; 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.result b/mysql-test/r/sp.result index 2cfbe7aadcb..1e3c4de0fcf 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -6315,4 +6315,78 @@ CALL p1(); NULL SET NAMES default; DROP PROCEDURE p1; +create function f1() +returns int(11) +not deterministic +contains sql +sql security definer +comment '' +begin +declare x int(11); +set x=-1; +return x; +end| +create view v1 as select 1 as one, f1() as days; +show create view test.v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `test`.`v1` AS select 1 AS `one`,`f1`() AS `days` +select column_name from information_schema.columns +where table_name='v1' and table_schema='test'; +column_name +one +days +drop view v1; +drop function f1; + +# 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 adjusted 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/r/status.result b/mysql-test/r/status.result index ca21b333a6a..36857e22aaf 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -43,3 +43,51 @@ SHOW STATUS LIKE 'max_used_connections'; Variable_name Value Max_used_connections 4 SET GLOBAL thread_cache_size=@save_thread_cache_size; +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (1), (2); +SELECT a FROM t1 LIMIT 1; +a +1 +SHOW SESSION STATUS LIKE 'Last_query_cost'; +Variable_name Value +Last_query_cost 2.402418 +EXPLAIN SELECT a FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +SHOW SESSION STATUS LIKE 'Last_query_cost'; +Variable_name Value +Last_query_cost 2.402418 +SELECT a FROM t1 UNION SELECT a FROM t1 ORDER BY a; +a +1 +2 +SHOW SESSION STATUS LIKE 'Last_query_cost'; +Variable_name Value +Last_query_cost 0.000000 +EXPLAIN SELECT a FROM t1 UNION SELECT a FROM t1 ORDER BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 +2 UNION t1 ALL NULL NULL NULL NULL 2 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL Using filesort +SHOW SESSION STATUS LIKE 'Last_query_cost'; +Variable_name Value +Last_query_cost 0.000000 +SELECT a IN (SELECT a FROM t1) FROM t1 LIMIT 1; +a IN (SELECT a FROM t1) +1 +SHOW SESSION STATUS LIKE 'Last_query_cost'; +Variable_name Value +Last_query_cost 0.000000 +SELECT (SELECT a FROM t1 LIMIT 1) x FROM t1 LIMIT 1; +x +1 +SHOW SESSION STATUS LIKE 'Last_query_cost'; +Variable_name Value +Last_query_cost 0.000000 +SELECT * FROM t1 a, t1 b LIMIT 1; +a a +1 1 +SHOW SESSION STATUS LIKE 'Last_query_cost'; +Variable_name Value +Last_query_cost 4.805836 +DROP TABLE t1; diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result index 7c765d6d50b..5356f7e0712 100644 --- a/mysql-test/r/type_bit.result +++ b/mysql-test/r/type_bit.result @@ -642,4 +642,19 @@ b+0 COUNT(DISTINCT a) 1 1 3 2 DROP TABLE t1; +CREATE TABLE t1 (b BIT); +INSERT INTO t1 (b) VALUES (1), (0); +SELECT DISTINCT b FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 b b 16 1 1 Y 32 0 63 +b +# +# +SELECT b FROM t1 GROUP BY b; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 b b 16 1 1 Y 32 0 63 +b +# +# +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1-0.1.Data b/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1-0.1.Data new file mode 100644 index 00000000000..90a8443cf45 Binary files /dev/null and b/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1-0.1.Data differ diff --git a/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1-0.2.Data b/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1-0.2.Data new file mode 100644 index 00000000000..763333c9b1a Binary files /dev/null and b/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1-0.2.Data differ diff --git a/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1.1.ctl b/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1.1.ctl new file mode 100644 index 00000000000..8849978e293 Binary files /dev/null and b/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1.1.ctl differ diff --git a/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1.1.log b/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1.1.log new file mode 100644 index 00000000000..780753239e1 Binary files /dev/null and b/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1.1.log differ diff --git a/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1.2.ctl b/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1.2.ctl new file mode 100644 index 00000000000..8849978e293 Binary files /dev/null and b/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1.2.ctl differ diff --git a/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1.2.log b/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1.2.log new file mode 100644 index 00000000000..780753239e1 Binary files /dev/null and b/mysql-test/std_data/ndb_backup50_data_be/BACKUP-1.2.log differ diff --git a/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1-0.1.Data b/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1-0.1.Data new file mode 100644 index 00000000000..157c28b67b3 Binary files /dev/null and b/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1-0.1.Data differ diff --git a/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1-0.2.Data b/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1-0.2.Data new file mode 100644 index 00000000000..e7602c89db7 Binary files /dev/null and b/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1-0.2.Data differ diff --git a/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1.1.ctl b/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1.1.ctl new file mode 100644 index 00000000000..e2b8f4977ed Binary files /dev/null and b/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1.1.ctl differ diff --git a/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1.1.log b/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1.1.log new file mode 100644 index 00000000000..c8037dd453a Binary files /dev/null and b/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1.1.log differ diff --git a/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1.2.ctl b/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1.2.ctl new file mode 100644 index 00000000000..e2b8f4977ed Binary files /dev/null and b/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1.2.ctl differ diff --git a/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1.2.log b/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1.2.log new file mode 100644 index 00000000000..c8037dd453a Binary files /dev/null and b/mysql-test/std_data/ndb_backup50_data_le/BACKUP-1.2.log differ diff --git a/mysql-test/t/comments.test b/mysql-test/t/comments.test index 52273ec9523..0c6853cf298 100644 --- a/mysql-test/t/comments.test +++ b/mysql-test/t/comments.test @@ -19,3 +19,36 @@ select 1 # The rest of the row will be ignored /* line with only comment */; # End of 4.1 tests + + +# +# 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/delete.test b/mysql-test/t/delete.test index 36d627209db..8a03cb6c715 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -173,8 +173,20 @@ delete from t1 where (@a:= f1) order by f1 limit 1; select @a; drop table t1; +# BUG#30385 "Server crash when deleting with order by and limit" +CREATE TABLE t1 ( + `date` date , + `time` time , + `seq` int(10) unsigned NOT NULL auto_increment, + PRIMARY KEY (`seq`), + KEY `seq` (`seq`), + KEY `time` (`time`), + KEY `date` (`date`) +); +DELETE FROM t1 ORDER BY date ASC, time ASC LIMIT 1; +drop table t1; + --echo End of 4.1 tests -# End of 4.1 tests # # Test of multi-delete where we are not scanning the first table @@ -221,3 +233,47 @@ DELETE FROM t1 ORDER BY t2.x; DELETE FROM t1 ORDER BY (SELECT x); DROP TABLE t1; + +# +# Bug #30234: Unexpected behavior using DELETE with AS and USING +# ' +CREATE TABLE t1 ( + a INT +); + +CREATE TABLE t2 ( + a INT +); + +CREATE DATABASE db1; +CREATE TABLE db1.t1 ( + a INT +); +INSERT INTO db1.t1 (a) SELECT * FROM t1; + +CREATE DATABASE db2; +CREATE TABLE db2.t1 ( + a INT +); +INSERT INTO db2.t1 (a) SELECT * FROM t2; + +--error ER_PARSE_ERROR +DELETE FROM t1 alias USING t1, t2 alias WHERE t1.a = alias.a; +DELETE FROM alias USING t1, t2 alias WHERE t1.a = alias.a; +DELETE FROM t1, alias USING t1, t2 alias WHERE t1.a = alias.a; +--error ER_UNKNOWN_TABLE +DELETE FROM t1, t2 USING t1, t2 alias WHERE t1.a = alias.a; +--error ER_PARSE_ERROR +DELETE FROM db1.t1 alias USING db1.t1, db2.t1 alias WHERE db1.t1.a = alias.a; +--error ER_UNKNOWN_TABLE +DELETE FROM alias USING db1.t1, db2.t1 alias WHERE db1.t1.a = alias.a; +DELETE FROM db2.alias USING db1.t1, db2.t1 alias WHERE db1.t1.a = alias.a; +DELETE FROM t1 USING t1 WHERE a = 1; +SELECT * FROM t1; +--error ER_PARSE_ERROR +DELETE FROM t1 alias USING t1 alias WHERE a = 2; +SELECT * FROM t1; + +DROP TABLE t1, t2; +DROP DATABASE db1; +DROP DATABASE db2; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 91e69f9db34..b7c28cada46 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -788,3 +788,30 @@ select * from t1 group by f1, f2; select t1.f1,t.* from t1, t1 t group by 1; drop table t1; SET SQL_MODE = ''; + +# +# Bug#30596: GROUP BY optimization gives wrong result order +# +CREATE TABLE t1( + a INT, + b INT NOT NULL, + c INT NOT NULL, + d INT, + UNIQUE KEY (c,b) +); + +INSERT INTO t1 VALUES (1,1,1,50), (1,2,3,40), (2,1,3,4); + +EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b,d; +SELECT c,b,d FROM t1 GROUP BY c,b,d; +EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b,d ORDER BY NULL; +SELECT c,b,d FROM t1 GROUP BY c,b,d ORDER BY NULL; +EXPLAIN SELECT c,b,d FROM t1 ORDER BY c,b,d; +SELECT c,b,d FROM t1 ORDER BY c,b,d; + +EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b; +SELECT c,b,d FROM t1 GROUP BY c,b; +EXPLAIN SELECT c,b FROM t1 GROUP BY c,b; +SELECT c,b FROM t1 GROUP BY c,b; + +DROP TABLE t1; diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index 4edd5b5ec32..6ef216f6ed2 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -441,3 +441,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/t/innodb-deadlock.test b/mysql-test/t/innodb-deadlock.test index 81acfba5c93..1a184f98771 100644 --- a/mysql-test/t/innodb-deadlock.test +++ b/mysql-test/t/innodb-deadlock.test @@ -112,4 +112,29 @@ commit; 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/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index aecefda93d3..c39c88096c4 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -910,4 +910,31 @@ ROLLBACK; ROLLBACK; DROP TABLE t1; +# +# Bug#30596: GROUP BY optimization gives wrong result order +# +CREATE TABLE t1( + a INT, + b INT NOT NULL, + c INT NOT NULL, + d INT, + UNIQUE KEY (c,b) +) engine=innodb; + +INSERT INTO t1 VALUES (1,1,1,50), (1,2,3,40), (2,1,3,4); + +EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b,d; +SELECT c,b,d FROM t1 GROUP BY c,b,d; +EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b,d ORDER BY NULL; +SELECT c,b,d FROM t1 GROUP BY c,b,d ORDER BY NULL; +EXPLAIN SELECT c,b,d FROM t1 ORDER BY c,b,d; +SELECT c,b,d FROM t1 ORDER BY c,b,d; + +EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b; +SELECT c,b,d FROM t1 GROUP BY c,b; +EXPLAIN SELECT c,b FROM t1 GROUP BY c,b; +SELECT c,b FROM t1 GROUP BY c,b; + +DROP TABLE t1; + --echo End of 5.0 tests diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 66bd2f67512..6e97d0faede 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -276,4 +276,9 @@ remove_file $MYSQLTEST_VARDIR/tmp/bug21412.sql; --exec $MYSQL --pager="540bytelengthstringxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -e "select 1" > /dev/null 2>&1 --exec $MYSQL --character-sets-dir="540bytelengthstringxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -e "select 1" 2>&1 +# +# bug #30164: Using client side macro inside server side comments generates broken queries +# +--exec $MYSQL test -e "/*! \C latin1 */ select 1;" + --echo End of 5.0 tests diff --git a/mysql-test/t/mysqldump-compat.opt b/mysql-test/t/mysqldump-compat.opt new file mode 100644 index 00000000000..40d4ac738a6 --- /dev/null +++ b/mysql-test/t/mysqldump-compat.opt @@ -0,0 +1 @@ +--loose-debug=d,4x_server_emul diff --git a/mysql-test/t/mysqldump-compat.test b/mysql-test/t/mysqldump-compat.test new file mode 100644 index 00000000000..848d66cc728 --- /dev/null +++ b/mysql-test/t/mysqldump-compat.test @@ -0,0 +1,13 @@ +# Embedded server doesn't support external clients +--source include/not_embedded.inc + +# +# Bug #30126: semicolon before closing */ in /*!... CREATE DATABASE ;*/ +# + +CREATE DATABASE mysqldump_30126; +USE mysqldump_30126; +CREATE TABLE t1 (c1 int); +--exec $MYSQL_DUMP --add-drop-database mysqldump_30126 > $MYSQLTEST_VARDIR/tmp/bug30126.sql +--exec $MYSQL mysqldump_30126 < $MYSQLTEST_VARDIR/tmp/bug30126.sql +DROP DATABASE mysqldump_30126; diff --git a/mysql-test/t/ndb_bug26793.test b/mysql-test/t/ndb_bug26793.test new file mode 100644 index 00000000000..f35d8808c1a --- /dev/null +++ b/mysql-test/t/ndb_bug26793.test @@ -0,0 +1,35 @@ +-- source include/have_ndb.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE `test` ( +`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , +`t` VARCHAR( 10 ) NOT NULL +) ENGINE = ndbcluster; + +# Add user1@localhost with a specific password +# and connect as that user +GRANT USAGE ON *.* TO user1@localhost IDENTIFIED BY 'pass'; +connect (user1,localhost,user1,pass,*NO-ONE*); + +# Run the query 100 times +disable_query_log; +disable_result_log; +let $i= 100; +while ($i) +{ +select count(*) from information_schema.tables union all select count(*) from information_schema.tables union all select count(*) from information_schema.tables; +dec $i; +} +enable_query_log; +enable_result_log; + +disconnect user1; + +# Switch back to the default connection and cleanup +connection default; +DROP TABLE `test`.`test`; +drop user user1@localhost; + diff --git a/mysql-test/t/ndb_read_multi_range.test b/mysql-test/t/ndb_read_multi_range.test index e1f1dfc1150..1d1d5f26552 100644 --- a/mysql-test/t/ndb_read_multi_range.test +++ b/mysql-test/t/ndb_read_multi_range.test @@ -291,3 +291,25 @@ insert into t2 values (1,1), (10,10); select * from t2 use index (ab) where a in(1,10) order by a; drop table t2; + +#bug#30337 + +create table t1 (id int primary key) engine ndb; +insert into t1 values (1), (2), (3); + +create table t2 (id int primary key) engine ndb; +insert into t2 select id from t1; + +delimiter |; +create trigger kaboom after delete on t1 +for each row begin + delete from t2 where id=old.id; +end| +delimiter ;| + +select * from t1 order by id; +delete from t1 where id in (1,2); +select * from t2 order by id; + +drop trigger kaboom; +drop table t1; diff --git a/mysql-test/t/ndb_restore_different_endian_data.test b/mysql-test/t/ndb_restore_different_endian_data.test new file mode 100644 index 00000000000..208ab8b459d --- /dev/null +++ b/mysql-test/t/ndb_restore_different_endian_data.test @@ -0,0 +1,185 @@ +-- source include/have_ndb.inc +-- source include/ndb_default_cluster.inc +-- source include/not_embedded.inc + +# +# Bug #27543 restore of backup from different endian does not work for blob column +# Bug #30024 restore of backup from different endian does not work for datetime column +# Bug #28674 backup will run forever if disk full and later write succes will kill ndb node +# +# The table structure and data list below +# +# CREATE TABLE t_num ( +# t_pk INT PRIMARY KEY, +# t_bit BIT(64), +# t_tinyint TINYINT, +# t_bool BOOL, +# t_smallint SMALLINT, +# t_mediumint MEDIUMINT, +# t_int INT, +# t_bigint BIGINT, +# t_float FLOAT, +# t_double DOUBLE, +# t_decimal DECIMAL (37, 16) +# ) ENGINE=NDBCLUSTER; +# +# INSERT INTO t_num VALUE ( +# 1, +# b'1010101010101010101010101010101010101010101010101010101010101010', +# 125, +# 1, +# 32765, +# 8388606, +# 2147483647, +# 9223372036854775807, +# 1e+20, +# 1e+150, +# '331.0000000000' +# ); +# +# CREATE TABLE t_datetime ( +# t_pk INT PRIMARY KEY, +# t_date DATE, +# t_datetime DATETIME, +# t_timestamp TIMESTAMP, +# t_time TIME, +# t_year YEAR +# ) ENGINE=NDBCLUSTER; +# +# INSERT INTO t_datetime VALUE ( +# 1, +# '1998-01-01', +# '2006-08-10 10:11:12', +# 20021029165106, +# '19:38:34', +# 2155 +# ); +# +# CREATE TABLE t_string_1 ( +# t_pk INT PRIMARY KEY, +# t_char CHAR(255), +# t_varchar VARCHAR(655), +# t_binary BINARY(255), +# t_varbinary VARBINARY(6553) +# ) ENGINE=NDBCLUSTER; +# +# CREATE TABLE t_string_2 ( +# t_pk INT PRIMARY KEY, +# t_tinyblob TINYBLOB, +# t_tinytext TINYTEXT, +# t_blob BLOB, +# t_text TEXT, +# t_mediumblob MEDIUMBLOB, +# t_mediumtext MEDIUMTEXT, +# t_longblob LONGBLOB, +# t_longtext LONGTEXT, +# t_enum ENUM('001001','001004','001010','001018','001019','001020','001021','001027','001028','001029','001030','001031','001100','002003','002004','002005','002007')DEFAULT '001001' NOT NULL, +# t_set SET('a','B') +# ) ENGINE=NDBCLUSTER; +# +# INSERT INTO t_string_1 VALUE ( +# 1, +# 'abcdefghijklmn', +# 'abcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmn', +# 0x612020, +# 0x4100 +# ); +# +# INSERT INTO t_string_2 VALUE ( +# 1, +# 'abcdefghijklmnabcdefghijklmn', +# 'abcdefghijklmnabcdefghijklmn', +# 'a123456789b123456789c123456789d123456789e123456789f123456789g123456789', +# 'a123456789b123456789c123456789d123456789e123456789f123456789g123456789', +# 'a123456789b123456789c123456789d123456789e123456789f123456789g123456789', +# 'a123456789b123456789c123456789d123456789e123456789f123456789g123456789', +# 'a123456789b123456789c123456789d123456789e123456789f123456789g123456789', +# 'a123456789b123456789c123456789d123456789e123456789f123456789g123456789', +# '001001', +# 'a' +# ); +# +# CREATE TABLE t_gis ( +# t_pk INT PRIMARY KEY, +# t_point POINT, +# t_linestring LINESTRING, +# t_polygon POLYGON, +# t_multipoint MULTIPOINT, +# t_multilinestring MULTILINESTRING, +# t_multipolygon MULTIPOLYGON, +# t_geometrycollection GEOMETRYCOLLECTION, +# t_geometry GEOMETRY +# ) ENGINE=NDBCLUSTER; +# +# INSERT INTO t_gis VALUE ( +# 1, +# PointFromText('POINT(10 10)'), +# LineStringFromText('LINESTRING(10 10,20 10,20 20,10 20,10 10)'), +# PolyFromText('POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10 20,10 10))'), +# MPointFromText('MULTIPOINT(1 1,11 11,11 21,21 21)'), +# MLineFromText('MULTILINESTRING((10 48,10 21,10 0))'), +# MPolyFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))'), +# GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))'), +# MPolyFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))') +# ); +# +# INSERT INTO t_gis VALUE ( +# 2, +# PointFromWKB(AsWKB(PointFromText('POINT(10 20)'))), +# LineStringFromWKB(LineString(Point(10, 10), Point(40, 10))), +# PolyFromWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0)))), +# MPointFromWKB(MultiPoint(Point(3, 6), Point(4, 10))), +# MLineFromWKB(MultiLineString(LineString(Point(1, 2), Point(3, 5)), LineString(Point(2, 5), Point(5, 8), Point(21, 7)))), +# MPolyFromWKB(MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3))))), +# GeometryFromWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))), +# GeometryFromWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))) +# ); + + + +# +# Restore backup files (from little endian) +# + +--disable_warnings +USE test; +DROP TABLE IF EXISTS t_num,t_datetime,t_string_1,t_string_2,t_gis; +--enable_warnings +--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults -b 1 -n 1 -m -r $MYSQL_TEST_DIR/std_data/ndb_backup50_data_le >> $NDB_TOOLS_OUTPUT +--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults -b 1 -n 2 -r $MYSQL_TEST_DIR/std_data/ndb_backup50_data_le >> $NDB_TOOLS_OUTPUT +SHOW TABLES; +SHOW CREATE TABLE t_num; +SHOW CREATE TABLE t_datetime; +SHOW CREATE TABLE t_string_1; +SHOW CREATE TABLE t_string_2; +SHOW CREATE TABLE t_gis; +SELECT * FROM t_datetime; +SELECT t_pk,hex(t_bit),t_tinyint,t_bool,t_smallint,t_mediumint,t_int,t_bigint,t_float,t_double,t_decimal FROM t_num; +SELECT t_pk,t_char,t_varchar,hex(t_binary),hex(t_varbinary) FROM t_string_1; +SELECT * FROM t_string_2; +SELECT AsText(t_point), AsText(t_linestring),AsText(t_polygon) FROM t_gis ORDER by t_pk; +SELECT AsText(t_multipoint), AsText(t_multilinestring),AsText(t_multipolygon) FROM t_gis ORDER by t_pk; +SELECT AsText(t_geometrycollection), AsText(t_geometry) FROM t_gis ORDER by t_pk; + +# +# Restore backup files (from big endian) +# + +DROP TABLE t_num,t_datetime,t_string_1,t_string_2,t_gis; +--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults -b 1 -n 1 -m -r $MYSQL_TEST_DIR/std_data/ndb_backup50_data_be >> $NDB_TOOLS_OUTPUT +--exec $NDB_TOOLS_DIR/ndb_restore --no-defaults -b 1 -n 2 -r $MYSQL_TEST_DIR/std_data/ndb_backup50_data_be >> $NDB_TOOLS_OUTPUT +SHOW TABLES; +SHOW CREATE TABLE t_num; +SHOW CREATE TABLE t_datetime; +SHOW CREATE TABLE t_string_1; +SHOW CREATE TABLE t_string_2; +SHOW CREATE TABLE t_gis; +SELECT * FROM t_datetime; +SELECT t_pk,hex(t_bit),t_tinyint,t_bool,t_smallint,t_mediumint,t_int,t_bigint,t_float,t_double,t_decimal FROM t_num; +SELECT t_pk,t_char,t_varchar,hex(t_binary),hex(t_varbinary) FROM t_string_1; +SELECT * FROM t_string_2; +SELECT AsText(t_point), AsText(t_linestring),AsText(t_polygon) FROM t_gis ORDER by t_pk; +SELECT AsText(t_multipoint), AsText(t_multilinestring),AsText(t_multipolygon) FROM t_gis ORDER by t_pk; +SELECT AsText(t_geometrycollection), AsText(t_geometry) FROM t_gis ORDER by t_pk; + +DROP TABLE t_num,t_datetime,t_string_1,t_string_2,t_gis; 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.test b/mysql-test/t/sp.test index 0b3dd89f3fa..9e0ca965b95 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -7300,4 +7300,91 @@ CALL p1(); SET NAMES default; DROP PROCEDURE p1; +# +# Bug#29408 Cannot find view in columns table if the selection contains a function +# +delimiter |; + +create function f1() + returns int(11) +not deterministic +contains sql +sql security definer +comment '' +begin + declare x int(11); + set x=-1; + return x; +end| + +delimiter ;| + +create view v1 as select 1 as one, f1() as days; + +connect (bug29408, localhost, root,,*NO-ONE*); +connection bug29408; + +show create view test.v1; +select column_name from information_schema.columns +where table_name='v1' and table_schema='test'; + +connection default; +disconnect bug29408; +drop view v1; +drop function f1; + +# +# 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/mysql-test/t/status.test b/mysql-test/t/status.test index 6fcb82e160d..33bba3a626a 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -139,4 +139,36 @@ disconnect con3; disconnect con2; disconnect con1; + +# +# Bug #30377: EXPLAIN loses last_query_cost when used with UNION +# + +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (1), (2); + +SELECT a FROM t1 LIMIT 1; +SHOW SESSION STATUS LIKE 'Last_query_cost'; + +EXPLAIN SELECT a FROM t1; +SHOW SESSION STATUS LIKE 'Last_query_cost'; + +SELECT a FROM t1 UNION SELECT a FROM t1 ORDER BY a; +SHOW SESSION STATUS LIKE 'Last_query_cost'; + +EXPLAIN SELECT a FROM t1 UNION SELECT a FROM t1 ORDER BY a; +SHOW SESSION STATUS LIKE 'Last_query_cost'; + +SELECT a IN (SELECT a FROM t1) FROM t1 LIMIT 1; +SHOW SESSION STATUS LIKE 'Last_query_cost'; + +SELECT (SELECT a FROM t1 LIMIT 1) x FROM t1 LIMIT 1; +SHOW SESSION STATUS LIKE 'Last_query_cost'; + +SELECT * FROM t1 a, t1 b LIMIT 1; +SHOW SESSION STATUS LIKE 'Last_query_cost'; + +DROP TABLE t1; + + # End of 5.0 tests diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test index 6423d017afb..66538f59c6f 100644 --- a/mysql-test/t/type_bit.test +++ b/mysql-test/t/type_bit.test @@ -291,4 +291,17 @@ INSERT INTO t1 (b, a) VALUES (1, 1), (3, 2), (0, 3), (3, 4); SELECT b+0, COUNT(DISTINCT a) FROM t1 GROUP BY b; DROP TABLE t1; +# +# Bug#30245: A wrong type of a BIT field is reported when grouped by it. +# +CREATE TABLE t1 (b BIT); +INSERT INTO t1 (b) VALUES (1), (0); +--enable_metadata +--replace_column 1 # +SELECT DISTINCT b FROM t1; +--replace_column 1 # +SELECT b FROM t1 GROUP BY b; +--disable_metadata +DROP TABLE t1; + --echo End of 5.0 tests diff --git a/ndb/src/kernel/blocks/ERROR_codes.txt b/ndb/src/kernel/blocks/ERROR_codes.txt index 17f2c35624a..e45c608b601 100644 --- a/ndb/src/kernel/blocks/ERROR_codes.txt +++ b/ndb/src/kernel/blocks/ERROR_codes.txt @@ -6,7 +6,7 @@ Next DBTUP 4014 Next DBLQH 5043 Next DBDICT 6007 Next DBDIH 7183 -Next DBTC 8039 +Next DBTC 8052 Next CMVMI 9000 Next BACKUP 10022 Next DBUTIL 11002 @@ -296,6 +296,10 @@ ABORT OF TCKEYREQ 8038 : Simulate API disconnect just after SCAN_TAB_REQ +8039 : Simulate failure of TransactionBufferMemory allocation for OI lookup + +8051 : Simulate failure of allocation for saveINDXKEYINFO + CMVMI ----- diff --git a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp index 6934de76ad3..710d2fde182 100644 --- a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp +++ b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp @@ -1497,12 +1497,12 @@ private: void clearCommitAckMarker(ApiConnectRecord * const regApiPtr, TcConnectRecord * const regTcPtr); // Trigger and index handling - bool saveINDXKEYINFO(Signal* signal, - TcIndexOperation* indexOp, - const Uint32 *src, - Uint32 len); + int saveINDXKEYINFO(Signal* signal, + TcIndexOperation* indexOp, + const Uint32 *src, + Uint32 len); bool receivedAllINDXKEYINFO(TcIndexOperation* indexOp); - bool saveINDXATTRINFO(Signal* signal, + int saveINDXATTRINFO(Signal* signal, TcIndexOperation* indexOp, const Uint32 *src, Uint32 len); diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index e2df1249661..60024e82978 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -1789,9 +1789,18 @@ start_failure: }//switch } +static +inline +bool +compare_transid(Uint32* val0, Uint32* val1) +{ + Uint32 tmp0 = val0[0] ^ val1[0]; + Uint32 tmp1 = val0[1] ^ val1[1]; + return (tmp0 | tmp1) == 0; +} + void Dbtc::execKEYINFO(Signal* signal) { - UintR compare_transid1, compare_transid2; jamEntry(); apiConnectptr.i = signal->theData[0]; tmaxData = 20; @@ -1801,10 +1810,8 @@ void Dbtc::execKEYINFO(Signal* signal) }//if ptrAss(apiConnectptr, apiConnectRecord); ttransid_ptr = 1; - compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[1]; - compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[2]; - compare_transid1 = compare_transid1 | compare_transid2; - if (compare_transid1 != 0) { + if (compare_transid(apiConnectptr.p->transid, signal->theData+1) == false) + { TCKEY_abort(signal, 19); return; }//if @@ -2105,7 +2112,6 @@ void Dbtc::saveAttrbuf(Signal* signal) void Dbtc::execATTRINFO(Signal* signal) { - UintR compare_transid1, compare_transid2; UintR Tdata1 = signal->theData[0]; UintR Tlength = signal->length(); UintR TapiConnectFilesize = capiConnectFilesize; @@ -2120,17 +2126,13 @@ void Dbtc::execATTRINFO(Signal* signal) return; }//if - UintR Tdata2 = signal->theData[1]; - UintR Tdata3 = signal->theData[2]; ApiConnectRecord * const regApiPtr = &localApiConnectRecord[Tdata1]; - compare_transid1 = regApiPtr->transid[0] ^ Tdata2; - compare_transid2 = regApiPtr->transid[1] ^ Tdata3; apiConnectptr.p = regApiPtr; - compare_transid1 = compare_transid1 | compare_transid2; - if (compare_transid1 != 0) { + if (compare_transid(regApiPtr->transid, signal->theData+1) == false) + { DEBUG("Drop ATTRINFO, wrong transid, lenght="<theData[1]<<", "<theData[2]); TCKEY_abort(signal, 19); return; }//if @@ -5456,11 +5458,32 @@ void Dbtc::execTC_COMMITREQ(Signal* signal) } }//Dbtc::execTC_COMMITREQ() +/** + * TCROLLBACKREQ + * + * Format is: + * + * thedata[0] = apiconnectptr + * thedata[1] = transid[0] + * thedata[2] = transid[1] + * OPTIONAL thedata[3] = flags + * + * Flags: + * 0x1 = potentiallyBad data from API (try not to assert) + */ void Dbtc::execTCROLLBACKREQ(Signal* signal) { + bool potentiallyBad= false; UintR compare_transid1, compare_transid2; jamEntry(); + + if(unlikely((signal->getLength() >= 4) && (signal->theData[3] & 0x1))) + { + ndbout_c("Trying to roll back potentially bad txn\n"); + potentiallyBad= true; + } + apiConnectptr.i = signal->theData[0]; if (apiConnectptr.i >= capiConnectFilesize) { goto TC_ROLL_warning; @@ -5547,12 +5570,14 @@ void Dbtc::execTCROLLBACKREQ(Signal* signal) TC_ROLL_warning: jam(); - warningHandlerLab(signal, __LINE__); + if(likely(potentiallyBad==false)) + warningHandlerLab(signal, __LINE__); return; TC_ROLL_system_error: jam(); - systemErrorLab(signal, __LINE__); + if(likely(potentiallyBad==false)) + systemErrorLab(signal, __LINE__); return; }//Dbtc::execTCROLLBACKREQ() @@ -11559,6 +11584,7 @@ void Dbtc::execTCINDXREQ(Signal* signal) // This is a newly started transaction, clean-up releaseAllSeizedIndexOperations(regApiPtr); + regApiPtr->apiConnectstate = CS_STARTED; regApiPtr->transid[0] = tcIndxReq->transId1; regApiPtr->transid[1] = tcIndxReq->transId2; }//if @@ -11599,20 +11625,29 @@ void Dbtc::execTCINDXREQ(Signal* signal) Uint32 includedIndexLength = MIN(indexLength, indexBufSize); indexOp->expectedAttrInfo = attrLength; Uint32 includedAttrLength = MIN(attrLength, attrBufSize); - if (saveINDXKEYINFO(signal, - indexOp, - dataPtr, - includedIndexLength)) { + + int ret; + if ((ret = saveINDXKEYINFO(signal, + indexOp, + dataPtr, + includedIndexLength)) == 0) + { jam(); // We have received all we need readIndexTable(signal, regApiPtr, indexOp); return; } + else if (ret == -1) + { + jam(); + return; + } + dataPtr += includedIndexLength; if (saveINDXATTRINFO(signal, indexOp, dataPtr, - includedAttrLength)) { + includedAttrLength) == 0) { jam(); // We have received all we need readIndexTable(signal, regApiPtr, indexOp); @@ -11715,13 +11750,25 @@ void Dbtc::execINDXKEYINFO(Signal* signal) TcIndexOperationPtr indexOpPtr; TcIndexOperation* indexOp; + if (compare_transid(regApiPtr->transid, indxKeyInfo->transId) == false) + { + TCKEY_abort(signal, 19); + return; + } + + if (regApiPtr->apiConnectstate == CS_ABORTING) + { + jam(); + return; + } + if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL) { indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i); if (saveINDXKEYINFO(signal, indexOp, src, - keyInfoLength)) { + keyInfoLength) == 0) { jam(); // We have received all we need readIndexTable(signal, regApiPtr, indexOp); @@ -11748,17 +11795,31 @@ void Dbtc::execINDXATTRINFO(Signal* signal) TcIndexOperationPtr indexOpPtr; TcIndexOperation* indexOp; + if (compare_transid(regApiPtr->transid, indxAttrInfo->transId) == false) + { + TCKEY_abort(signal, 19); + return; + } + + if (regApiPtr->apiConnectstate == CS_ABORTING) + { + jam(); + return; + } + if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL) { indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i); if (saveINDXATTRINFO(signal, indexOp, src, - attrInfoLength)) { + attrInfoLength) == 0) { jam(); // We have received all we need readIndexTable(signal, regApiPtr, indexOp); + return; } + return; } } @@ -11766,12 +11827,13 @@ void Dbtc::execINDXATTRINFO(Signal* signal) * Save signal INDXKEYINFO * Return true if we have received all needed data */ -bool Dbtc::saveINDXKEYINFO(Signal* signal, - TcIndexOperation* indexOp, - const Uint32 *src, - Uint32 len) +int +Dbtc::saveINDXKEYINFO(Signal* signal, + TcIndexOperation* indexOp, + const Uint32 *src, + Uint32 len) { - if (!indexOp->keyInfo.append(src, len)) { + if (ERROR_INSERTED(8039) || !indexOp->keyInfo.append(src, len)) { jam(); // Failed to seize keyInfo, abort transaction #ifdef VM_TRACE @@ -11781,15 +11843,17 @@ bool Dbtc::saveINDXKEYINFO(Signal* signal, apiConnectptr.i = indexOp->connectionIndex; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); releaseIndexOperation(apiConnectptr.p, indexOp); - terrorCode = 4000; + terrorCode = 289; + if(TcKeyReq::getExecuteFlag(indexOp->tcIndxReq.requestInfo)) + apiConnectptr.p->m_exec_flag= 1; abortErrorLab(signal); - return false; + return -1; } if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) { jam(); - return true; + return 0; } - return false; + return 1; } bool Dbtc::receivedAllINDXKEYINFO(TcIndexOperation* indexOp) @@ -11801,12 +11865,13 @@ bool Dbtc::receivedAllINDXKEYINFO(TcIndexOperation* indexOp) * Save signal INDXATTRINFO * Return true if we have received all needed data */ -bool Dbtc::saveINDXATTRINFO(Signal* signal, - TcIndexOperation* indexOp, - const Uint32 *src, - Uint32 len) +int +Dbtc::saveINDXATTRINFO(Signal* signal, + TcIndexOperation* indexOp, + const Uint32 *src, + Uint32 len) { - if (!indexOp->attrInfo.append(src, len)) { + if (ERROR_INSERTED(8051) || !indexOp->attrInfo.append(src, len)) { jam(); #ifdef VM_TRACE ndbout_c("Dbtc::saveINDXATTRINFO: Failed to seize attrInfo\n"); @@ -11814,15 +11879,17 @@ bool Dbtc::saveINDXATTRINFO(Signal* signal, apiConnectptr.i = indexOp->connectionIndex; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); releaseIndexOperation(apiConnectptr.p, indexOp); - terrorCode = 4000; + terrorCode = 289; + if(TcKeyReq::getExecuteFlag(indexOp->tcIndxReq.requestInfo)) + apiConnectptr.p->m_exec_flag= 1; abortErrorLab(signal); - return false; + return -1; } if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) { jam(); - return true; + return 0; } - return false; + return 1; } bool Dbtc::receivedAllINDXATTRINFO(TcIndexOperation* indexOp) @@ -12006,6 +12073,9 @@ void Dbtc::execTCKEYREF(Signal* signal) tcIndxRef->transId[0] = tcKeyRef->transId[0]; tcIndxRef->transId[1] = tcKeyRef->transId[1]; tcIndxRef->errorCode = tcKeyRef->errorCode; + + releaseIndexOperation(regApiPtr, indexOp); + sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; @@ -12538,7 +12608,18 @@ void Dbtc::executeIndexOperation(Signal* signal, bool Dbtc::seizeIndexOperation(ApiConnectRecord* regApiPtr, TcIndexOperationPtr& indexOpPtr) { - return regApiPtr->theSeizedIndexOperations.seize(indexOpPtr); + if (regApiPtr->theSeizedIndexOperations.seize(indexOpPtr)) + { + ndbassert(indexOpPtr.p->expectedKeyInfo == 0); + ndbassert(indexOpPtr.p->keyInfo.getSize() == 0); + ndbassert(indexOpPtr.p->expectedAttrInfo == 0); + ndbassert(indexOpPtr.p->attrInfo.getSize() == 0); + ndbassert(indexOpPtr.p->expectedTransIdAI == 0); + ndbassert(indexOpPtr.p->transIdAI.getSize() == 0); + return true; + } + + return false; } void Dbtc::releaseIndexOperation(ApiConnectRecord* regApiPtr, diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp index 8abce4f9cc4..1036461d404 100644 --- a/ndb/src/mgmclient/CommandInterpreter.cpp +++ b/ndb/src/mgmclient/CommandInterpreter.cpp @@ -2148,7 +2148,7 @@ CommandInterpreter::executeRestart(Vector &command_list, return -1; } - if (!nostart) + if (nostart) ndbout_c("Shutting down nodes with \"-n, no start\" option, to subsequently start the nodes."); result= ndb_mgm_restart3(m_mgmsrv, no_of_nodes, node_ids, diff --git a/ndb/src/ndbapi/NdbBlob.cpp b/ndb/src/ndbapi/NdbBlob.cpp index 7ab9c2132d8..611d0396f96 100644 --- a/ndb/src/ndbapi/NdbBlob.cpp +++ b/ndb/src/ndbapi/NdbBlob.cpp @@ -892,7 +892,12 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count) while (n < count) { NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable); if (tOp == NULL || - tOp->committedRead() == -1 || + /* + * This was committedRead() before. However lock on main + * table tuple does not fully protect blob parts since DBTUP + * commits each tuple separately. + */ + tOp->readTuple() == -1 || setPartKeyValue(tOp, part + n) == -1 || tOp->getValue((Uint32)3, buf) == NULL) { setErrorCode(tOp); diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 3fed04de26d..bf0c02714db 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -1220,7 +1220,8 @@ indexTypeMapping[] = { int NdbDictInterface::parseTableInfo(NdbTableImpl ** ret, const Uint32 * data, Uint32 len, - bool fullyQualifiedNames) + bool fullyQualifiedNames, + bool hostByteOrder) { DBUG_ENTER("NdbDictInterface::parseTableInfo"); @@ -1379,13 +1380,19 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret, if(tableDesc.FragmentDataLen > 0) { - Uint32 replicaCount = tableDesc.FragmentData[0]; - Uint32 fragCount = tableDesc.FragmentData[1]; + Uint16 replicaCount = tableDesc.FragmentData[0]; + Uint16 fragCount = tableDesc.FragmentData[1]; + + if(hostByteOrder == false) + { + replicaCount = ((replicaCount & 0xFF00) >> 8) |((replicaCount & 0x00FF) << 8); + fragCount = ((fragCount & 0xFF00) >> 8) |((fragCount & 0x00FF) << 8); + } impl->m_replicaCount = replicaCount; impl->m_fragmentCount = fragCount; - for(i = 0; i<(fragCount*replicaCount); i++) + for(i = 0; i<(Uint32) (fragCount*replicaCount); i++) { if (impl->m_fragments.push_back(tableDesc.FragmentData[i+2])) { diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.hpp b/ndb/src/ndbapi/NdbDictionaryImpl.hpp index 819de921235..a8757b69472 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.hpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.hpp @@ -262,7 +262,8 @@ public: static int parseTableInfo(NdbTableImpl ** dst, const Uint32 * data, Uint32 len, - bool fullyQualifiedNames); + bool fullyQualifiedNames, + bool hostByteOrder = true); static int create_index_obj_from_table(NdbIndexImpl ** dst, NdbTableImpl* index_table, diff --git a/ndb/src/ndbapi/NdbTransaction.cpp b/ndb/src/ndbapi/NdbTransaction.cpp index f5076ff2020..1ebc5b7ef24 100644 --- a/ndb/src/ndbapi/NdbTransaction.cpp +++ b/ndb/src/ndbapi/NdbTransaction.cpp @@ -481,12 +481,27 @@ NdbTransaction::executeNoBlobs(ExecType aTypeOfExec, while (1) { int noOfComp = tNdb->sendPollNdb(3 * timeout, 1, forceSend); if (noOfComp == 0) { - /** - * This timeout situation can occur if NDB crashes. + /* + * Just for fun, this is only one of two places where + * we could hit this error... It's quite possible we + * hit it in Ndbif.cpp in Ndb::check_send_timeout() + * + * We behave rather similarly in both places. + * Hitting this is certainly a bug though... */ - ndbout << "This timeout should never occur, execute(..)" << endl; - theError.code = 4012; - setOperationErrorCodeAbort(4012); // Error code for "Cluster Failure" + g_eventLogger.error("WARNING: Timeout in executeNoBlobs() waiting for " + "response from NDB data nodes. This should NEVER " + "occur. You have likely hit a NDB Bug. Please " + "file a bug."); + DBUG_PRINT("error",("This timeout should never occure, execute()")); + g_eventLogger.error("Forcibly trying to rollback txn (%p" + ") to try to clean up data node resources.", + this); + executeNoBlobs(NdbTransaction::Rollback); + theError.code = 4012; + theError.status= NdbError::PermanentError; + theError.classification= NdbError::TimeoutExpired; + setOperationErrorCodeAbort(4012); // ndbd timeout DBUG_RETURN(-1); }//if @@ -550,7 +565,12 @@ NdbTransaction::executeAsynchPrepare( ExecType aTypeOfExec, */ if (theError.code != 0) DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code)); - theError.code = 0; + /** + * for timeout (4012) we want sendROLLBACK to behave differently. + * Else, normal behaviour of reset errcode + */ + if (theError.code != 4012) + theError.code = 0; NdbScanOperation* tcOp = m_theFirstScanOperation; if (tcOp != 0){ // Execute any cursor operations @@ -873,6 +893,12 @@ NdbTransaction::sendROLLBACK() // Send a TCROLLBACKREQ signal; tSignal.setData(theTCConPtr, 1); tSignal.setData(tTransId1, 2); tSignal.setData(tTransId2, 3); + if(theError.code == 4012) + { + g_eventLogger.error("Sending TCROLLBACKREQ with Bad flag"); + tSignal.setLength(tSignal.getLength() + 1); // + flags + tSignal.setData(0x1, 4); // potentially bad data + } tReturnCode = tp->sendSignal(&tSignal,theDBnode); if (tReturnCode != -1) { theSendStatus = sendTC_ROLLBACK; diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c index 328b0688857..24ccb1d07c2 100644 --- a/ndb/src/ndbapi/ndberror.c +++ b/ndb/src/ndbapi/ndberror.c @@ -173,6 +173,8 @@ ErrorBundle ErrorCodes[] = { { 4022, TR, "Out of Send Buffer space in NDB API" }, { 4032, TR, "Out of Send Buffer space in NDB API" }, { 288, TR, "Out of index operations in transaction coordinator (increase MaxNoOfConcurrentIndexOperations)" }, + { 289, TR, "Out of transaction buffer memory in TC (increase TransactionBufferMemory)" }, + /** * InsufficientSpace */ diff --git a/ndb/test/ndbapi/testIndex.cpp b/ndb/test/ndbapi/testIndex.cpp index 78672cd519f..f715db1ef8c 100644 --- a/ndb/test/ndbapi/testIndex.cpp +++ b/ndb/test/ndbapi/testIndex.cpp @@ -1297,6 +1297,102 @@ runBug25059(NDBT_Context* ctx, NDBT_Step* step) return res; } +int tcSaveINDX_test(NDBT_Context* ctx, NDBT_Step* step, int inject_err) +{ + int result= NDBT_OK; + Ndb* pNdb = GETNDB(step); + NdbDictionary::Dictionary * dict = pNdb->getDictionary(); + const NdbDictionary::Index * idx = dict->getIndex(pkIdxName, *ctx->getTab()); + + HugoOperations ops(*ctx->getTab(), idx); + + g_err << "Using INDEX: " << pkIdxName << endl; + + NdbRestarter restarter; + + int loops = ctx->getNumLoops(); + const int rows = ctx->getNumRecords(); + const int batchsize = ctx->getProperty("BatchSize", 1); + + for(int bs=1; bs < loops; bs++) + { + int c= 0; + while (c++ < loops) + { + g_err << "BS " << bs << " LOOP #" << c << endl; + + g_err << "inserting error on op#" << c << endl; + + CHECK(ops.startTransaction(pNdb) == 0); + for(int i=1;i<=c;i++) + { + if(i==c) + { + if(restarter.insertErrorInAllNodes(inject_err)!=0) + { + g_err << "**** FAILED to insert error" << endl; + result= NDBT_FAILED; + break; + } + } + CHECK(ops.indexReadRecords(pNdb, pkIdxName, i,false,1) == 0); + if(i%bs==0 || i==c) + { + if(ivoid_value = ptr; attr_data->size = 4*sz; + if(!m_hostByteOrder + && attr_desc->m_column->getType() == NdbDictionary::Column::Timestamp) + attr_data->u_int32_value[0] = Twiddle32(attr_data->u_int32_value[0]); + if(!Twiddle(attr_desc, attr_data)) { res = -1; @@ -520,6 +528,29 @@ RestoreDataIterator::getNextTuple(int & res) */ const Uint32 arraySize = (4 * sz) / (attr_desc->size / 8); assert(arraySize >= attr_desc->arraySize); + + //convert the length of blob(v1) and text(v1) + if(!m_hostByteOrder + && (attr_desc->m_column->getType() == NdbDictionary::Column::Blob + || attr_desc->m_column->getType() == NdbDictionary::Column::Text)) + { + char* p = (char*)&attr_data->u_int64_value[0]; + Uint64 x; + memcpy(&x, p, sizeof(Uint64)); + x = Twiddle64(x); + memcpy(p, &x, sizeof(Uint64)); + } + + if(!m_hostByteOrder + && attr_desc->m_column->getType() == NdbDictionary::Column::Datetime) + { + char* p = (char*)&attr_data->u_int64_value[0]; + Uint64 x; + memcpy(&x, p, sizeof(Uint64)); + x = Twiddle64(x); + memcpy(p, &x, sizeof(Uint64)); + } + if(!Twiddle(attr_desc, attr_data, attr_desc->arraySize)) { res = -1; diff --git a/ndb/tools/restore/restore_main.cpp b/ndb/tools/restore/restore_main.cpp index 9ec59b9b4a6..9887869a0b3 100644 --- a/ndb/tools/restore/restore_main.cpp +++ b/ndb/tools/restore/restore_main.cpp @@ -112,7 +112,7 @@ static struct my_option my_long_options[] = "(parallelism can be 1 to 1024)", (gptr*) &ga_nParallelism, (gptr*) &ga_nParallelism, 0, GET_INT, REQUIRED_ARG, 128, 1, 1024, 0, 1, 0 }, - { "print", OPT_PRINT, "Print data and log to stdout", + { "print", OPT_PRINT, "Print metadata, data and log to stdout", (gptr*) &_print, (gptr*) &_print, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, { "print_data", OPT_PRINT_DATA, "Print data to stdout", diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index a00dd6c505c..05e35bd0157 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -181,8 +181,8 @@ struct err_code_mapping static const err_code_mapping err_map[]= { { 626, HA_ERR_KEY_NOT_FOUND, 0 }, - { 630, HA_ERR_FOUND_DUPP_KEY, 0 }, - { 893, HA_ERR_FOUND_DUPP_KEY, 0 }, + { 630, HA_ERR_FOUND_DUPP_KEY, 1 }, + { 893, HA_ERR_FOUND_DUPP_KEY, 1 }, { 721, HA_ERR_TABLE_EXIST, 1 }, { 4244, HA_ERR_TABLE_EXIST, 1 }, @@ -1758,9 +1758,15 @@ int ha_ndbcluster::unique_index_read(const byte *key, if (execute_no_commit_ie(this,trans,false) != 0) { - table->status= STATUS_NOT_FOUND; - DBUG_RETURN(ndb_err(trans)); + int err= ndb_err(trans); + if(err==HA_ERR_KEY_NOT_FOUND) + table->status= STATUS_NOT_FOUND; + else + table->status= STATUS_GARBAGE; + + DBUG_RETURN(err); } + // The value have now been fetched from NDB unpack_record(buf); table->status= 0; @@ -3310,6 +3316,8 @@ int ha_ndbcluster::info(uint flag) DBUG_PRINT("info", ("HA_STATUS_AUTO")); if (m_table && table->found_next_number_field) { + if ((my_errno= check_ndb_connection())) + DBUG_RETURN(my_errno); Ndb *ndb= get_ndb(); Uint64 auto_increment_value64; @@ -6462,7 +6470,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, if (uses_blob_value(m_retrieve_all_fields) || (cur_index_type == UNIQUE_INDEX && has_null_in_unique_index(active_index) && - null_value_index_search(ranges, ranges+range_count, buffer))) + null_value_index_search(ranges, ranges+range_count, buffer)) + || m_delete_cannot_batch || m_update_cannot_batch) { m_disable_multi_read= TRUE; DBUG_RETURN(handler::read_multi_range_first(found_range_p, diff --git a/sql/ha_ndbcluster_cond.cc b/sql/ha_ndbcluster_cond.cc index a0eaccb68d8..ea3f8a7683a 100644 --- a/sql/ha_ndbcluster_cond.cc +++ b/sql/ha_ndbcluster_cond.cc @@ -46,6 +46,14 @@ void ndb_serialize_cond(const Item *item, void *arg) // Check if we are skipping arguments to a function to be evaluated if (context->skip) { + if (!item) + { + DBUG_PRINT("info", ("Unexpected mismatch of found and expected number of function arguments %u", context->skip)); + sql_print_error("ndb_serialize_cond: Unexpected mismatch of found and " + "expected number of function arguments %u", context->skip); + context->skip= 0; + DBUG_VOID_RETURN; + } DBUG_PRINT("info", ("Skiping argument %d", context->skip)); context->skip--; switch (item->type()) { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 7b6eaef08ec..8410c66b034 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1361,6 +1361,7 @@ public: Item_cond(List &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 *nlist) { list.prepand(nlist); } bool fix_fields(THD *, Item **ref); @@ -1553,6 +1554,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: @@ -1574,6 +1584,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 0036d0aef77..cf06be5f95f 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -172,6 +172,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((gptr) sql_lock,MYF(0)); sql_lock= 0; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index b195e37920e..04e2816d553 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1597,10 +1597,10 @@ SEL_ARG *SEL_ARG::clone_tree(PARAM *param) the UPDATE/DELETE code will work: * index can only be scanned in forward direction * HA_EXTRA_KEYREAD will not be used - Perhaps these assumptions could be relaxed + Perhaps these assumptions could be relaxed. RETURN - index number + Number of the index that produces the required ordering in the cheapest way MAX_KEY if no such index was found. */ @@ -1619,6 +1619,7 @@ uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit) if (!(table->keys_in_use_for_query.is_set(idx))) continue; KEY_PART_INFO *keyinfo= table->key_info[idx].key_part; + uint n_parts= table->key_info[idx].key_parts; uint partno= 0; /* @@ -1628,7 +1629,7 @@ uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit) */ if (!(table->file->index_flags(idx, 0, 1) & HA_READ_ORDER)) continue; - for (ord= order; ord; ord= ord->next, partno++) + for (ord= order; ord && partno < n_parts; ord= ord->next, partno++) { Item *item= order->item[0]; if (!(item->type() == Item::FIELD_ITEM && diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index e1df1ce8d9a..9a29350880e 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1032,6 +1032,13 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) Query_cache_block_table *block_table, *block_table_end; ulong tot_length; Query_cache_query_flags flags; + const uint spin_treshold= 50000; + const double lock_time_treshold= 0.1; /* Time in seconds */ + uint spin_count= 0; + int lock_status= 0; + ulong new_time= 0; + ulong stop_time= 0; + DBUG_ENTER("Query_cache::send_result_to_client"); /* @@ -1078,7 +1085,29 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) } } - STRUCT_LOCK(&structure_guard_mutex); + stop_time= my_clock()+(ulong)lock_time_treshold*CLOCKS_PER_SEC; + while ((lock_status= pthread_mutex_trylock(&structure_guard_mutex)) == EBUSY + && spin_count < spin_treshold + && new_time < stop_time) + { + spin_count++; + if (spin_count%5) + new_time= my_clock(); + my_sleep(0); + } + + if (lock_status != 0) + { + /* + Query cache is too busy doing something else. + Fall back on ordinary statement execution. We also mark this + query as unsafe to cache because otherwise this thread will + still be halted when the result set is stored to the cache. + */ + thd->lex->safe_to_cache_query= FALSE; + goto err; + } + if (query_cache_size == 0 || flush_in_progress) { DBUG_PRINT("qcache", ("query cache disabled")); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 83c141f099f..9aefa71647e 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -440,7 +440,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) @@ -448,13 +448,13 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, if ((keyno=find_type(keyname, &table->s->keynames, 1+2)-1)<0) { my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), keyname, tables->alias); - goto err0; + goto err; } } if (insert_fields(thd, &thd->lex->select_lex.context, tables->db, tables->alias, &it, 0)) - goto err0; + goto err; protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index bd21d929291..f07af393070 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -417,7 +417,7 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type, if (duplic == DUP_UPDATE || duplic == DUP_REPLACE && *lock_type == TL_WRITE_CONCURRENT_INSERT) { - *lock_type= TL_WRITE; + *lock_type= TL_WRITE_DEFAULT; return; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index d11c2b21635..f1b4ffc949d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -526,6 +526,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; @@ -961,15 +962,34 @@ int MYSQLlex(void *arg, void *yythd) break; } } - while (lip->ptr != lip->end_of_query && - ((c=yyGet()) != '*' || 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->ptr != lip->end_of_query) { - if (c == '\n') - lip->yylineno++; + c= yyGet(); + if (c == '*') + { + if (yyPeek() == '/') + { + yySkip(); + comment_closed= TRUE; + state = MY_LEX_START; + break; + } + } + else if (c == '\n') + lip->yylineno++; } - if (lip->ptr != lip->end_of_query) - yySkip(); // remove last '/' - state = MY_LEX_START; // Try again + /* Unbalanced comments with a missing '*' '/' are a syntax error */ + if (! comment_closed) + return (ABORT_SYM); break; case MY_LEX_END_LONG_COMMENT: if (lex->in_comment && yyPeek() == '/') @@ -1009,6 +1029,9 @@ int MYSQLlex(void *arg, void *yythd) if (lip->ptr >= lip->end_of_query) { lip->next_state=MY_LEX_END; // Mark for next loop + /* Unbalanced comments with a missing '*' '/' are a syntax error */ + if (lex->in_comment) + return (ABORT_SYM); return(END_OF_INPUT); } state=MY_LEX_CHAR; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 94015a9fe07..ce56be79744 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1257,6 +1257,28 @@ typedef struct st_lex : public Query_tables_list void reset_n_backup_query_tables_list(Query_tables_list *backup); void restore_backup_query_tables_list(Query_tables_list *backup); + + /** + @brief check if the statement is a single-level join + @return result of the check + @retval TRUE The statement doesn't contain subqueries, unions and + stored procedure calls. + @retval FALSE There are subqueries, UNIONs or stored procedure calls. + */ + bool is_single_level_stmt() + { + /* + This check exploits the fact that the last added to all_select_list is + on its top. So select_lex (as the first added) will be at the tail + of the list. + */ + if (&select_lex == all_selects_list && !sroutines.records) + { + DBUG_ASSERT(!all_selects_list->next_select_in_list()); + return TRUE; + } + return FALSE; + } } LEX; struct st_lex_local: public st_lex diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 58f5ffc5235..084bcfc3c76 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1864,7 +1864,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS], &LOCK_status); bzero((char*) &table_list,sizeof(table_list)); - if (thd->copy_db_to(&table_list.db, 0)) + if (thd->copy_db_to(&table_list.db, &table_list.db_length)) break; pend= strend(packet); thd->convert_string(&conv_name, system_charset_info, @@ -3990,6 +3990,8 @@ end_with_restore_list: } case SQLCOM_SHOW_CREATE_DB: { + DBUG_EXECUTE_IF("4x_server_emul", + my_error(ER_UNKNOWN_ERROR, MYF(0)); goto error;); if (!strip_sp(lex->name) || check_db_name(lex->name)) { my_error(ER_WRONG_DB_NAME, MYF(0), lex->name); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1040ae7e04b..bd93a7ae203 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -189,6 +189,7 @@ static bool setup_new_fields(THD *thd, List &fields, List &all_fields, ORDER *new_order); static ORDER *create_distinct_group(THD *thd, Item **ref_pointer_array, ORDER *order, List &fields, + List &all_fields, bool *all_order_by_fields_used); static bool test_if_subpart(ORDER *a,ORDER *b); static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables); @@ -537,6 +538,28 @@ JOIN::prepare(Item ***rref_pointer_array, fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array)) DBUG_RETURN(-1); + if (group_list) + { + /* + Because HEAP tables can't index BIT fields we need to use an + additional hidden field for grouping because later it will be + converted to a LONG field. Original field will remain of the + BIT type and will be returned to a client. + */ + for (ORDER *ord= group_list; ord; ord= ord->next) + { + if ((*ord->item)->type() == Item::FIELD_ITEM && + (*ord->item)->field_type() == MYSQL_TYPE_BIT) + { + Item_field *field= new Item_field(thd, *(Item_field**)ord->item); + int el= all_fields.elements; + ref_pointer_array[el]= field; + all_fields.push_front(field); + ord->item= ref_pointer_array + el; + } + } + } + if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */ DBUG_RETURN(-1); @@ -1030,6 +1053,14 @@ JOIN::optimize() find_field_in_order_list, (void *) group_list)) { + /* + We have found that grouping can be removed since groups correspond to + only one row anyway, but we still have to guarantee correct result + order. The line below effectively rewrites the query from GROUP BY + to ORDER BY . One exception is if skip_sort_order is + set (see above), then we can simply skip GROUP BY. + */ + order= skip_sort_order ? 0 : group_list; group_list= 0; group= 0; } @@ -1068,12 +1099,13 @@ JOIN::optimize() if (order) skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1); if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array, - order, fields_list, + order, fields_list, all_fields, &all_order_fields_used))) { bool skip_group= (skip_sort_order && test_if_skip_sort_order(tab, group_list, select_limit, 1) != 0); + count_field_types(select_lex, &tmp_table_param, all_fields, 0); if ((skip_group && all_order_fields_used) || select_limit == HA_POS_ERROR || (order && !skip_sort_order)) @@ -4369,9 +4401,13 @@ choose_plan(JOIN *join, table_map join_tables) /* Store the cost of this query into a user variable - Don't update last_query_cost for 'show status' command + Don't update last_query_cost for 'show status' command. + Don't update last_query_cost for statements that are not "flat joins" : + i.e. they have subqueries, unions or call stored procedures. + TODO: calculate a correct cost for a query with subqueries and UNIONs. */ - if (join->thd->lex->orig_sql_command != SQLCOM_SHOW_STATUS) + if (join->thd->lex->orig_sql_command != SQLCOM_SHOW_STATUS && + join->thd->lex->is_single_level_stmt()) join->thd->status_var.last_query_cost= join->best_read; DBUG_RETURN(FALSE); } @@ -13629,11 +13665,12 @@ setup_new_fields(THD *thd, List &fields, static ORDER * create_distinct_group(THD *thd, Item **ref_pointer_array, - ORDER *order_list, List &fields, + ORDER *order_list, List &fields, + List &all_fields, bool *all_order_by_fields_used) { List_iterator li(fields); - Item *item; + Item *item, **orig_ref_pointer_array= ref_pointer_array; ORDER *order,*group,**prev; *all_order_by_fields_used= 1; @@ -13673,12 +13710,31 @@ create_distinct_group(THD *thd, Item **ref_pointer_array, ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER)); if (!ord) return 0; - /* - We have here only field_list (not all_field_list), so we can use - simple indexing of ref_pointer_array (order in the array and in the - list are same) - */ - ord->item= ref_pointer_array; + + if (item->type() == Item::FIELD_ITEM && + item->field_type() == MYSQL_TYPE_BIT) + { + /* + Because HEAP tables can't index BIT fields we need to use an + additional hidden field for grouping because later it will be + converted to a LONG field. Original field will remain of the + BIT type and will be returned to a client. + */ + Item_field *new_item= new Item_field(thd, (Item_field*)item); + int el= all_fields.elements; + orig_ref_pointer_array[el]= new_item; + all_fields.push_front(new_item); + ord->item= orig_ref_pointer_array + el; + } + else + { + /* + We have here only field_list (not all_field_list), so we can use + simple indexing of ref_pointer_array (order in the array and in the + list are same) + */ + ord->item= ref_pointer_array; + } ord->asc=1; *prev=ord; prev= &ord->next; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 6e4b5defb97..1737bb0d9f8 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -971,7 +971,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, Lex_input_stream lip(thd, trg_create_str->str, trg_create_str->length); thd->m_lip= &lip; lex_start(thd); - thd->spcont= NULL; + thd->spcont= NULL; int err= MYSQLparse((void *)thd); if (err || thd->is_fatal_error) diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 56d7a3f8a9d..35a97411511 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1008,8 +1008,19 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local; { + char old_db_buf[NAME_LEN+1]; + LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; + bool dbchanged; Lex_input_stream lip(thd, table->query.str, table->query.length); thd->m_lip= &lip; + + /* + Use view db name as thread default database, in order to ensure + that the view is parsed and prepared correctly. + */ + if ((result= sp_use_new_db(thd, table->view_db, &old_db, 1, &dbchanged))) + goto end; + lex_start(thd); view_select= &lex->select_lex; view_select->select_number= ++thd->select_number; @@ -1051,6 +1062,9 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, thd->variables.character_set_client= save_cs; thd->variables.sql_mode= save_mode; + + if (dbchanged && mysql_change_db(thd, &old_db, TRUE)) + goto err; } if (!res && !thd->is_fatal_error) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a53cadafda8..553cc6d24d5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -458,10 +458,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there is 251 shift/reduce conflict. We should not introduce - new conflicts any more. + Currently there are 245 shift/reduce conflicts. + We should not introduce new conflicts any more. */ -%expect 251 +%expect 245 %token END_OF_INPUT @@ -1011,7 +1011,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 @@ -1024,6 +1025,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 IDENT IDENT_QUOTED TEXT_STRING DECIMAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM @@ -1066,8 +1068,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type 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 @@ -1159,7 +1162,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); field_opt_list opt_binary table_lock_list table_lock ref_list opt_on_delete opt_on_delete_list opt_on_delete_item use opt_delete_options opt_delete_option varchar nchar nvarchar - opt_outer table_list table_name opt_option opt_place + opt_outer table_list table_name table_alias_ref_list table_alias_ref + opt_option opt_place opt_attribute opt_attribute_list attribute column_list column_list_id opt_column_list grant_privileges grant_ident grant_list grant_option object_privilege object_privilege_list user_list rename_list @@ -4464,77 +4468,126 @@ optional_braces: | '(' ')' {}; /* all possible expressions */ -expr: - bool_term { Select->expr_list.push_front(new List); } - bool_or_expr +expr: + expr or expr %prec OR_SYM { - List *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; - } - ; - -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); } - bool_and_expr - { - List *list= Select->expr_list.pop(); - if (list->elements) { - list->push_front($1); - $$= new Item_cond_and(*list); - /* optimize construction of logical AND to reduce - amount of objects for complex expressions */ + /* X OR Y */ + $$ = new (YYTHD->mem_root) Item_cond_or($1, $3); + } + } + | 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 + { + /* See comments in rule expr: expr or expr */ + Item_cond_and *item1; + Item_cond_and *item3; + if (is_cond_and($1)) + { + 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 @@ -4577,11 +4630,11 @@ predicate: | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate { $$= new Item_func_between($1,$3,$5); } | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate - { - Item_func_between *item= new Item_func_between($1,$4,$6); - item->negate(); - $$= item; - } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | bit_expr SOUNDS_SYM LIKE bit_expr { $$= new Item_func_eq(new Item_func_soundex($1), new Item_func_soundex($4)); } @@ -4595,40 +4648,36 @@ predicate: | bit_expr ; 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 - { $$= new Item_func_shift_left($1,$3); } - | bit_factor SHIFT_RIGHT value_expr - { $$= 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 - { $$= new Item_date_add_interval($1,$3,$4,0); } - | value_expr '-' interval_expr interval - { $$= 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); } - | simple_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_expr SHIFT_RIGHT bit_expr %prec SHIFT_RIGHT + { $$= new Item_func_shift_right($1,$3); } + | 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); } + | bit_expr '-' interval_expr interval %prec '-' + { $$= new Item_date_add_interval($1,$3,$4,1); } + | 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 + ; or: OR_SYM | OR2_SYM; and: AND_SYM | AND_AND_SYM; @@ -4648,7 +4697,8 @@ all_or_any: ALL { $$ = 1; } ; interval_expr: - INTERVAL_SYM expr { $$=$2; } + INTERVAL_SYM expr %prec INTERVAL_SYM + { $$=$2; } ; simple_expr: @@ -6504,6 +6554,20 @@ table_name: } ; +table_alias_ref_list: + table_alias_ref + | table_alias_ref_list ',' table_alias_ref; + +table_alias_ref: + table_ident + { + if (!Select->add_table_to_list(YYTHD, $1, NULL, + TL_OPTION_UPDATING | TL_OPTION_ALIAS, + Lex->lock_option )) + MYSQL_YYABORT; + } + ; + if_exists: /* empty */ { $$= 0; } | IF EXISTS { $$= 1; } @@ -6774,7 +6838,7 @@ single_multi: if (multi_delete_set_locks_and_link_aux_tables(Lex)) MYSQL_YYABORT; } - | FROM table_wild_list + | FROM table_alias_ref_list { mysql_init_multi_delete(Lex); } USING join_table_list where_clause {