diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 96ec5803b63..4f2065657d5 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -44,17 +44,21 @@ set -e export AM_MAKEFLAGS AM_MAKEFLAGS="-j 4" +# SSL library to use. Should be changed to --with-yassl +SSL_LIBRARY=--with-openssl + # If you are not using codefusion add "-Wpointer-arith" to WARNINGS # The following warning flag will give too many warnings: # -Wshadow -Wunused -Winline (The later isn't usable in C++ as # __attribute()__ doesn't work with gnu C++) + global_warnings="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings" #debug_extra_warnings="-Wuninitialized" c_warnings="$global_warnings -Wunused" cxx_warnings="$global_warnings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor" -base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-openssl --with-big-tables --with-blackhole-storage-engine --with-federated-storage-engine --with-csv-storage-engine" -base_max_no_ndb_configs="--with-innodb --with-berkeley-db --without-ndbcluster --with-archive-storage-engine --with-openssl --with-big-tables --with-blackhole-storage-engine --with-federated-storage-engine --with-csv-storage-engine" -max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-blackhole-storage-engine --with-csv-storage-engine --with-openssl --with-embedded-server --with-big-tables" +base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-big-tables --with-blackhole-storage-engine --with-federated-storage-engine --with-csv-storage-engine $SSL_LIBRARY" +base_max_no_ndb_configs="--with-innodb --with-berkeley-db --without-ndbcluster --with-archive-storage-engine --with-big-tables --with-blackhole-storage-engine --with-federated-storage-engine --with-csv-storage-engine $SSL_LIBRARY" +max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-blackhole-storage-engine --with-csv-storage-engine $SSL_LIBRARY --with-embedded-server --with-big-tables" max_configs="$base_max_configs --with-embedded-server" max_no_ndb_configs="$base_max_no_ndb_configs --with-embedded-server" diff --git a/BUILD/compile-pentium64-debug-max b/BUILD/compile-pentium64-debug-max new file mode 100755 index 00000000000..f0745c88c90 --- /dev/null +++ b/BUILD/compile-pentium64-debug-max @@ -0,0 +1,13 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" $@ --with-debug=full + +extra_flags="$pentium64_cflags $debug_cflags $max_cflags" +c_warnings="$c_warnings $debug_extra_warnings" +cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$pentium_configs $debug_configs $max_configs" + +extra_configs="$extra_configs " + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium64-valgrind-max b/BUILD/compile-pentium64-valgrind-max index 2e4ff8e0082..ef932920130 100755 --- a/BUILD/compile-pentium64-valgrind-max +++ b/BUILD/compile-pentium64-valgrind-max @@ -3,13 +3,13 @@ path=`dirname $0` . "$path/SETUP.sh" -extra_flags="$pentium64_cflags $debug_cflags -USAFEMALLOC -UFORCE_INIT_OF_VARS -DHAVE_purify -DMYSQL_SERVER_SUFFIX=-valgrind-max" +extra_flags="$pentium64_cflags $debug_cflags $max_cflags -USAFEMALLOC -UFORCE_INIT_OF_VARS -DHAVE_purify -DMYSQL_SERVER_SUFFIX=-valgrind-max" c_warnings="$c_warnings $debug_extra_warnings" cxx_warnings="$cxx_warnings $debug_extra_warnings" extra_configs="$pentium_configs $debug_configs" # We want to test isam when building with valgrind -extra_configs="$extra_configs --with-berkeley-db --with-innodb --with-isam --with-embedded-server --with-openssl --with-raid --with-ndbcluster" +extra_configs="$extra_configs $max_leave_isam_configs --with-isam" . "$path/FINISH.sh" diff --git a/Makefile.am b/Makefile.am index 401a53459ae..d6a04583801 100644 --- a/Makefile.am +++ b/Makefile.am @@ -112,7 +112,7 @@ test: test-force: cd mysql-test; \ - ./mysql-test-run --force ; \ + ./mysql-test-run --force && \ ./mysql-test-run --ps-protocol --force # We are testing a new Perl version of the test script @@ -123,7 +123,7 @@ test-pl: test-force-pl: cd mysql-test; \ - ./mysql-test-run.pl --force ; \ + ./mysql-test-run.pl --force && \ ./mysql-test-run.pl --ps-protocol --force # Don't update the files from bitkeeper diff --git a/configure.in b/configure.in index 65fe7152055..c36d24a5bc5 100644 --- a/configure.in +++ b/configure.in @@ -334,6 +334,10 @@ case "$target_os" in # Use the built-in alloca() CFLAGS="$CFLAGS -Kalloca" CXXFLAGS="$CFLAGS -Kalloca" + # Use no_implicit for templates + CXXFLAGS="$CXXFLAGS -Tno_implicit" + AC_DEFINE([HAVE_EXPLICIT_TEMPLATE_INSTANTIATION], + [1], [Defined by configure. Use explicit template instantiation.]) fi ;; esac diff --git a/extra/yassl/src/socket_wrapper.cpp b/extra/yassl/src/socket_wrapper.cpp index 91cea1f9753..285e0dee2e5 100644 --- a/extra/yassl/src/socket_wrapper.cpp +++ b/extra/yassl/src/socket_wrapper.cpp @@ -39,7 +39,7 @@ #include #endif // _WIN32 -#ifdef __sun +#if defined(__sun) || defined(__SCO_VERSION__) #include #endif diff --git a/extra/yassl/src/timer.cpp b/extra/yassl/src/timer.cpp index 4fe0d3aa4f9..8b7d2d17a84 100644 --- a/extra/yassl/src/timer.cpp +++ b/extra/yassl/src/timer.cpp @@ -26,13 +26,17 @@ #include "runtime.hpp" #include "timer.hpp" +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#endif + namespace yaSSL { #ifdef _WIN32 - #define WIN32_LEAN_AND_MEAN - #include - timer_d timer() { static bool init(false); @@ -57,8 +61,6 @@ namespace yaSSL { #else // _WIN32 - #include - timer_d timer() { struct timeval tv; diff --git a/include/my_base.h b/include/my_base.h index c76cf8c604e..ba3edfad0c8 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -248,6 +248,7 @@ enum ha_base_keytype { #define HA_OPTION_CHECKSUM 32 #define HA_OPTION_DELAY_KEY_WRITE 64 #define HA_OPTION_NO_PACK_KEYS 128 /* Reserved for MySQL */ +#define HA_OPTION_CREATE_FROM_ENGINE 256 #define HA_OPTION_TEMP_COMPRESS_RECORD ((uint) 16384) /* set by isamchk */ #define HA_OPTION_READ_ONLY_DATA ((uint) 32768) /* Set by isamchk */ @@ -258,7 +259,6 @@ enum ha_base_keytype { #define HA_CREATE_TMP_TABLE 4 #define HA_CREATE_CHECKSUM 8 #define HA_CREATE_DELAY_KEY_WRITE 64 -#define HA_CREATE_FROM_ENGINE 128 /* Bits in flag to _status */ diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 2133043a587..62c2b9014c3 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -223,10 +223,10 @@ MYSQL_MANAGER_USER=root # number is to be used, 0 - 16 or similar. # if [ -n "$MTR_BUILD_THREAD" ] ; then - MASTER_MYPORT=`expr $MTR_BUILD_THREAD '*' 40 + 8120` + MASTER_MYPORT=`expr $MTR_BUILD_THREAD '*' 5 + 10000` MYSQL_MANAGER_PORT=`expr $MASTER_MYPORT + 2` - SLAVE_MYPORT=`expr $MASTER_MYPORT + 16` - NDBCLUSTER_PORT=`expr $MASTER_MYPORT + 24` + SLAVE_MYPORT=`expr $MASTER_MYPORT + 3` + NDBCLUSTER_PORT=`expr $MASTER_MYPORT + 4` echo "Using MTR_BUILD_THREAD = $MTR_BUILD_THREAD" echo "Using MASTER_MYPORT = $MASTER_MYPORT" diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result index 530ff6ef59b..5cdf9612300 100644 --- a/mysql-test/r/bdb.result +++ b/mysql-test/r/bdb.result @@ -1870,7 +1870,7 @@ a b drop table t1; create table t1 (v varchar(65530), key(v)); Warnings: -Warning 1071 Specified key was too long; max key length is 1024 bytes +Warning 1071 Specified key was too long; max key length is MAX_KEY_LENGTH bytes drop table if exists t1; create table t1 (v varchar(65536)); Warnings: diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index ca9a2662f94..84779858b75 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -1,4 +1,4 @@ -drop table if exists t1; +drop table if exists t1, t2; select 0,256,00000000000000065536,2147483647,-2147483648,2147483648,+4294967296; 0 256 00000000000000065536 2147483647 -2147483648 2147483648 4294967296 0 256 65536 2147483647 -2147483648 2147483648 4294967296 diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index d5b1cf4dd63..4f49f77d46c 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -20,9 +20,9 @@ time_zone_transition_type user show tables; Tables_in_test -connect(localhost,root,z,test2,MASTER_PORT,MYSQL_TEST_DIR/var/tmp/master.sock); +connect(localhost,root,z,test2,MASTER_PORT,MASTER_SOCKET); ERROR 28000: Access denied for user 'root'@'localhost' (using password: YES) -connect(localhost,root,z,test,MASTER_PORT,MYSQL_TEST_DIR/var/tmp/master.sock); +connect(localhost,root,z,test,MASTER_PORT,MASTER_SOCKET); ERROR 28000: Access denied for user 'root'@'localhost' (using password: YES) grant ALL on *.* to test@localhost identified by "gambling"; grant ALL on *.* to test@127.0.0.1 identified by "gambling"; @@ -47,13 +47,13 @@ time_zone_transition_type user show tables; Tables_in_test -connect(localhost,test,,test2,MASTER_PORT,MYSQL_TEST_DIR/var/tmp/master.sock); +connect(localhost,test,,test2,MASTER_PORT,MASTER_SOCKET); ERROR 28000: Access denied for user 'test'@'localhost' (using password: NO) -connect(localhost,test,,"",MASTER_PORT,MYSQL_TEST_DIR/var/tmp/master.sock); +connect(localhost,test,,"",MASTER_PORT,MASTER_SOCKET); ERROR 28000: Access denied for user 'test'@'localhost' (using password: NO) -connect(localhost,test,zorro,test2,MASTER_PORT,MYSQL_TEST_DIR/var/tmp/master.sock); +connect(localhost,test,zorro,test2,MASTER_PORT,MASTER_SOCKET); ERROR 28000: Access denied for user 'test'@'localhost' (using password: YES) -connect(localhost,test,zorro,test,MASTER_PORT,MYSQL_TEST_DIR/var/tmp/master.sock); +connect(localhost,test,zorro,test,MASTER_PORT,MASTER_SOCKET); ERROR 28000: Access denied for user 'test'@'localhost' (using password: YES) update mysql.user set password=old_password("gambling2") where user=_binary"test"; flush privileges; @@ -82,13 +82,13 @@ time_zone_transition_type user show tables; Tables_in_test -connect(localhost,test,,test2,MASTER_PORT,MYSQL_TEST_DIR/var/tmp/master.sock); +connect(localhost,test,,test2,MASTER_PORT,MASTER_SOCKET); ERROR 28000: Access denied for user 'test'@'localhost' (using password: NO) -connect(localhost,test,,test,MASTER_PORT,MYSQL_TEST_DIR/var/tmp/master.sock); +connect(localhost,test,,test,MASTER_PORT,MASTER_SOCKET); ERROR 28000: Access denied for user 'test'@'localhost' (using password: NO) -connect(localhost,test,zorro,test2,MASTER_PORT,MYSQL_TEST_DIR/var/tmp/master.sock); +connect(localhost,test,zorro,test2,MASTER_PORT,MASTER_SOCKET); ERROR 28000: Access denied for user 'test'@'localhost' (using password: YES) -connect(localhost,test,zorro,test,MASTER_PORT,MYSQL_TEST_DIR/var/tmp/master.sock); +connect(localhost,test,zorro,test,MASTER_PORT,MASTER_SOCKET); ERROR 28000: Access denied for user 'test'@'localhost' (using password: YES) delete from mysql.user where user=_binary"test"; flush privileges; diff --git a/mysql-test/r/csv.result b/mysql-test/r/csv.result index ea0d34271b5..2e3d11ad461 100644 --- a/mysql-test/r/csv.result +++ b/mysql-test/r/csv.result @@ -4929,3 +4929,50 @@ Warnings: Note 1051 Unknown table 't2' Note 1051 Unknown table 't3' Note 1051 Unknown table 't4' +DROP TABLE IF EXISTS bug13894; +CREATE TABLE bug13894 ( val integer ) ENGINE = CSV; +INSERT INTO bug13894 VALUES (5); +INSERT INTO bug13894 VALUES (10); +INSERT INTO bug13894 VALUES (11); +INSERT INTO bug13894 VALUES (10); +SELECT * FROM bug13894; +val +5 +10 +11 +10 +UPDATE bug13894 SET val=6 WHERE val=10; +SELECT * FROM bug13894; +val +5 +11 +6 +6 +DROP TABLE bug13894; +DROP TABLE IF EXISTS bug14672; +CREATE TABLE bug14672 (c1 integer) engine = CSV; +INSERT INTO bug14672 VALUES (1), (2), (3); +SELECT * FROM bug14672; +c1 +1 +2 +3 +DELETE FROM bug14672 WHERE c1 = 2; +SELECT * FROM bug14672; +c1 +1 +3 +INSERT INTO bug14672 VALUES (4); +SELECT * FROM bug14672; +c1 +1 +3 +4 +INSERT INTO bug14672 VALUES (5); +SELECT * FROM bug14672; +c1 +1 +3 +4 +5 +DROP TABLE bug14672; diff --git a/mysql-test/r/ctype_cp932_binlog.result b/mysql-test/r/ctype_cp932_binlog.result new file mode 100644 index 00000000000..d04fce7738c --- /dev/null +++ b/mysql-test/r/ctype_cp932_binlog.result @@ -0,0 +1,17 @@ +drop table if exists t1; +set names cp932; +set character_set_database = cp932; +RESET MASTER; +CREATE TABLE t1(f1 blob); +PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)'; +SET @var1= x'8300'; +EXECUTE stmt1 USING @var1; +SHOW BINLOG EVENTS FROM 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 98 Query 1 185 use `test`; CREATE TABLE t1(f1 blob) +master-bin.000001 185 User var 1 224 @`var1`=_binary 0x8300 COLLATE binary +master-bin.000001 224 Query 1 317 use `test`; INSERT INTO t1 VALUES(@'var1') +SELECT HEX(f1) FROM t1; +HEX(f1) +8300 +DROP table t1; diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 6461c393d51..90884dcc596 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -93,7 +93,7 @@ explain extended select grp,group_concat(distinct c order by c desc) from t1 gro id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 9 Using filesort Warnings: -Note 1003 select `test`.`t1`.`grp` AS `grp`,group_concat(distinct `test`.`t1`.`c` order by `test`.`t1`.`c` separator ',') AS `group_concat(distinct c order by c desc)` from `test`.`t1` group by `test`.`t1`.`grp` +Note 1003 select `test`.`t1`.`grp` AS `grp`,group_concat(distinct `test`.`t1`.`c` order by `test`.`t1`.`c` DESC separator ',') AS `group_concat(distinct c order by c desc)` from `test`.`t1` group by `test`.`t1`.`grp` select grp,group_concat(c order by c separator ",") from t1 group by grp; grp group_concat(c order by c separator ",") 1 a @@ -113,7 +113,7 @@ explain extended select grp,group_concat(distinct c order by c separator ",") fr id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 9 Using filesort Warnings: -Note 1003 select `test`.`t1`.`grp` AS `grp`,group_concat(distinct `test`.`t1`.`c` order by `test`.`t1`.`c` separator ',') AS `group_concat(distinct c order by c separator ",")` from `test`.`t1` group by `test`.`t1`.`grp` +Note 1003 select `test`.`t1`.`grp` AS `grp`,group_concat(distinct `test`.`t1`.`c` order by `test`.`t1`.`c` ASC separator ',') AS `group_concat(distinct c order by c separator ",")` from `test`.`t1` group by `test`.`t1`.`grp` select grp,group_concat(distinct c order by c desc separator ",") from t1 group by grp; grp group_concat(distinct c order by c desc separator ",") 1 a diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result index 9d514be76e8..c4dd6cf9a86 100644 --- a/mysql-test/r/join_nested.result +++ b/mysql-test/r/join_nested.result @@ -1403,3 +1403,67 @@ SELECT v2.x FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); ERROR 42S22: Unknown column 'v2.x' in 'field list' DROP VIEW v1, v2; DROP TABLE t1, t2, t3, t4, t5, t6; +create table t1 (id1 int(11) not null); +insert into t1 values (1),(2); +create table t2 (id2 int(11) not null); +insert into t2 values (1),(2),(3),(4); +create table t3 (id3 char(16) not null); +insert into t3 values ('100'); +create table t4 (id2 int(11) not null, id3 char(16)); +create table t5 (id1 int(11) not null, key (id1)); +insert into t5 values (1),(2),(1); +create view v1 as +select t4.id3 from t4 join t2 on t4.id2 = t2.id2; +select t1.id1 from t1 inner join (t3 left join v1 on t3.id3 = v1.id3); +id1 +1 +2 +drop view v1; +drop table t1, t2, t3, t4, t5; +create table t0 (a int); +insert into t0 values (0),(1),(2),(3); +create table t1(a int); +insert into t1 select A.a + 10*(B.a) from t0 A, t0 B; +create table t2 (a int, b int); +insert into t2 values (1,1), (2,2), (3,3); +create table t3(a int, b int, filler char(200), key(a)); +insert into t3 select a,a,'filler' from t1; +insert into t3 select a,a,'filler' from t1; +create table t4 like t3; +insert into t4 select * from t3; +insert into t4 select * from t3; +create table t5 like t4; +insert into t5 select * from t4; +insert into t5 select * from t4; +create table t6 like t5; +insert into t6 select * from t5; +insert into t6 select * from t5; +create table t7 like t6; +insert into t7 select * from t6; +insert into t7 select * from t6; +explain select * from t4 join +t2 left join (t3 join t5 on t5.a=t3.b) on t3.a=t2.b where t4.a<=>t3.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL X +1 SIMPLE t3 ref a a 5 test.t2.b X +1 SIMPLE t5 ref a a 5 test.t3.b X +1 SIMPLE t4 ref a a 5 test.t3.b X Using where +explain select * from (t4 join t6 on t6.a=t4.b) right join t3 on t4.a=t3.b +join t2 left join (t5 join t7 on t7.a=t5.b) on t5.a=t2.b where t3.a<=>t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL X +1 SIMPLE t3 ref a a 5 test.t2.b X Using where +1 SIMPLE t4 ref a a 5 test.t3.b X +1 SIMPLE t6 ref a a 5 test.t4.b X +1 SIMPLE t5 ref a a 5 test.t2.b X +1 SIMPLE t7 ref a a 5 test.t5.b X +explain select * from t2 left join +(t3 left join (t4 join t6 on t6.a=t4.b) on t4.a=t3.b +join t5 on t5.a=t3.b) on t3.a=t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL X +1 SIMPLE t3 ref a a 5 test.t2.b X +1 SIMPLE t4 ref a a 5 test.t3.b X +1 SIMPLE t6 ref a a 5 test.t4.b X +1 SIMPLE t5 ref a a 5 test.t3.b X +drop table t0, t1, t2, t4, t5, t6; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 60e7ebbd966..82a761252b5 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -2236,6 +2236,7 @@ DROP FUNCTION bug9056_func1; DROP FUNCTION bug9056_func2; DROP PROCEDURE bug9056_proc1; DROP PROCEDURE bug9056_proc2; +DROP PROCEDURE `a'b`; drop table t1; drop table if exists t1; create table t1 (`d` timestamp, unique (`d`)); diff --git a/mysql-test/r/ndb_basic.result b/mysql-test/r/ndb_basic.result index a374f845933..e288592c390 100644 --- a/mysql-test/r/ndb_basic.result +++ b/mysql-test/r/ndb_basic.result @@ -673,3 +673,7 @@ select * from atablewithareallylongandirritatingname; a 2 drop table atablewithareallylongandirritatingname; +CREATE TABLE t1 ( b INT ) PACK_KEYS = 0 ENGINE = ndb; +select * from t1; +b +drop table t1; diff --git a/mysql-test/r/read_only.result b/mysql-test/r/read_only.result new file mode 100644 index 00000000000..55a14bcaec8 --- /dev/null +++ b/mysql-test/r/read_only.result @@ -0,0 +1,43 @@ +DROP TABLE IF EXISTS t1,t2,t3; +grant CREATE, SELECT, DROP on *.* to test@localhost; +set global read_only=0; +create table t1 (a int); +insert into t1 values(1); +create table t2 select * from t1; +set global read_only=1; +create table t3 (a int); +drop table t3; +select @@global.read_only; +@@global.read_only +1 +create table t3 (a int); +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +insert into t1 values(1); +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +update t1 set a=1 where 1=0; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +update t1,t2 set t1.a=t2.a+1 where t1.a=t2.a; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +delete t1,t2 from t1,t2 where t1.a=t2.a; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +create temporary table t3 (a int); +create temporary table t4 (a int) select * from t3; +insert into t3 values(1); +insert into t4 select * from t3; +update t1,t3 set t1.a=t3.a+1 where t1.a=t3.a; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +update t1,t3 set t3.a=t1.a+1 where t1.a=t3.a; +update t4,t3 set t4.a=t3.a+1 where t4.a=t3.a; +delete t1 from t1,t3 where t1.a=t3.a; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +delete t3 from t1,t3 where t1.a=t3.a; +delete t4 from t3,t4 where t4.a=t3.a; +create temporary table t1 (a int); +insert into t1 values(1); +update t1,t3 set t1.a=t3.a+1 where t1.a=t3.a; +delete t1 from t1,t3 where t1.a=t3.a; +drop table t1; +insert into t1 values(1); +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +drop table t1,t2; +drop user test@localhost; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 76a8b5a11e7..318cf8e7b65 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3201,3 +3201,43 @@ a b c select * from t1 join t2 straight_join t3 on (t1.a=t3.c); a b c drop table t1, t2 ,t3; +create table t1(f1 int, f2 date); +insert into t1 values(1,'2005-01-01'),(2,'2005-09-01'),(3,'2005-09-30'), +(4,'2005-10-01'),(5,'2005-12-30'); +select * from t1 where f2 >= 0; +f1 f2 +1 2005-01-01 +2 2005-09-01 +3 2005-09-30 +4 2005-10-01 +5 2005-12-30 +select * from t1 where f2 >= '0000-00-00'; +f1 f2 +1 2005-01-01 +2 2005-09-01 +3 2005-09-30 +4 2005-10-01 +5 2005-12-30 +select * from t1 where f2 >= '2005-09-31'; +f1 f2 +4 2005-10-01 +5 2005-12-30 +select * from t1 where f2 >= '2005-09-3a'; +f1 f2 +4 2005-10-01 +5 2005-12-30 +Warnings: +Warning 1292 Incorrect date value: '2005-09-3a' for column 'f2' at row 1 +select * from t1 where f2 <= '2005-09-31'; +f1 f2 +1 2005-01-01 +2 2005-09-01 +3 2005-09-30 +select * from t1 where f2 <= '2005-09-3a'; +f1 f2 +1 2005-01-01 +2 2005-09-01 +3 2005-09-30 +Warnings: +Warning 1292 Incorrect date value: '2005-09-3a' for column 'f2' at row 1 +drop table t1; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 1f3f7dba7da..d50e6dd3751 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3575,4 +3575,46 @@ DROP VIEW bug13095_v1 DROP PROCEDURE IF EXISTS bug13095; DROP VIEW IF EXISTS bug13095_v1; DROP TABLE IF EXISTS bug13095_t1; +drop procedure if exists bug14210| +set @@session.max_heap_table_size=16384| +select @@session.max_heap_table_size| +@@session.max_heap_table_size +16384 +create table t3 (a char(255)) engine=InnoDB| +create procedure bug14210_fill_table() +begin +declare table_size, max_table_size int default 0; +select @@session.max_heap_table_size into max_table_size; +delete from t3; +insert into t3 (a) values (repeat('a', 255)); +repeat +insert into t3 select a from t3; +select count(*)*255 from t3 into table_size; +until table_size > max_table_size*2 end repeat; +end| +call bug14210_fill_table()| +drop procedure bug14210_fill_table| +create table t4 like t3| +create procedure bug14210() +begin +declare a char(255); +declare done int default 0; +declare c cursor for select * from t3; +declare continue handler for sqlstate '02000' set done = 1; +open c; +repeat +fetch c into a; +if not done then +insert into t4 values (upper(a)); +end if; +until done end repeat; +close c; +end| +call bug14210()| +select count(*) from t4| +count(*) +256 +drop table t3, t4| +drop procedure bug14210| +set @@session.max_heap_table_size=default| drop table t1,t2; diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index dbae646c362..1ed4135d52b 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -846,15 +846,14 @@ select 0/0; NULL select 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 as x; x -999999999999999999999999999999999999999999999999999999999999999999999999999999999 +99999999999999999999999999999999999999999999999999999999999999999 Warnings: Error 1292 Truncated incorrect DECIMAL value: '' select 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + 1 as x; x -NULL +100000000000000000000000000000000000000000000000000000000000000000 Warnings: Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' select 0.190287977636363637 + 0.040372670 * 0 - 0; 0.190287977636363637 + 0.040372670 * 0 - 0 0.190287977636363637 @@ -1021,3 +1020,26 @@ cast(@non_existing_user_var/2 as DECIMAL) NULL create table t (d decimal(0,10)); ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'd'). +create table t1 (c1 decimal(64)); +insert into t1 values( +89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000); +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value adjusted for column 'c1' at row 1 +insert into t1 values( +99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * +99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999); +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value adjusted for column 'c1' at row 1 +insert into t1 values(1e100); +Warnings: +Warning 1264 Out of range value adjusted for column 'c1' at row 1 +select * from t1; +c1 +9999999999999999999999999999999999999999999999999999999999999999 +9999999999999999999999999999999999999999999999999999999999999999 +9999999999999999999999999999999999999999999999999999999999999999 +drop table t1; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 6f15e7af399..b31ec9a3bab 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1,4 +1,4 @@ -drop table if exists t1,t2,t9,`t1a``b`,v1,v2,v3,v4,v5,v6; +drop table if exists t1,t2,t3,t4,t9,`t1a``b`,v1,v2,v3,v4,v5,v6; drop view if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6; drop database if exists mysqltest; use test; @@ -2323,3 +2323,55 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where DROP VIEW v1,v2; DROP TABLE t1,t2,t3; +create table t1 (f1 int, f2 int); +insert into t1 values(1,1),(1,2),(1,3); +create view v1 as select f1 ,group_concat(f2 order by f2 asc) from t1 group by f1; +create view v2 as select f1 ,group_concat(f2 order by f2 desc) from t1 group by f1; +select * from v1; +f1 group_concat(f2 order by f2 asc) +1 1,2,3 +select * from v2; +f1 group_concat(f2 order by f2 desc) +1 3,2,1 +drop view v1,v2; +drop table t1; +create table t1 (x int, y int); +create table t2 (x int, y int, z int); +create table t3 (x int, y int, z int); +create table t4 (x int, y int, z int); +create view v1 as +select t1.x +from ( +(t1 join t2 on ((t1.y = t2.y))) +join +(t3 left join t4 on (t3.y = t4.y) and (t3.z = t4.z)) +); +prepare stmt1 from "select count(*) from v1 where x = ?"; +set @parm1=1; +execute stmt1 using @parm1; +count(*) +0 +execute stmt1 using @parm1; +count(*) +0 +drop view v1; +drop table t1,t2,t3,t4; +CREATE TABLE t1(id INT); +CREATE VIEW v1 AS SELECT id FROM t1; +OPTIMIZE TABLE v1; +Table Op Msg_type Msg_text +test.v1 optimize note Unknown table 'test.v1' +ANALYZE TABLE v1; +Table Op Msg_type Msg_text +test.v1 analyze note Unknown table 'test.v1' +REPAIR TABLE v1; +Table Op Msg_type Msg_text +test.v1 repair note Unknown table 'test.v1' +DROP TABLE t1; +OPTIMIZE TABLE v1; +Table Op Msg_type Msg_text +test.v1 optimize note Unknown table 'test.v1' +Warnings: +Error 1146 Table 'test.t1' doesn't exist +Error 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +DROP VIEW v1; diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test index 3167682f816..97d8f28cd3f 100644 --- a/mysql-test/t/bdb.test +++ b/mysql-test/t/bdb.test @@ -962,6 +962,7 @@ source include/varchar.inc; # Some errors/warnings on create # +--replace_result 1024 MAX_KEY_LENGTH 3072 MAX_KEY_LENGTH create table t1 (v varchar(65530), key(v)); drop table if exists t1; create table t1 (v varchar(65536)); diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test index d9c1abd9ba9..7871b3647e3 100644 --- a/mysql-test/t/bigint.test +++ b/mysql-test/t/bigint.test @@ -2,7 +2,7 @@ # Initialize --disable_warnings -drop table if exists t1; +drop table if exists t1, t2; --enable_warnings # diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index a867baa9fc9..fef9d4552e6 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -17,10 +17,10 @@ show tables; connect (con2,localhost,root,,test); show tables; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_PORT +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT --error 1045 connect (fail_con,localhost,root,z,test2); ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_PORT +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT --error 1045 connect (fail_con,localhost,root,z,); @@ -35,16 +35,16 @@ show tables; connect (con4,localhost,test,gambling,test); show tables; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_PORT +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT --error 1045 connect (fail_con,localhost,test,,test2); ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_PORT +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT --error 1045 connect (fail_con,localhost,test,,""); ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_PORT +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT --error 1045 connect (fail_con,localhost,test,zorro,test2); ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_PORT +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT --error 1045 connect (fail_con,localhost,test,zorro,); @@ -63,16 +63,16 @@ show tables; connect (con6,localhost,test,gambling3,test); show tables; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_PORT +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT --error 1045 connect (fail_con,localhost,test,,test2); ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_PORT +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT --error 1045 connect (fail_con,localhost,test,,); ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_PORT +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT --error 1045 connect (fail_con,localhost,test,zorro,test2); ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_PORT +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT --error 1045 connect (fail_con,localhost,test,zorro,); diff --git a/mysql-test/t/csv.test b/mysql-test/t/csv.test index 2ac46d75f9a..5b693335a43 100644 --- a/mysql-test/t/csv.test +++ b/mysql-test/t/csv.test @@ -1314,4 +1314,41 @@ select period from t1; drop table if exists t1,t2,t3,t4; +# +# Bug #13894 Server crashes on update of CSV table +# + +--disable_warnings +DROP TABLE IF EXISTS bug13894; +--enable_warnings + +CREATE TABLE bug13894 ( val integer ) ENGINE = CSV; +INSERT INTO bug13894 VALUES (5); +INSERT INTO bug13894 VALUES (10); +INSERT INTO bug13894 VALUES (11); +INSERT INTO bug13894 VALUES (10); +SELECT * FROM bug13894; +UPDATE bug13894 SET val=6 WHERE val=10; +SELECT * FROM bug13894; +DROP TABLE bug13894; + +# +# Bug #14672 Bug in deletion +# + +--disable_warnings +DROP TABLE IF EXISTS bug14672; +--enable_warnings + +CREATE TABLE bug14672 (c1 integer) engine = CSV; +INSERT INTO bug14672 VALUES (1), (2), (3); +SELECT * FROM bug14672; +DELETE FROM bug14672 WHERE c1 = 2; +SELECT * FROM bug14672; +INSERT INTO bug14672 VALUES (4); +SELECT * FROM bug14672; +INSERT INTO bug14672 VALUES (5); +SELECT * FROM bug14672; +DROP TABLE bug14672; + # End of 4.1 tests diff --git a/mysql-test/t/ctype_cp932_binlog.test b/mysql-test/t/ctype_cp932_binlog.test new file mode 100644 index 00000000000..270e27cf27f --- /dev/null +++ b/mysql-test/t/ctype_cp932_binlog.test @@ -0,0 +1,34 @@ +-- source include/not_embedded.inc +-- source include/have_cp932.inc + +--character_set cp932 +--disable_warnings +drop table if exists t1; +--enable_warnings + +set names cp932; +set character_set_database = cp932; + +# Test prepared statement with 0x8300 sequence in parameter while +# running with cp932 client character set. +RESET MASTER; +CREATE TABLE t1(f1 blob); +PREPARE stmt1 FROM 'INSERT INTO t1 VALUES(?)'; +SET @var1= x'8300'; +# TODO: Note that this doesn't actually test the code which was added for +# bug#11338 because this syntax for prepared statements causes the PS to +# be replicated differently than if we executed the PS from C or Java. +# Using this syntax, variable names are inserted into the binlog instead +# of values. The real goal of this test is to check the code that was +# added to Item_param::query_val_str() in order to do hex encoding of +# PS parameters when the client character set is cp932; +# Bug#11338 has an example java program which can be used to verify this +# code (and I have used it to test the fix) until there is some way to +# exercise this code from mysql-test-run. +EXECUTE stmt1 USING @var1; +SHOW BINLOG EVENTS FROM 98; +SELECT HEX(f1) FROM t1; +DROP table t1; +# end test for bug#11338 + +# End of 4.1 tests diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test index 0592ec3152f..9dbf153ec55 100644 --- a/mysql-test/t/join_nested.test +++ b/mysql-test/t/join_nested.test @@ -832,3 +832,71 @@ SELECT v2.x FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); DROP VIEW v1, v2; DROP TABLE t1, t2, t3, t4, t5, t6; + +# +# BUG#13126 -test case from bug report +# +create table t1 (id1 int(11) not null); +insert into t1 values (1),(2); + +create table t2 (id2 int(11) not null); +insert into t2 values (1),(2),(3),(4); + +create table t3 (id3 char(16) not null); +insert into t3 values ('100'); + +create table t4 (id2 int(11) not null, id3 char(16)); + +create table t5 (id1 int(11) not null, key (id1)); +insert into t5 values (1),(2),(1); + +create view v1 as + select t4.id3 from t4 join t2 on t4.id2 = t2.id2; + +select t1.id1 from t1 inner join (t3 left join v1 on t3.id3 = v1.id3); + +drop view v1; +drop table t1, t2, t3, t4, t5; + +create table t0 (a int); +insert into t0 values (0),(1),(2),(3); +create table t1(a int); +insert into t1 select A.a + 10*(B.a) from t0 A, t0 B; + +create table t2 (a int, b int); +insert into t2 values (1,1), (2,2), (3,3); + +create table t3(a int, b int, filler char(200), key(a)); +insert into t3 select a,a,'filler' from t1; +insert into t3 select a,a,'filler' from t1; + +create table t4 like t3; +insert into t4 select * from t3; +insert into t4 select * from t3; + +create table t5 like t4; +insert into t5 select * from t4; +insert into t5 select * from t4; + +create table t6 like t5; +insert into t6 select * from t5; +insert into t6 select * from t5; + +create table t7 like t6; +insert into t7 select * from t6; +insert into t7 select * from t6; + +--replace_column 9 X +explain select * from t4 join + t2 left join (t3 join t5 on t5.a=t3.b) on t3.a=t2.b where t4.a<=>t3.b; + +--replace_column 9 X +explain select * from (t4 join t6 on t6.a=t4.b) right join t3 on t4.a=t3.b + join t2 left join (t5 join t7 on t7.a=t5.b) on t5.a=t2.b where t3.a<=>t2.b; + +--replace_column 9 X +explain select * from t2 left join + (t3 left join (t4 join t6 on t6.a=t4.b) on t4.a=t3.b + join t5 on t5.a=t3.b) on t3.a=t2.b; + +drop table t0, t1, t2, t4, t5, t6; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 4481bc62dfa..91a87e2c774 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -917,6 +917,7 @@ DROP FUNCTION bug9056_func1; DROP FUNCTION bug9056_func2; DROP PROCEDURE bug9056_proc1; DROP PROCEDURE bug9056_proc2; +DROP PROCEDURE `a'b`; drop table t1; # diff --git a/mysql-test/t/ndb_basic.test b/mysql-test/t/ndb_basic.test index 1c78a4b8744..1a351018b8d 100644 --- a/mysql-test/t/ndb_basic.test +++ b/mysql-test/t/ndb_basic.test @@ -615,3 +615,12 @@ create table atablewithareallylongandirritatingname (a int); insert into atablewithareallylongandirritatingname values (2); select * from atablewithareallylongandirritatingname; drop table atablewithareallylongandirritatingname; + + +# +# BUG#14514 +# + +CREATE TABLE t1 ( b INT ) PACK_KEYS = 0 ENGINE = ndb; +select * from t1; +drop table t1; diff --git a/mysql-test/t/read_only.test b/mysql-test/t/read_only.test new file mode 100644 index 00000000000..0861951a6a1 --- /dev/null +++ b/mysql-test/t/read_only.test @@ -0,0 +1,103 @@ +# Test of the READ_ONLY global variable: +# check that it blocks updates unless they are only on temporary tables. + +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3; +--enable_warnings + +# READ_ONLY does nothing to SUPER users +# so we use a non-SUPER one: + +grant CREATE, SELECT, DROP on *.* to test@localhost; + +connect (con1,localhost,test,,test); + +connection default; + +set global read_only=0; + +connection con1; + +create table t1 (a int); + +insert into t1 values(1); + +create table t2 select * from t1; + +connection default; + +set global read_only=1; + +# We check that SUPER can: + +create table t3 (a int); +drop table t3; + +connection con1; + +select @@global.read_only; + +--error 1290 +create table t3 (a int); + +--error 1290 +insert into t1 values(1); + +# if a statement, after parse stage, looks like it will update a +# non-temp table, it will be rejected, even if at execution it would +# have turned out that 0 rows would be updated +--error 1290 +update t1 set a=1 where 1=0; + +# multi-update is special (see sql_parse.cc) so we test it +--error 1290 +update t1,t2 set t1.a=t2.a+1 where t1.a=t2.a; + +# check multi-delete to be sure +--error 1290 +delete t1,t2 from t1,t2 where t1.a=t2.a; + +# With temp tables updates should be accepted: + +create temporary table t3 (a int); + +create temporary table t4 (a int) select * from t3; + +insert into t3 values(1); + +insert into t4 select * from t3; + +# a non-temp table updated: +--error 1290 +update t1,t3 set t1.a=t3.a+1 where t1.a=t3.a; + +# no non-temp table updated (just swapped): +update t1,t3 set t3.a=t1.a+1 where t1.a=t3.a; + +update t4,t3 set t4.a=t3.a+1 where t4.a=t3.a; + +--error 1290 +delete t1 from t1,t3 where t1.a=t3.a; + +delete t3 from t1,t3 where t1.a=t3.a; + +delete t4 from t3,t4 where t4.a=t3.a; + +# and even homonymous ones + +create temporary table t1 (a int); + +insert into t1 values(1); + +update t1,t3 set t1.a=t3.a+1 where t1.a=t3.a; + +delete t1 from t1,t3 where t1.a=t3.a; + +drop table t1; + +--error 1290 +insert into t1 values(1); + +connection default; +drop table t1,t2; +drop user test@localhost; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index d38371577d9..e7e6d899a66 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2711,3 +2711,21 @@ select * from t1 join t2 left join t3 on (t1.a=t3.c); select * from t1 join t2 right join t3 on (t1.a=t3.c); select * from t1 join t2 straight_join t3 on (t1.a=t3.c); drop table t1, t2 ,t3; + +# +# Bug #14093 Query takes a lot of time when date format is not valid +# fix optimizes execution. so here we just check that returned set is +# correct. +create table t1(f1 int, f2 date); +insert into t1 values(1,'2005-01-01'),(2,'2005-09-01'),(3,'2005-09-30'), + (4,'2005-10-01'),(5,'2005-12-30'); +# should return all records +select * from t1 where f2 >= 0; +select * from t1 where f2 >= '0000-00-00'; +# should return 4,5 +select * from t1 where f2 >= '2005-09-31'; +select * from t1 where f2 >= '2005-09-3a'; +# should return 1,2,3 +select * from t1 where f2 <= '2005-09-31'; +select * from t1 where f2 <= '2005-09-3a'; +drop table t1; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index ab57139bb77..eaf69c0ab03 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4488,6 +4488,58 @@ DROP TABLE IF EXISTS bug13095_t1; delimiter |; +# +# BUG#14210: "Simple query with > operator on large table gives server +# crash" +# Check that cursors work in case when HEAP tables are converted to +# MyISAM +# +--disable_warnings +drop procedure if exists bug14210| +--enable_warnings +set @@session.max_heap_table_size=16384| +select @@session.max_heap_table_size| +# To trigger the memory corruption the original table must be InnoDB. +# No harm if it's not, so don't warn if the suite is run with --skip-innodb +--disable_warnings +create table t3 (a char(255)) engine=InnoDB| +--enable_warnings +create procedure bug14210_fill_table() +begin + declare table_size, max_table_size int default 0; + select @@session.max_heap_table_size into max_table_size; + delete from t3; + insert into t3 (a) values (repeat('a', 255)); + repeat + insert into t3 select a from t3; + select count(*)*255 from t3 into table_size; + until table_size > max_table_size*2 end repeat; +end| +call bug14210_fill_table()| +drop procedure bug14210_fill_table| +create table t4 like t3| + +create procedure bug14210() +begin + declare a char(255); + declare done int default 0; + declare c cursor for select * from t3; + declare continue handler for sqlstate '02000' set done = 1; + open c; + repeat + fetch c into a; + if not done then + insert into t4 values (upper(a)); + end if; + until done end repeat; + close c; +end| +call bug14210()| +select count(*) from t4| + +drop table t3, t4| +drop procedure bug14210| +set @@session.max_heap_table_size=default| # # BUG#NNNN: New bug synopsis diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index a7087d46dca..93a1a1afa45 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -1050,3 +1050,19 @@ select cast(@non_existing_user_var/2 as DECIMAL); # --error 1427 create table t (d decimal(0,10)); + +# +# Bug #13573 (Wrong data inserted for too big values) +# + +create table t1 (c1 decimal(64)); +--disable_ps_protocol +insert into t1 values( +89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000); +insert into t1 values( +99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * +99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999); +--enable_ps_protocol +insert into t1 values(1e100); +select * from t1; +drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index aa3189bad69..4e287375e5d 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1,5 +1,5 @@ --disable_warnings -drop table if exists t1,t2,t9,`t1a``b`,v1,v2,v3,v4,v5,v6; +drop table if exists t1,t2,t3,t4,t9,`t1a``b`,v1,v2,v3,v4,v5,v6; drop view if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6; drop database if exists mysqltest; --enable_warnings @@ -2189,4 +2189,54 @@ EXPLAIN SELECT * FROM v2 WHERE a=1; DROP VIEW v1,v2; DROP TABLE t1,t2,t3; +# +# Bug #14466 lost sort order in GROUP_CONCAT() in a view +# +create table t1 (f1 int, f2 int); +insert into t1 values(1,1),(1,2),(1,3); +create view v1 as select f1 ,group_concat(f2 order by f2 asc) from t1 group by f1; +create view v2 as select f1 ,group_concat(f2 order by f2 desc) from t1 group by f1; +select * from v1; +select * from v2; +drop view v1,v2; +drop table t1; +# +# BUG#14026 Crash on second PS execution when using views +# +create table t1 (x int, y int); +create table t2 (x int, y int, z int); +create table t3 (x int, y int, z int); +create table t4 (x int, y int, z int); + +create view v1 as +select t1.x +from ( + (t1 join t2 on ((t1.y = t2.y))) + join + (t3 left join t4 on (t3.y = t4.y) and (t3.z = t4.z)) +); + +prepare stmt1 from "select count(*) from v1 where x = ?"; +set @parm1=1; + +execute stmt1 using @parm1; +execute stmt1 using @parm1; +drop view v1; +drop table t1,t2,t3,t4; + +# +# Bug #14540: OPTIMIZE, ANALYZE, REPAIR applied to not a view +# + +CREATE TABLE t1(id INT); +CREATE VIEW v1 AS SELECT id FROM t1; + +OPTIMIZE TABLE v1; +ANALYZE TABLE v1; +REPAIR TABLE v1; + +DROP TABLE t1; +OPTIMIZE TABLE v1; + +DROP VIEW v1; diff --git a/mysys/base64.c b/mysys/base64.c index 0165982fb67..c521f352690 100644 --- a/mysys/base64.c +++ b/mysys/base64.c @@ -134,7 +134,7 @@ base64_decode(const char *src, size_t size, void *dst) { char b[3]; size_t i= 0; - void *d= dst; + unsigned char *d= (unsigned char*)dst; size_t j; while (i < size) @@ -186,14 +186,14 @@ base64_decode(const char *src, size_t size, void *dst) b[2]= (c >> 0) & 0xff; for (j=0; j<3-mark; j++) - *(char *)d++= b[j]; + *d++= b[j]; } if (i != size) { return -1; } - return d - dst; + return d - (unsigned char*)dst; } diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc index 25609f489af..83f13b34aa2 100644 --- a/server-tools/instance-manager/instance_options.cc +++ b/server-tools/instance-manager/instance_options.cc @@ -47,14 +47,12 @@ static inline int create_mysqld_command(Buffer *buf, if (buf->get_size()) /* malloc succeeded */ { #ifdef __WIN__ - buf->append(position, "\"", 1); - position++; + buf->append(position++, "\"", 1); #endif buf->append(position, mysqld_path_str, mysqld_path_len); position+= mysqld_path_len; #ifdef __WIN__ - buf->append(position, "\"", 1); - position++; + buf->append(position++, "\"", 1); #endif /* here the '\0' character is copied from the option string */ buf->append(position, option, option_len); @@ -336,10 +334,15 @@ int Instance_options::complete_initialization(const char *default_path, uint instance_type) { const char *tmp; + char *end; if (!mysqld_path && !(mysqld_path= strdup_root(&alloc, default_path))) goto err; + // it's safe to cast this to char* since this is a buffer we are allocating + end= convert_dirname((char*)mysqld_path, mysqld_path, NullS); + end[-1]= 0; + mysqld_path_len= strlen(mysqld_path); if (mysqld_port) diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc index b5af3cb83a7..ebc45c1f7d4 100644 --- a/server-tools/instance-manager/parse_output.cc +++ b/server-tools/instance-manager/parse_output.cc @@ -24,6 +24,20 @@ #include "portability.h" +void trim_space(const char **text, uint *word_len) +{ + const char *start= *text; + while (*start != 0 && *start == ' ') + start++; + *text= start; + + int len= strlen(start); + const char *end= start + len - 1; + while (end > start && my_isspace(&my_charset_latin1, *end)) + end--; + *word_len= (end - start)+1; +} + /* Parse output of the given command @@ -82,20 +96,17 @@ int parse_output_and_get_value(const char *command, const char *word, linebuf[sizeof(linebuf) - 1]= '\0'; /* safety */ /* - Get the word, which might contain non-alphanumeric characters. (Usually - these are '/', '-' and '.' in the path expressions and filenames) + Compare the start of our line with the word(s) we are looking for. */ - get_word((const char **) &linep, &found_word_len, NONSPACE); if (!strncmp(word, linep, wordlen)) { /* - If we have found the word, return the next one (this is usually - an option value) or the whole line (if flag) + If we have found our word(s), then move linep past the word(s) */ - linep+= found_word_len; /* swallow the previous one */ + linep+= wordlen; if (flag & GET_VALUE) { - get_word((const char **) &linep, &found_word_len, NONSPACE); + trim_space((const char**) &linep, &found_word_len); if (input_buffer_len <= found_word_len) goto err; strmake(result, linep, found_word_len); diff --git a/server-tools/instance-manager/priv.cc b/server-tools/instance-manager/priv.cc index cf073d9d7dc..a5040aa2e83 100644 --- a/server-tools/instance-manager/priv.cc +++ b/server-tools/instance-manager/priv.cc @@ -73,8 +73,9 @@ unsigned long open_files_limit; int set_stacksize_n_create_thread(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { - int rc; + int rc= 0; +#ifndef __WIN__ /* Set stack size to be safe on the platforms with too small default thread stack. @@ -82,7 +83,7 @@ int set_stacksize_n_create_thread(pthread_t *thread, pthread_attr_t *attr, rc= pthread_attr_setstacksize(attr, (size_t) (PTHREAD_STACK_MIN + IM_THREAD_STACK_SIZE)); - +#endif if (!rc) rc= pthread_create(thread, attr, start_routine, arg); return rc; diff --git a/server-tools/instance-manager/priv.h b/server-tools/instance-manager/priv.h index db6fa2ec143..4739bca68eb 100644 --- a/server-tools/instance-manager/priv.h +++ b/server-tools/instance-manager/priv.h @@ -22,7 +22,7 @@ #else #include #endif - +#include "my_pthread.h" /* the pid of the manager process (of the signal thread on the LinuxThreads) */ extern pid_t manager_pid; diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 541e91f4b46..e00657c66ba 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -82,12 +82,16 @@ handlerton tina_hton= { ** TINA tables *****************************************************************************/ -/* - Used for sorting chains. +/* + Used for sorting chains with qsort(). */ int sort_set (tina_set *a, tina_set *b) { - return ( a->begin > b->begin ? 1 : ( a->begin < b->begin ? -1 : 0 ) ); + /* + We assume that intervals do not intersect. So, it is enought to compare + any two points. Here we take start of intervals for comparison. + */ + return ( a->begin > b->begin ? -1 : ( a->begin < b->begin ? 1 : 0 ) ); } static byte* tina_get_key(TINA_SHARE *share,uint *length, @@ -186,7 +190,8 @@ static TINA_SHARE *get_share(const char *table_name, TABLE *table) thr_lock_init(&share->lock); pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST); - if ((share->data_file= my_open(data_file_name, O_RDWR, MYF(0))) == -1) + if ((share->data_file= my_open(data_file_name, O_RDWR|O_APPEND, + MYF(0))) == -1) goto error2; /* We only use share->data_file for writing, so we scan to the end to append */ @@ -797,13 +802,8 @@ int ha_tina::rnd_end() qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), (qsort_cmp)sort_set); for (ptr= chain; ptr < chain_ptr; ptr++) { - /* We peek a head to see if this is the last chain */ - if (ptr+1 == chain_ptr) - memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end, - length - (size_t)ptr->end); - else - memmove((caddr_t)share->mapped_file + ptr->begin, (caddr_t)share->mapped_file + ptr->end, - (size_t)((ptr++)->begin - ptr->end)); + memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end, + length - (size_t)ptr->end); length= length - (size_t)(ptr->end - ptr->begin); } diff --git a/sql/field.cc b/sql/field.cc index 03d20b4bfe2..381a13c3263 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6202,9 +6202,16 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table) This is done to ensure that ALTER TABLE will convert old VARCHAR fields to now VARCHAR fields. */ - return new Field_varstring(field_length, maybe_null(), - field_name, new_table, - charset()); + Field *new_field= new Field_varstring(field_length, maybe_null(), + field_name, new_table, + charset()); + /* + delayed_insert::get_local_table() needs a ptr copied from old table. + This is what other new_field() methods do too. The above method of + Field_varstring sets ptr to NULL. + */ + new_field->ptr= ptr; + return new_field; } /**************************************************************************** @@ -7931,7 +7938,7 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs) { int delta; - for (; !*from && length; from++, length--); // skip left 0's + for (; length && !*from; from++, length--); // skip left 0's delta= field_length - length; if (delta < -1 || @@ -8151,7 +8158,7 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs) int delta; uchar bits= create_length & 7; - for (; !*from && length; from++, length--); // skip left 0's + for (; length && !*from; from++, length--); // skip left 0's delta= field_length - length; if (delta < 0 || diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index 99e13286554..16e4db59c10 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -94,8 +94,8 @@ class ha_berkeley: public handler uint max_supported_keys() const { return MAX_KEY-1; } uint extra_rec_buf_length() { return BDB_HIDDEN_PRIMARY_KEY_LENGTH; } ha_rows estimate_rows_upper_bound(); - uint max_supported_key_length() const { return 4294967295L; } - uint max_supported_key_part_length() const { return 4294967295L; } + uint max_supported_key_length() const { return UINT_MAX32; } + uint max_supported_key_part_length() const { return UINT_MAX32; } const key_map *keys_to_use_for_scanning() { return &key_map_full; } bool has_transactions() { return 1;} diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 4248230abbe..80c34f1117f 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -3861,7 +3861,8 @@ int ha_ndbcluster::create(const char *name, uint pack_length, length, i, pk_length= 0; const void *data, *pack_data; char name2[FN_HEADLEN]; - bool create_from_engine= (info->table_options & HA_CREATE_FROM_ENGINE); + bool create_from_engine= test(info->table_options & + HA_OPTION_CREATE_FROM_ENGINE); DBUG_ENTER("ha_ndbcluster::create"); DBUG_PRINT("enter", ("name: %s", name)); diff --git a/sql/handler.cc b/sql/handler.cc index 81e94af5dc7..7724b27949e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -293,61 +293,61 @@ enum db_type ha_checktype(THD *thd, enum db_type database_type, } /* ha_checktype */ -handler *get_new_handler(TABLE *table, enum db_type db_type) +handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type) { switch (db_type) { #ifndef NO_HASH case DB_TYPE_HASH: - return new ha_hash(table); + return new (alloc) ha_hash(table); #endif case DB_TYPE_MRG_ISAM: - return new ha_myisammrg(table); + return new (alloc) ha_myisammrg(table); #ifdef HAVE_BERKELEY_DB case DB_TYPE_BERKELEY_DB: - return new ha_berkeley(table); + return new (alloc) ha_berkeley(table); #endif #ifdef HAVE_INNOBASE_DB case DB_TYPE_INNODB: - return new ha_innobase(table); + return new (alloc) ha_innobase(table); #endif #ifdef HAVE_EXAMPLE_DB case DB_TYPE_EXAMPLE_DB: - return new ha_example(table); + return new (alloc) ha_example(table); #endif #ifdef HAVE_ARCHIVE_DB case DB_TYPE_ARCHIVE_DB: - return new ha_archive(table); + return new (alloc) ha_archive(table); #endif #ifdef HAVE_BLACKHOLE_DB case DB_TYPE_BLACKHOLE_DB: - return new ha_blackhole(table); + return new (alloc) ha_blackhole(table); #endif #ifdef HAVE_FEDERATED_DB case DB_TYPE_FEDERATED_DB: - return new ha_federated(table); + return new (alloc) ha_federated(table); #endif #ifdef HAVE_CSV_DB case DB_TYPE_CSV_DB: - return new ha_tina(table); + return new (alloc) ha_tina(table); #endif #ifdef HAVE_NDBCLUSTER_DB case DB_TYPE_NDBCLUSTER: - return new ha_ndbcluster(table); + return new (alloc) ha_ndbcluster(table); #endif case DB_TYPE_HEAP: - return new ha_heap(table); + return new (alloc) ha_heap(table); default: // should never happen { enum db_type def=(enum db_type) current_thd->variables.table_type; /* Try first with 'default table type' */ if (db_type != def) - return get_new_handler(table, def); + return get_new_handler(table, alloc, def); } /* Fall back to MyISAM */ case DB_TYPE_MYISAM: - return new ha_myisam(table); + return new (alloc) ha_myisam(table); case DB_TYPE_MRG_MYISAM: - return new ha_myisammrg(table); + return new (alloc) ha_myisammrg(table); } } @@ -1300,7 +1300,7 @@ int ha_delete_table(THD *thd, enum db_type table_type, const char *path, /* DB_TYPE_UNKNOWN is used in ALTER TABLE when renaming only .frm files */ if (table_type == DB_TYPE_UNKNOWN || - ! (file=get_new_handler(&dummy_table, table_type))) + ! (file=get_new_handler(&dummy_table, thd->mem_root, table_type))) DBUG_RETURN(ENOENT); if (lower_case_table_names == 2 && !(file->table_flags() & HA_FILE_BASED)) @@ -2016,7 +2016,7 @@ int ha_create_table_from_engine(THD* thd, DBUG_RETURN(3); update_create_info_from_table(&create_info, &table); - create_info.table_options|= HA_CREATE_FROM_ENGINE; + create_info.table_options|= HA_OPTION_CREATE_FROM_ENGINE; if (lower_case_table_names == 2 && !(table.file->table_flags() & HA_FILE_BASED)) @@ -2469,6 +2469,7 @@ int handler::index_read_idx(byte * buf, uint index, const byte * key, TYPELIB *ha_known_exts(void) { + MEM_ROOT *mem_root= current_thd->mem_root; if (!known_extensions.type_names || mysys_usage_id != known_extensions_id) { handlerton **types; @@ -2483,7 +2484,8 @@ TYPELIB *ha_known_exts(void) { if ((*types)->state == SHOW_OPTION_YES) { - handler *file= get_new_handler(0,(enum db_type) (*types)->db_type); + handler *file= get_new_handler(0, mem_root, + (enum db_type) (*types)->db_type); for (ext= file->bas_ext(); *ext; ext++) { while ((old_ext= it++)) diff --git a/sql/handler.h b/sql/handler.h index af80f021e75..e317f95b990 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -45,6 +45,7 @@ #define HA_ADMIN_REJECT -6 #define HA_ADMIN_TRY_ALTER -7 #define HA_ADMIN_WRONG_CHECKSUM -8 +#define HA_ADMIN_NOT_BASE_TABLE -9 /* Bits in table_flags() to show what database can do */ @@ -874,7 +875,7 @@ extern ulong total_ha, total_ha_2pc; /* lookups */ enum db_type ha_resolve_by_name(const char *name, uint namelen); const char *ha_get_storage_engine(enum db_type db_type); -handler *get_new_handler(TABLE *table, enum db_type db_type); +handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type); enum db_type ha_checktype(THD *thd, enum db_type database_type, bool no_substitute, bool report_error); bool ha_check_storage_engine_flag(enum db_type db_type, uint32 flag); diff --git a/sql/item.h b/sql/item.h index 2f753564009..8bc659c3060 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1750,6 +1750,7 @@ public: return ref->save_in_field(field, no_conversions); } Item *new_item(); + virtual Item *real_item() { return ref; } }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 761d15c8a3e..06cb83a7101 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -186,13 +186,18 @@ static bool convert_constant_item(THD *thd, Field *field, Item **item) { if ((*item)->const_item()) { + /* For comparison purposes allow invalid dates like 2000-01-32 */ + ulong orig_sql_mode= field->table->in_use->variables.sql_mode; + field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES; if (!(*item)->save_in_field(field, 1) && !((*item)->null_value)) { Item *tmp=new Item_int_with_ref(field->val_int(), *item); + field->table->in_use->variables.sql_mode= orig_sql_mode; if (tmp) thd->change_item_tree(item, tmp); return 1; // Item was replaced } + field->table->in_use->variables.sql_mode= orig_sql_mode; } return 0; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 057f9b84a84..f467981540b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -972,8 +972,8 @@ my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value) return 0; val2= args[1]->val_decimal(&value2); if (!(null_value= (args[1]->null_value || - my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1, - val2) > 1))) + (my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1, + val2) > 3)))) return decimal_value; return 0; } @@ -1045,8 +1045,8 @@ my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value) return 0; val2= args[1]->val_decimal(&value2); if (!(null_value= (args[1]->null_value || - my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1, - val2) > 1))) + (my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1, + val2) > 3)))) return decimal_value; return 0; } @@ -1083,8 +1083,8 @@ my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value) return 0; val2= args[1]->val_decimal(&value2); if (!(null_value= (args[1]->null_value || - my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1, - val2) > 1))) + (my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1, + val2) > 3)))) return decimal_value; return 0; } @@ -1124,6 +1124,7 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value) { my_decimal value1, *val1; my_decimal value2, *val2; + int err; val1= args[0]->val_decimal(&value1); if ((null_value= args[0]->null_value)) @@ -1131,17 +1132,15 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value) val2= args[1]->val_decimal(&value2); if ((null_value= args[1]->null_value)) return 0; - switch (my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, - val1, val2, prec_increment)) { - case E_DEC_TRUNCATED: - case E_DEC_OK: - return decimal_value; - case E_DEC_DIV_ZERO: - signal_divide_by_null(); - default: - null_value= 1; // Safety + if ((err= my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, + val1, val2, prec_increment)) > 3) + { + if (err == E_DEC_DIV_ZERO) + signal_divide_by_null(); + null_value= 1; return 0; } + return decimal_value; } @@ -1378,7 +1377,6 @@ my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value) void Item_func_abs::fix_length_and_dec() { Item_func_num1::fix_length_and_dec(); - maybe_null= 1; } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index b56d99cf245..b2eaf39d624 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3173,6 +3173,10 @@ void Item_func_group_concat::print(String *str) if (i) str->append(','); (*order[i]->item)->print(str); + if (order[i]->asc) + str->append(" ASC"); + else + str->append(" DESC"); } } str->append(" separator \'", 12); diff --git a/sql/log.cc b/sql/log.cc index f9f71e2d55a..7ea2dba2144 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -356,9 +356,10 @@ static int find_uniq_filename(char *name) MYSQL_LOG::MYSQL_LOG() :bytes_written(0), last_time(0), query_start(0), name(0), - file_id(1), open_count(1), log_type(LOG_CLOSED), write_error(0), inited(0), - need_start_event(1), prepared_xids(0), description_event_for_exec(0), - description_event_for_queue(0), readers_count(0), reset_pending(FALSE) + prepared_xids(0), log_type(LOG_CLOSED), file_id(1), open_count(1), + readers_count(0), reset_pending(FALSE), write_error(FALSE), inited(FALSE), + need_start_event(TRUE), + description_event_for_exec(0), description_event_for_queue(0) { /* We don't want to initialize LOCK_Log here as such initialization depends on @@ -2074,7 +2075,10 @@ void MYSQL_LOG::wait_for_update(THD* thd, bool is_slave) DBUG_ENTER("wait_for_update"); if (reset_pending) + { + pthread_mutex_unlock(&LOCK_log); DBUG_VOID_RETURN; + } old_msg= thd->enter_cond(&update_cond, &LOCK_log, is_slave ? diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index f188d27ff78..1bd16940b47 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -185,7 +185,7 @@ int str2my_decimal(uint mask, const char *from, uint length, } } } - check_result(mask, err); + check_result_and_overflow(mask, err, decimal_value); return err; } diff --git a/sql/my_decimal.h b/sql/my_decimal.h index b65e6aedaa2..b02abacf0a3 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -126,6 +126,19 @@ inline int decimal_operation_results(int result) } #endif /*MYSQL_CLIENT*/ +inline +void max_my_decimal(my_decimal *to, int precision, int frac) +{ + DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION)&& + (frac <= DECIMAL_MAX_SCALE)); + max_decimal(precision, frac, (decimal_t*) to); +} + +inline void max_internal_decimal(my_decimal *to) +{ + max_my_decimal(to, DECIMAL_MAX_PRECISION, 0); +} + inline int check_result(uint mask, int result) { if (result & mask) @@ -133,6 +146,18 @@ inline int check_result(uint mask, int result) return result; } +inline int check_result_and_overflow(uint mask, int result, my_decimal *val) +{ + if (check_result(mask, result) & E_DEC_OVERFLOW) + { + bool sign= val->sign(); + val->fix_buffer_pointer(); + max_internal_decimal(val); + val->sign(sign); + } + return result; +} + inline uint my_decimal_length_to_precision(uint length, uint scale, bool unsigned_flag) { @@ -256,7 +281,8 @@ int my_decimal2double(uint mask, const my_decimal *d, double *result) inline int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end) { - return check_result(mask, string2decimal(str, (decimal_t*) d, end)); + return check_result_and_overflow(mask, string2decimal(str,(decimal_t*)d,end), + d); } @@ -274,7 +300,7 @@ int string2my_decimal(uint mask, const String *str, my_decimal *d) inline int double2my_decimal(uint mask, double val, my_decimal *d) { - return check_result(mask, double2decimal(val, (decimal_t*) d)); + return check_result_and_overflow(mask, double2decimal(val, (decimal_t*)d), d); } @@ -303,7 +329,9 @@ inline int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { - return check_result(mask, decimal_add((decimal_t*) a, (decimal_t*) b, res)); + return check_result_and_overflow(mask, + decimal_add((decimal_t*)a,(decimal_t*)b,res), + res); } @@ -311,7 +339,9 @@ inline int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { - return check_result(mask, decimal_sub((decimal_t*) a, (decimal_t*) b, res)); + return check_result_and_overflow(mask, + decimal_sub((decimal_t*)a,(decimal_t*)b,res), + res); } @@ -319,7 +349,9 @@ inline int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { - return check_result(mask, decimal_mul((decimal_t*) a, (decimal_t*) b, res)); + return check_result_and_overflow(mask, + decimal_mul((decimal_t*)a,(decimal_t*)b,res), + res); } @@ -327,8 +359,10 @@ inline int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b, int div_scale_inc) { - return check_result(mask, decimal_div((decimal_t*) a, (decimal_t*) b, res, - div_scale_inc)); + return check_result_and_overflow(mask, + decimal_div((decimal_t*)a,(decimal_t*)b,res, + div_scale_inc), + res); } @@ -336,7 +370,9 @@ inline int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { - return check_result(mask, decimal_mod((decimal_t*) a, (decimal_t*) b, res)); + return check_result_and_overflow(mask, + decimal_mod((decimal_t*)a,(decimal_t*)b,res), + res); } @@ -347,13 +383,5 @@ int my_decimal_cmp(const my_decimal *a, const my_decimal *b) return decimal_cmp((decimal_t*) a, (decimal_t*) b); } -inline -void max_my_decimal(my_decimal *to, int precision, int frac) -{ - DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION)&& - (frac <= DECIMAL_MAX_SCALE)); - max_decimal(precision, frac, (decimal_t*) to); -} - #endif /*my_decimal_h*/ diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 5f1d0fe18db..b7bd34c613f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -44,6 +44,12 @@ typedef ulonglong table_map; /* Used for table bits in join */ typedef Bitmap<64> key_map; /* Used for finding keys */ typedef ulong key_part_map; /* Used for finding key parts */ +/* + Used to identify NESTED_JOIN structures within a join (applicable only to + structures that have not been simplified away and embed more the one + element) +*/ +typedef ulonglong nested_join_map; /* query_id */ typedef ulonglong query_id_t; @@ -1297,7 +1303,6 @@ int openfrm(THD *thd, const char *name,const char *alias,uint filestat, int readfrm(const char *name, const void** data, uint* length); int writefrm(const char* name, const void* data, uint len); int closefrm(TABLE *table); -db_type get_table_type(THD *thd, const char *name); int read_string(File file, gptr *to, uint length); void free_blobs(TABLE *table); int set_zone(int nr,int min_zone,int max_zone); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 143ed74e012..acad378353b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1194,6 +1194,7 @@ static void clean_up_mutexes() (void) rwlock_destroy(&LOCK_sys_init_slave); (void) pthread_mutex_destroy(&LOCK_global_system_variables); (void) pthread_mutex_destroy(&LOCK_global_read_lock); + (void) pthread_mutex_destroy(&LOCK_uuid_generator); (void) pthread_cond_destroy(&COND_thread_count); (void) pthread_cond_destroy(&COND_refresh); (void) pthread_cond_destroy(&COND_thread_cache); @@ -3033,6 +3034,23 @@ server."); sql_print_error("Can't init databases"); unireg_abort(1); } + + /* + Check that the default storage engine is actually available. + */ + if (!ha_storage_engine_is_enabled((enum db_type) + global_system_variables.table_type)) + { + if (!opt_bootstrap) + { + sql_print_error("Default storage engine (%s) is not available", + ha_get_storage_engine((enum db_type) + global_system_variables.table_type)); + unireg_abort(1); + } + global_system_variables.table_type= DB_TYPE_MYISAM; + } + tc_log= (total_ha_2pc > 1 ? (opt_bin_log ? (TC_LOG *) &mysql_bin_log : (TC_LOG *) &tc_log_mmap) : @@ -6999,22 +7017,6 @@ static void get_options(int argc,char **argv) !opt_slow_log) sql_print_warning("options --log-slow-admin-statements and --log-queries-not-using-indexes have no effect if --log-slow-queries is not set"); - /* - Check that the default storage engine is actually available. - */ - if (!ha_storage_engine_is_enabled((enum db_type) - global_system_variables.table_type)) - { - if (!opt_bootstrap) - { - sql_print_error("Default storage engine (%s) is not available", - ha_get_storage_engine((enum db_type) - global_system_variables.table_type)); - exit(1); - } - global_system_variables.table_type= DB_TYPE_MYISAM; - } - if (argc > 0) { fprintf(stderr, "%s: Too many arguments (first extra is '%s').\nUse --help to get a list of available options\n", my_progname, *argv); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index ff2b14a27ee..63a49a46110 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -931,7 +931,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) } THD *thd= current_thd; - if (!(file= get_new_handler(head, head->s->db_type))) + if (!(file= get_new_handler(head, thd->mem_root, head->s->db_type))) goto failure; DBUG_PRINT("info", ("Allocated new handler %p", file)); if (file->ha_open(head->s->path, head->db_stat, HA_OPEN_IGNORE_IF_LOCKED)) @@ -3776,6 +3776,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, SEL_ARG *tree= 0; MEM_ROOT *alloc= param->mem_root; char *str; + ulong orig_sql_mode; DBUG_ENTER("get_mm_leaf"); /* @@ -3921,13 +3922,20 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, value->result_type() != STRING_RESULT && field->cmp_type() != value->result_type()) goto end; - + /* For comparison purposes allow invalid dates like 2000-01-32 */ + orig_sql_mode= field->table->in_use->variables.sql_mode; + if (value->real_item()->type() == Item::STRING_ITEM && + (field->type() == FIELD_TYPE_DATE || + field->type() == FIELD_TYPE_DATETIME)) + field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES; if (value->save_in_field_no_warnings(field, 1) < 0) { + field->table->in_use->variables.sql_mode= orig_sql_mode; /* This happens when we try to insert a NULL field in a not null column */ tree= &null_element; // cmp with NULL is never TRUE goto end; } + field->table->in_use->variables.sql_mode= orig_sql_mode; str= (char*) alloc_root(alloc, key_part->store_length+1); if (!str) goto end; diff --git a/sql/spatial.h b/sql/spatial.h index 6189d5c1462..4253689c078 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -245,8 +245,8 @@ public: static Geometry *create_from_wkt(Geometry_buffer *buffer, Gis_read_stream *trs, String *wkt, bool init_stream=1); - static int Geometry::create_from_wkb(Geometry_buffer *buffer, - const char *wkb, uint32 len, String *res); + static int create_from_wkb(Geometry_buffer *buffer, + const char *wkb, uint32 len, String *res); int as_wkt(String *wkt, const char **end) { uint32 len= get_class_info()->m_name.length; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5c929dcdf69..1e7fce9001f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1193,10 +1193,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, */ { char path[FN_REFLEN]; + db_type not_used; strxnmov(path, FN_REFLEN, mysql_data_home, "/", table_list->db, "/", table_list->table_name, reg_ext, NullS); (void) unpack_filename(path, path); - if (mysql_frm_type(path) == FRMTYPE_VIEW) + if (mysql_frm_type(thd, path, ¬_used) == FRMTYPE_VIEW) { TABLE tab;// will not be used (because it's VIEW) but have to be passed table= &tab; @@ -2634,7 +2635,7 @@ bool rm_temporary_table(enum db_type base, char *path) if (my_delete(path,MYF(0))) error=1; /* purecov: inspected */ *fn_ext(path)='\0'; // remove extension - handler *file=get_new_handler((TABLE*) 0, base); + handler *file= get_new_handler((TABLE*) 0, current_thd->mem_root, base); if (file && file->delete_table(path)) { error=1; diff --git a/sql/sql_class.h b/sql/sql_class.h index 7ca168ec518..2d1880a6d9d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -190,10 +190,10 @@ class MYSQL_LOG: public TC_LOG private: /* LOCK_log and LOCK_index are inited by init_pthread_objects() */ pthread_mutex_t LOCK_log, LOCK_index, LOCK_readers; + pthread_mutex_t LOCK_prep_xids; + pthread_cond_t COND_prep_xids; pthread_cond_t update_cond; pthread_cond_t reset_cond; - bool reset_pending; - int readers_count; ulonglong bytes_written; time_t last_time,query_start; IO_CACHE log_file; @@ -201,21 +201,6 @@ class MYSQL_LOG: public TC_LOG char *name; char time_buff[20],db[NAME_LEN+1]; char log_file_name[FN_REFLEN],index_file_name[FN_REFLEN]; - // current file sequence number for load data infile binary logging - uint file_id; - uint open_count; // For replication - volatile enum_log_type log_type; - enum cache_type io_cache_type; - bool write_error, inited; - bool need_start_event; - /* - no_auto_events means we don't want any of these automatic events : - Start/Rotate/Stop. That is, in 4.x when we rotate a relay log, we don't want - a Rotate_log event to be written to the relay log. When we start a relay log - etc. So in 4.x this is 1 for relay logs, 0 for binlogs. - In 5.0 it's 0 for relay logs too! - */ - bool no_auto_events; /* The max size before rotation (usable only if log_type == LOG_BIN: binary logs and relay logs). @@ -227,13 +212,38 @@ class MYSQL_LOG: public TC_LOG fix_max_relay_log_size). */ ulong max_size; - ulong prepared_xids; /* for tc log - number of xids to remember */ - pthread_mutex_t LOCK_prep_xids; - pthread_cond_t COND_prep_xids; + volatile enum_log_type log_type; + enum cache_type io_cache_type; + // current file sequence number for load data infile binary logging + uint file_id; + uint open_count; // For replication + int readers_count; + bool reset_pending; + bool write_error, inited; + bool need_start_event; + /* + no_auto_events means we don't want any of these automatic events : + Start/Rotate/Stop. That is, in 4.x when we rotate a relay log, we don't + want a Rotate_log event to be written to the relay log. When we start a + relay log etc. So in 4.x this is 1 for relay logs, 0 for binlogs. + In 5.0 it's 0 for relay logs too! + */ + bool no_auto_events; friend class Log_event; public: + /* + These describe the log's format. This is used only for relay logs. + _for_exec is used by the SQL thread, _for_queue by the I/O thread. It's + necessary to have 2 distinct objects, because the I/O thread may be reading + events in a different format from what the SQL thread is reading (consider + the case of a master which has been upgraded from 5.0 to 5.1 without doing + RESET MASTER, or from 4.x to 5.0). + */ + Format_description_log_event *description_event_for_exec, + *description_event_for_queue; + MYSQL_LOG(); /* note that there's no destructor ~MYSQL_LOG() ! @@ -246,18 +256,6 @@ public: int log(THD *thd, my_xid xid); void unlog(ulong cookie, my_xid xid); int recover(IO_CACHE *log, Format_description_log_event *fdle); - - /* - These describe the log's format. This is used only for relay logs. - _for_exec is used by the SQL thread, _for_queue by the I/O thread. It's - necessary to have 2 distinct objects, because the I/O thread may be reading - events in a different format from what the SQL thread is reading (consider - the case of a master which has been upgraded from 5.0 to 5.1 without doing - RESET MASTER, or from 4.x to 5.0). - */ - Format_description_log_event *description_event_for_exec, - *description_event_for_queue; - void reset_bytes_written() { bytes_written = 0; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 24b11916bf1..983f0931ef9 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -833,7 +833,8 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) if (!dont_send_ok) { db_type table_type; - if ((table_type=get_table_type(thd, path)) == DB_TYPE_UNKNOWN) + mysql_frm_type(thd, path, &table_type); + if (table_type == DB_TYPE_UNKNOWN) { my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 11f056d6510..a302db15736 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2037,6 +2037,35 @@ void st_lex::cleanup_after_one_table_open() } +/* + Do end-of-prepare fixup for list of tables and their merge-VIEWed tables + + SYNOPSIS + fix_prepare_info_in_table_list() + thd Thread handle + tbl List of tables to process + + DESCRIPTION + Perform end-end-of prepare fixup for list of tables, if any of the tables + is a merge-algorithm VIEW, recursively fix up its underlying tables as + well. + +*/ + +static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl) +{ + for (; tbl; tbl= tbl->next_local) + { + if (tbl->on_expr) + { + tbl->prep_on_expr= tbl->on_expr; + tbl->on_expr= tbl->on_expr->copy_andor_structure(thd); + } + fix_prepare_info_in_table_list(thd, tbl->merge_underlying_list); + } +} + + /* fix some structures at the end of preparation @@ -2056,16 +2085,7 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds) prep_where= *conds; *conds= where= prep_where->copy_andor_structure(thd); } - for (TABLE_LIST *tbl= (TABLE_LIST *)table_list.first; - tbl; - tbl= tbl->next_local) - { - if (tbl->on_expr) - { - tbl->prep_on_expr= tbl->on_expr; - tbl->on_expr= tbl->on_expr->copy_andor_structure(thd); - } - } + fix_prepare_info_in_table_list(thd, (TABLE_LIST *)table_list.first); } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index aab4caec5d4..4bbca55f6ba 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -194,6 +194,18 @@ inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) #endif +static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables) +{ + for (TABLE_LIST *table= tables; table; table= table->next_global) + { + DBUG_ASSERT(table->db && table->table_name); + if (table->updating && + !find_temporary_table(thd, table->db, table->table_name)) + return 1; + } + return 0; +} + static HASH hash_user_connections; static int get_or_create_user_conn(THD *thd, const char *user, @@ -2365,7 +2377,7 @@ mysql_execute_command(THD *thd) mysql_reset_errors(thd, 0); #ifdef HAVE_REPLICATION - if (thd->slave_thread) + if (unlikely(thd->slave_thread)) { /* Check if statment should be skipped because of slave filtering @@ -2404,16 +2416,20 @@ mysql_execute_command(THD *thd) } #endif } + else #endif /* HAVE_REPLICATION */ /* - When option readonly is set deny operations which change tables. - Except for the replication thread and the 'super' users. + When option readonly is set deny operations which change non-temporary + tables. Except for the replication thread and the 'super' users. */ if (opt_readonly && - !(thd->slave_thread || - (thd->security_ctx->master_access & SUPER_ACL)) && - uc_update_queries[lex->sql_command]) + !(thd->security_ctx->master_access & SUPER_ACL) && + uc_update_queries[lex->sql_command] && + !((lex->sql_command == SQLCOM_CREATE_TABLE) && + (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) && + ((lex->sql_command != SQLCOM_UPDATE_MULTI) && + some_non_temp_table_to_be_updated(thd, all_tables))) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); DBUG_RETURN(-1); @@ -3212,13 +3228,24 @@ end_with_restore_list: #ifdef HAVE_REPLICATION /* Check slave filtering rules */ - if (thd->slave_thread && all_tables_not_ok(thd, all_tables)) + if (unlikely(thd->slave_thread)) { - /* we warn the slave SQL thread */ - my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); + if (all_tables_not_ok(thd, all_tables)) + { + /* we warn the slave SQL thread */ + my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); + break; + } + } + else +#endif /* HAVE_REPLICATION */ + if (opt_readonly && + !(thd->security_ctx->master_access & SUPER_ACL) && + some_non_temp_table_to_be_updated(thd, all_tables)) + { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); break; } -#endif /* HAVE_REPLICATION */ res= mysql_multi_update(thd, all_tables, &select_lex->item_list, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 0d0afb5ca7d..ced862170ec 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2109,8 +2109,6 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) were closed in the end of previous prepare or execute call. */ tables->table= 0; - if (tables->nested_join) - tables->nested_join->counter= 0; if (tables->prep_on_expr) { diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 154e828b47e..80fcb973028 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -134,6 +134,8 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) { TABLE_LIST *ren_table,*new_table; frm_type_enum frm_type; + db_type table_type; + DBUG_ENTER("rename_tables"); for (ren_table= table_list; ren_table; ren_table= new_table->next_local) @@ -166,13 +168,12 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) reg_ext); unpack_filename(name, name); - frm_type= mysql_frm_type(name); + frm_type= mysql_frm_type(thd, name, &table_type); switch (frm_type) { case FRMTYPE_TABLE: { - db_type table_type; - if ((table_type= get_table_type(thd, name)) == DB_TYPE_UNKNOWN) + if (table_type == DB_TYPE_UNKNOWN) my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno); else rc= mysql_rename_table(table_type, ren_table->db, old_alias, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 285a5c5696b..44c4ec998bb 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -98,6 +98,12 @@ static COND* substitute_for_best_equal_field(COND *cond, void *table_join_idx); static COND *simplify_joins(JOIN *join, List *join_list, COND *conds, bool top); +static bool check_interleaving_with_nj(JOIN_TAB *last, JOIN_TAB *next); +static void restore_prev_nj_state(JOIN_TAB *last); +static void reset_nj_counters(List *join_list); +static uint build_bitmap_for_nested_joins(List *join_list, + uint first_unused); + static COND *optimize_cond(JOIN *join, COND *conds, List *join_list, Item::cond_result *cond_value); @@ -520,12 +526,14 @@ bool JOIN::test_in_subselect(Item **where) return 0; } + /* global select optimisation. return 0 - success 1 - error error code saved in field 'error' */ + int JOIN::optimize() { @@ -588,6 +596,7 @@ JOIN::optimize() /* Convert all outer joins to inner joins if possible */ conds= simplify_joins(this, join_list, conds, TRUE); + build_bitmap_for_nested_joins(join_list, 0); sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0; @@ -700,7 +709,8 @@ JOIN::optimize() DBUG_PRINT("error",("Error: make_select() failed")); DBUG_RETURN(1); } - + + reset_nj_counters(join_list); make_outerjoin_info(this); /* @@ -1968,14 +1978,19 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, continue; } outer_join|= table->map; + s->embedding_map= 0; + for (;embedding; embedding= embedding->embedding) + s->embedding_map|= embedding->nested_join->nj_map; continue; } if (embedding) { /* s belongs to a nested join, maybe to several embedded joins */ + s->embedding_map= 0; do { NESTED_JOIN *nested_join= embedding->nested_join; + s->embedding_map|=nested_join->nj_map; s->dependent|= embedding->dep_tables; embedding= embedding->embedding; outer_join|= nested_join->used_tables; @@ -3549,6 +3564,8 @@ choose_plan(JOIN *join, table_map join_tables) bool straight_join= join->select_options & SELECT_STRAIGHT_JOIN; DBUG_ENTER("choose_plan"); + join->cur_embedding_map= 0; + reset_nj_counters(join->join_list); /* if (SELECT_STRAIGHT_JOIN option is set) reorder tables so dependent tables come after tables they depend @@ -4029,7 +4046,9 @@ best_extension_by_limited_search(JOIN *join, for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++) { table_map real_table_bit= s->table->map; - if ((remaining_tables & real_table_bit) && !(remaining_tables & s->dependent)) + if ((remaining_tables & real_table_bit) && + !(remaining_tables & s->dependent) && + (!idx || !check_interleaving_with_nj(join->positions[idx-1].table, s))) { double current_record_count, current_read_time; @@ -4045,6 +4064,7 @@ best_extension_by_limited_search(JOIN *join, { DBUG_EXECUTE("opt", print_plan(join, read_time, record_count, idx, "prune_by_cost");); + restore_prev_nj_state(s); continue; } @@ -4073,6 +4093,7 @@ best_extension_by_limited_search(JOIN *join, { DBUG_EXECUTE("opt", print_plan(join, read_time, record_count, idx, "pruned_by_heuristic");); + restore_prev_nj_state(s); continue; } } @@ -4107,9 +4128,11 @@ best_extension_by_limited_search(JOIN *join, sizeof(POSITION) * (idx + 1)); join->best_read= current_read_time - 0.001; } - DBUG_EXECUTE("opt", - print_plan(join, current_read_time, current_record_count, idx, "full_plan");); + DBUG_EXECUTE("opt", print_plan(join, current_read_time, + current_record_count, idx, + "full_plan");); } + restore_prev_nj_state(s); } } DBUG_VOID_RETURN; @@ -4154,7 +4177,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, for (JOIN_TAB **pos=join->best_ref+idx ; (s=*pos) ; pos++) { table_map real_table_bit=s->table->map; - if ((rest_tables & real_table_bit) && !(rest_tables & s->dependent)) + if ((rest_tables & real_table_bit) && !(rest_tables & s->dependent) && + (!idx|| !check_interleaving_with_nj(join->positions[idx-1].table, s))) { double best,best_time,records; best=best_time=records=DBL_MAX; @@ -4492,10 +4516,10 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, join->unit->select_limit_cnt >= records) join->sort_by_table= (TABLE*) 1; // Must use temporary table - /* + /* Go to the next level only if there hasn't been a better key on this level! This will cut down the search for a lot simple cases! - */ + */ double current_record_count=record_count*records; double current_read_time=read_time+best; if (best_record_count > current_record_count || @@ -4516,6 +4540,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, return; swap_variables(JOIN_TAB*, join->best_ref[idx], *pos); } + restore_prev_nj_state(s); if (join->select_options & SELECT_STRAIGHT_JOIN) break; // Don't test all combinations } @@ -5101,7 +5126,7 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab) This function can be called only after the execution plan has been chosen. */ - + static void make_outerjoin_info(JOIN *join) { @@ -7262,11 +7287,11 @@ propagate_cond_constants(THD *thd, I_List *save_list, ascent all attributes are calculated, all outer joins that can be converted are replaced and then all unnecessary braces are removed. As join list contains join tables in the reverse order sequential - elimination of outer joins does not requite extra recursive calls. + elimination of outer joins does not require extra recursive calls. EXAMPLES Here is an example of a join query with invalid cross references: - SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t3.a LEFT JOIN ON t3.b=t1.b + SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t3.a LEFT JOIN t3 ON t3.b=t1.b RETURN VALUE The new condition, if success @@ -7423,7 +7448,257 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top) } DBUG_RETURN(conds); } - + + +/* + Assign each nested join structure a bit in nested_join_map + + SYNOPSIS + build_bitmap_for_nested_joins() + join Join being processed + join_list List of tables + first_unused Number of first unused bit in nested_join_map before the + call + + DESCRIPTION + Assign each nested join structure (except "confluent" ones - those that + embed only one element) a bit in nested_join_map. + + NOTE + This function is called after simplify_joins(), when there are no + redundant nested joins, #non_confluent_nested_joins <= #tables_in_join so + we will not run out of bits in nested_join_map. + + RETURN + First unused bit in nested_join_map after the call. +*/ + +static uint build_bitmap_for_nested_joins(List *join_list, + uint first_unused) +{ + List_iterator li(*join_list); + TABLE_LIST *table; + DBUG_ENTER("build_bitmap_for_nested_joins"); + while ((table= li++)) + { + NESTED_JOIN *nested_join; + if ((nested_join= table->nested_join)) + { + /* + It is guaranteed by simplify_joins() function that a nested join + that has only one child represents a single table VIEW (and the child + is an underlying table). We don't assign bits to such nested join + structures because + 1. it is redundant (a "sequence" of one table cannot be interleaved + with anything) + 2. we could run out bits in nested_join_map otherwise. + */ + if (nested_join->join_list.elements != 1) + { + nested_join->nj_map= 1 << first_unused++; + first_unused= build_bitmap_for_nested_joins(&nested_join->join_list, + first_unused); + } + } + } + DBUG_RETURN(first_unused); +} + + +/* + Set NESTED_JOIN::counter=0 in all nested joins in passed list + + SYNOPSIS + reset_nj_counters() + join_list List of nested joins to process. It may also contain base + tables which will be ignored. + + DESCRIPTION + Recursively set NESTED_JOIN::counter=0 for all nested joins contained in + the passed join_list. +*/ + +static void reset_nj_counters(List *join_list) +{ + List_iterator li(*join_list); + TABLE_LIST *table; + DBUG_ENTER("reset_nj_counters"); + while ((table= li++)) + { + NESTED_JOIN *nested_join; + if ((nested_join= table->nested_join)) + { + nested_join->counter= 0; + reset_nj_counters(&nested_join->join_list); + } + } + DBUG_VOID_RETURN; +} + + +/* + Check interleaving with an inner tables of an outer join for extension table + + SYNOPSIS + check_interleaving_with_nj() + join Join being processed + last_tab Last table in current partial join order (this function is + not called for empty partial join orders) + next_tab Table we're going to extend the current partial join with + + DESCRIPTION + Check if table next_tab can be added to current partial join order, and + if yes, record that it has been added. + + The function assumes that both current partial join order and its + extension with next_tab are valid wrt table dependencies. + + IMPLEMENTATION + LIMITATIONS ON JOIN ORDER + The nested [outer] joins executioner algorithm imposes these limitations + on join order: + 1. "Outer tables first" - any "outer" table must be before any + corresponding "inner" table. + 2. "No interleaving" - tables inside a nested join must form a continuous + sequence in join order (i.e. the sequence must not be interrupted by + tables that are outside of this nested join). + + #1 is checked elsewhere, this function checks #2 provided that #1 has + been already checked. + + WHY NEED NON-INTERLEAVING + Consider an example: + + select * from t0 join t1 left join (t2 join t3) on cond1 + + The join order "t1 t2 t0 t3" is invalid: + + table t0 is outside of the nested join, so WHERE condition for t0 is + attached directly to t0 (without triggers, and it may be used to access + t0). Applying WHERE(t0) to (t2,t0,t3) record is invalid as we may miss + combinations of (t1, t2, t3) that satisfy condition cond1, and produce a + null-complemented (t1, t2.NULLs, t3.NULLs) row, which should not have + been produced. + + If table t0 is not between t2 and t3, the problem doesn't exist: + * If t0 is located after (t2,t3), WHERE(t0) is applied after nested join + processing has finished. + * If t0 is located before (t2,t3), predicates like WHERE_cond(t0, t2) are + wrapped into condition triggers, which takes care of correct nested + join processing. + + HOW IT IS IMPLEMENTED + The limitations on join order can be rephrased as follows: for valid + join order one must be able to: + 1. write down the used tables in the join order on one line. + 2. for each nested join, put one '(' and one ')' on the said line + 3. write "LEFT JOIN" and "ON (...)" where appropriate + 4. get a query equivalent to the query we're trying to execute. + + Calls to check_interleaving_with_nj() are equivalent to writing the + above described line from left to right. + A single check_interleaving_with_nj(A,B) call is equivalent to writing + table B and appropriate brackets on condition that table A and + appropriate brackets is the last what was written. Graphically the + transition is as follows: + + +---- current position + | + ... last_tab ))) | ( next_tab ) )..) | ... + X Y Z | + +- need to move to this + position. + + Notes about the position: + The caller guarantees that there is no more then one X-bracket by + checking "!(remaining_tables & s->dependent)" before calling this + function. X-bracket may have a pair in Y-bracket. + + When "writing" we store/update this auxilary info about the current + position: + 1. join->cur_embedding_map - bitmap of pairs of brackets (aka nested + joins) we've opened but didn't close. + 2. {each NESTED_JOIN structure not simplified away}->counter - number + of this nested join's children that have already been added to to + the partial join order. + + RETURN + FALSE Join order extended, nested joins info about current join order + (see NOTE section) updated. + TRUE Requested join order extension not allowed. +*/ + +static bool check_interleaving_with_nj(JOIN_TAB *last_tab, JOIN_TAB *next_tab) +{ + TABLE_LIST *next_emb= next_tab->table->pos_in_table_list->embedding; + JOIN *join= last_tab->join; + + if (join->cur_embedding_map & ~next_tab->embedding_map) + { + /* + next_tab is outside of the "pair of brackets" we're currently in. + Cannot add it. + */ + return TRUE; + } + + /* + Do update counters for "pairs of brackets" that we've left (marked as + X,Y,Z in the above picture) + */ + for (;next_emb; next_emb= next_emb->embedding) + { + next_emb->nested_join->counter++; + if (next_emb->nested_join->counter == 1) + { + /* + next_emb is the first table inside a nested join we've "entered". In + the picture above, we're looking at the 'X' bracket. Don't exit yet as + X bracket might have Y pair bracket. + */ + join->cur_embedding_map |= next_emb->nested_join->nj_map; + } + + if (next_emb->nested_join->join_list.elements != + next_emb->nested_join->counter) + break; + + /* + We're currently at Y or Z-bracket as depicted in the above picture. + Mark that we've left it and continue walking up the brackets hierarchy. + */ + join->cur_embedding_map &= ~next_emb->nested_join->nj_map; + } + return FALSE; +} + + +/* + Nested joins perspective: Remove the last table from the join order + + SYNOPSIS + restore_prev_nj_state() + last join table to remove, it is assumed to be the last in current + partial join order. + + DESCRIPTION + Remove the last table from the partial join order and update the nested + joins counters and join->cur_embedding_map. It is ok to call this + function for the first table in join order (for which + check_interleaving_with_nj has not been called) +*/ + +static void restore_prev_nj_state(JOIN_TAB *last) +{ + TABLE_LIST *last_emb= last->table->pos_in_table_list->embedding; + JOIN *join= last->join; + while (last_emb && !(--last_emb->nested_join->counter)) + { + join->cur_embedding_map &= last_emb->nested_join->nj_map; + last_emb= last_emb->embedding; + } +} + static COND * optimize_cond(JOIN *join, COND *conds, List *join_list, @@ -8029,7 +8304,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, statistic_increment(thd->status_var.created_tmp_tables, &LOCK_status); - if (use_temp_pool) + if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES)) temp_pool_slot = bitmap_set_next(&temp_pool); if (temp_pool_slot != MY_BIT_NONE) // we got a slot @@ -8279,7 +8554,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, (select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) == OPTION_BIG_TABLES || (select_options & TMP_TABLE_FORCE_MYISAM)) { - table->file=get_new_handler(table,table->s->db_type= DB_TYPE_MYISAM); + table->file= get_new_handler(table, &table->mem_root, + table->s->db_type= DB_TYPE_MYISAM); if (group && (param->group_parts > table->file->max_key_parts() || param->group_length > table->file->max_key_length())) @@ -8287,7 +8563,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, } else { - table->file=get_new_handler(table,table->s->db_type= DB_TYPE_HEAP); + table->file= get_new_handler(table, &table->mem_root, + table->s->db_type= DB_TYPE_HEAP); } if (!using_unique_constraint) @@ -8871,7 +9148,8 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, new_table= *table; new_table.s= &new_table.share_not_to_be_used; new_table.s->db_type= DB_TYPE_MYISAM; - if (!(new_table.file= get_new_handler(&new_table,DB_TYPE_MYISAM))) + if (!(new_table.file= get_new_handler(&new_table, &new_table.mem_root, + DB_TYPE_MYISAM))) DBUG_RETURN(1); // End of memory save_proc_info=thd->proc_info; diff --git a/sql/sql_select.h b/sql/sql_select.h index 28f5888af76..2f53c9a3b35 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -136,7 +136,9 @@ typedef struct st_join_table { TABLE_REF ref; JOIN_CACHE cache; JOIN *join; - + /* Bitmap of nested joins this table is part of */ + nested_join_map embedding_map; + void cleanup(); } JOIN_TAB; @@ -193,6 +195,13 @@ class JOIN :public Sql_alloc */ ha_rows fetch_limit; POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1]; + + /* + Bitmap of nested joins embedding the position at the end of the current + partial join (valid only during join optimizer run). + */ + nested_join_map cur_embedding_map; + double best_read; List *fields; List group_fields, group_fields_cache; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9cf8ff884ae..b4b24e0b6be 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2006,6 +2006,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) Security_context *sctx= thd->security_ctx; uint derived_tables= lex->derived_tables; int error= 1; + db_type not_used; Open_tables_state open_tables_state_backup; DBUG_ENTER("get_all_tables"); @@ -2117,7 +2118,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) else { my_snprintf(end, len, "/%s%s", file_name, reg_ext); - switch (mysql_frm_type(path)) { + switch (mysql_frm_type(thd, path, ¬_used)) { case FRMTYPE_ERROR: table->field[3]->store("ERROR", 5, system_charset_info); break; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b635c44c6dc..fb190f5524f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -218,6 +218,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, String wrong_tables; int error; bool some_tables_deleted=0, tmp_table_deleted=0, foreign_key_error=0; + DBUG_ENTER("mysql_rm_table_part2"); if (lock_table_names(thd, tables)) @@ -229,6 +230,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, for (table= tables; table; table= table->next_local) { char *db=table->db; + db_type table_type= DB_TYPE_UNKNOWN; + mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL); if (!close_temporary_table(thd, db, table->table_name)) { @@ -256,7 +259,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, if (drop_temporary || (access(path,F_OK) && ha_create_table_from_engine(thd,db,alias)) || - (!drop_view && mysql_frm_type(path) != FRMTYPE_TABLE)) + (!drop_view && + mysql_frm_type(thd, path, &table_type) != FRMTYPE_TABLE)) { // Table was not found on disk and table can't be created from engine if (if_exists) @@ -269,7 +273,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, else { char *end; - db_type table_type= get_table_type(thd, path); + if (table_type == DB_TYPE_UNKNOWN) + mysql_frm_type(thd, path, &table_type); *(end=fn_ext(path))=0; // Remove extension for delete error= ha_delete_table(thd, table_type, path, table->table_name, !dont_log_query); @@ -1508,7 +1513,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, if (create_info->row_type == ROW_TYPE_DYNAMIC) db_options|=HA_OPTION_PACK_RECORD; alias= table_case_name(create_info, table_name); - file=get_new_handler((TABLE*) 0, create_info->db_type); + file= get_new_handler((TABLE*) 0, thd->mem_root, create_info->db_type); #ifdef NOT_USED /* @@ -1806,10 +1811,12 @@ mysql_rename_table(enum db_type base, const char *new_db, const char *new_name) { + THD *thd= current_thd; char from[FN_REFLEN], to[FN_REFLEN], lc_from[FN_REFLEN], lc_to[FN_REFLEN]; char *from_base= from, *to_base= to; char tmp_name[NAME_LEN+1]; - handler *file=(base == DB_TYPE_UNKNOWN ? 0 : get_new_handler((TABLE*) 0, base)); + handler *file= (base == DB_TYPE_UNKNOWN ? 0 : + get_new_handler((TABLE*) 0, thd->mem_root, base)); int error=0; DBUG_ENTER("mysql_rename_table"); @@ -2189,7 +2196,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, /* if view are unsupported */ if (table->view && view_operator_func == NULL) { - result_code= HA_ADMIN_NOT_IMPLEMENTED; + result_code= HA_ADMIN_NOT_BASE_TABLE; goto send_result; } thd->open_options&= ~extra_open_options; @@ -2324,6 +2331,16 @@ send_result_message: } break; + case HA_ADMIN_NOT_BASE_TABLE: + { + char buf[ERRMSGSIZE+20]; + uint length= my_snprintf(buf, ERRMSGSIZE, + ER(ER_BAD_TABLE_ERROR), table_name); + protocol->store("note", 4, system_charset_info); + protocol->store(buf, length, system_charset_info); + } + break; + case HA_ADMIN_OK: protocol->store("status", 6, system_charset_info); protocol->store("OK",2, system_charset_info); @@ -2424,16 +2441,19 @@ send_result_message: break; } } - if (fatal_error) - table->table->s->version=0; // Force close of table - else if (open_for_modify) + if (table->table) { - pthread_mutex_lock(&LOCK_open); - remove_table_from_cache(thd, table->table->s->db, - table->table->s->table_name, RTFC_NO_FLAG); - pthread_mutex_unlock(&LOCK_open); - /* May be something modified consequently we have to invalidate cache */ - query_cache_invalidate3(thd, table->table, 0); + if (fatal_error) + table->table->s->version=0; // Force close of table + else if (open_for_modify) + { + pthread_mutex_lock(&LOCK_open); + remove_table_from_cache(thd, table->table->s->db, + table->table->s->table_name, RTFC_NO_FLAG); + pthread_mutex_unlock(&LOCK_open); + /* Something may be modified, that's why we have to invalidate cache */ + query_cache_invalidate3(thd, table->table, 0); + } } close_thread_tables(thd); table->table=0; // For query cache @@ -2615,6 +2635,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, char *src_table= table_ident->table.str; int err; bool res= TRUE; + db_type not_used; + TABLE_LIST src_tables_list; DBUG_ENTER("mysql_create_like_table"); src_db= table_ident->db.str ? table_ident->db.str : thd->db; @@ -2662,7 +2684,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, /* create like should be not allowed for Views, Triggers, ... */ - if (mysql_frm_type(src_path) != FRMTYPE_TABLE) + if (mysql_frm_type(thd, src_path, ¬_used) != FRMTYPE_TABLE) { my_error(ER_WRONG_OBJECT, MYF(0), src_db, src_table, "BASE TABLE"); goto err; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index bd19d4d85f3..039aa0f71fa 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -121,7 +121,7 @@ int mysql_update(THD *thd, bool safe_update= thd->options & OPTION_SAFE_UPDATES; bool used_key_is_modified, transactional_table; int res; - int error=0; + int error; uint used_index= MAX_KEY; bool need_sort= TRUE; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -132,7 +132,7 @@ int mysql_update(THD *thd, ha_rows updated, found; key_map old_used_keys; TABLE *table; - SQL_SELECT *select= 0; + SQL_SELECT *select; READ_RECORD info; SELECT_LEX *select_lex= &thd->lex->select_lex; bool need_reopen; @@ -237,8 +237,7 @@ int mysql_update(THD *thd, } // Don't count on usage of 'only index' when calculating which key to use table->used_keys.clear_all(); - if (limit) - select= make_select(table, 0, 0, conds, 0, &error); + select= make_select(table, 0, 0, conds, 0, &error); if (error || !limit || (select && select->check_quick(thd, safe_update, limit))) { diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 846130c53fc..71c5d198b27 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1171,6 +1171,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) char path[FN_REFLEN]; TABLE_LIST *view; bool type= 0; + db_type not_used; for (view= views; view; view= view->next_local) { @@ -1178,7 +1179,8 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) view->table_name, reg_ext, NullS); (void) unpack_filename(path, path); VOID(pthread_mutex_lock(&LOCK_open)); - if (access(path, F_OK) || (type= (mysql_frm_type(path) != FRMTYPE_VIEW))) + if (access(path, F_OK) || + (type= (mysql_frm_type(thd, path, ¬_used) != FRMTYPE_VIEW))) { char name[FN_REFLEN]; my_snprintf(name, sizeof(name), "%s.%s", view->db, view->table_name); @@ -1225,24 +1227,36 @@ err: FRMTYPE_VIEW view */ -frm_type_enum mysql_frm_type(char *path) +frm_type_enum mysql_frm_type(THD *thd, char *path, db_type *dbt) { File file; - char header[10]; //"TYPE=VIEW\n" it is 10 characters - int length; + uchar header[10]; //"TYPE=VIEW\n" it is 10 characters + int error; DBUG_ENTER("mysql_frm_type"); + *dbt= DB_TYPE_UNKNOWN; + if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0) - { DBUG_RETURN(FRMTYPE_ERROR); - } - length= my_read(file, (byte*) header, sizeof(header), MYF(MY_WME)); + error= my_read(file, (byte*) header, sizeof(header), MYF(MY_WME | MY_NABP)); my_close(file, MYF(MY_WME)); - if (length == (int) MY_FILE_ERROR) + + if (error) DBUG_RETURN(FRMTYPE_ERROR); - if (length < (int) sizeof(header) || - !strncmp(header, "TYPE=VIEW\n", sizeof(header))) + if (!strncmp((char*) header, "TYPE=VIEW\n", sizeof(header))) DBUG_RETURN(FRMTYPE_VIEW); + + /* + This is just a check for DB_TYPE. We'll return default unknown type + if the following test is true (arg #3). This should not have effect + on return value from this function (default FRMTYPE_TABLE) + */ + if (header[0] != (uchar) 254 || header[1] != 1 || + (header[2] != FRM_VER && header[2] != FRM_VER+1 && + (header[2] < FRM_VER+3 || header[2] > FRM_VER+4))) + DBUG_RETURN(FRMTYPE_TABLE); + + *dbt= ha_checktype(thd, (enum db_type) (uint) *(header + 3), 0, 0); DBUG_RETURN(FRMTYPE_TABLE); // Is probably a .frm table } diff --git a/sql/sql_view.h b/sql/sql_view.h index f58fe1fc6ca..cd61d7e9e71 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -27,7 +27,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST * view); bool insert_view_fields(THD *thd, List *list, TABLE_LIST *view); -frm_type_enum mysql_frm_type(char *path); +frm_type_enum mysql_frm_type(THD *thd, char *path, db_type *dbt); int view_checksum(THD *thd, TABLE_LIST *view); diff --git a/sql/table.cc b/sql/table.cc index 809787a9203..3bc5c9a242b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -338,7 +338,8 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, my_free(buff, MYF(0)); } /* Allocate handler */ - if (!(outparam->file= get_new_handler(outparam, share->db_type))) + if (!(outparam->file= get_new_handler(outparam, &outparam->mem_root, + share->db_type))) goto err; error=4; @@ -1692,29 +1693,6 @@ bool check_column_name(const char *name) return last_char_is_space || (uint) (name - start) > NAME_LEN; } -/* -** Get type of table from .frm file -*/ - -db_type get_table_type(THD *thd, const char *name) -{ - File file; - uchar head[4]; - int error; - DBUG_ENTER("get_table_type"); - DBUG_PRINT("enter",("name: '%s'",name)); - - if ((file=my_open(name,O_RDONLY, MYF(0))) < 0) - DBUG_RETURN(DB_TYPE_UNKNOWN); - error=my_read(file,(byte*) head,4,MYF(MY_NABP)); - my_close(file,MYF(0)); - if (error || head[0] != (uchar) 254 || head[1] != 1 || - (head[2] != FRM_VER && head[2] != FRM_VER+1 && - (head[2] < FRM_VER+3 || head[2] > FRM_VER+4))) - DBUG_RETURN(DB_TYPE_UNKNOWN); - DBUG_RETURN(ha_checktype(thd,(enum db_type) (uint) *(head+3),0,0)); -} - /* Create Item_field for each column in the table. @@ -2511,9 +2489,9 @@ bool st_table_list::prepare_security(THD *thd) { List_iterator_fast tb(*view_tables); TABLE_LIST *tbl; + DBUG_ENTER("st_table_list::prepare_security"); #ifndef NO_EMBEDDED_ACCESS_CHECKS Security_context *save_security_ctx= thd->security_ctx; - DBUG_ENTER("st_table_list::prepare_security"); DBUG_ASSERT(!prelocking_placeholder); if (prepare_view_securety_context(thd)) diff --git a/sql/table.h b/sql/table.h index 9e94c5fa2f6..d919b9a4203 100644 --- a/sql/table.h +++ b/sql/table.h @@ -795,7 +795,15 @@ typedef struct st_nested_join table_map used_tables; /* bitmap of tables in the nested join */ table_map not_null_tables; /* tables that rejects nulls */ struct st_join_table *first_nested;/* the first nested table in the plan */ - uint counter; /* to count tables in the nested join */ + /* + Used to count tables in the nested join in 2 isolated places: + 1. In make_outerjoin_info(). + 2. check_interleaving_with_nj/restore_prev_nj_state (these are called + by the join optimizer. + Before each use the counters are zeroed by reset_nj_counters. + */ + uint counter; + nested_join_map nj_map; /* Bit used to identify this nested join*/ } NESTED_JOIN; diff --git a/sql/unireg.cc b/sql/unireg.cc index 065f8583f71..0ab77462f61 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -90,7 +90,7 @@ bool mysql_create_frm(THD *thd, my_string file_name, if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0))) DBUG_RETURN(1); if (db_file == NULL) - db_file= get_new_handler((TABLE*) 0, create_info->db_type); + db_file= get_new_handler((TABLE*) 0, thd->mem_root, create_info->db_type); /* If fixed row records, we need one bit to check for deleted rows */ if (!(create_info->table_options & HA_OPTION_PACK_RECORD)) @@ -699,7 +699,7 @@ static bool make_empty_rec(THD *thd, File file,enum db_type table_type, /* We need a table to generate columns for default values */ bzero((char*) &table,sizeof(table)); table.s= &table.share_not_to_be_used; - handler= get_new_handler((TABLE*) 0, table_type); + handler= get_new_handler((TABLE*) 0, thd->mem_root, table_type); if (!handler || !(buff=(uchar*) my_malloc((uint) reclength,MYF(MY_WME | MY_ZEROFILL)))) diff --git a/strings/decimal.c b/strings/decimal.c index ea6ac2caf38..f536bdb1d6b 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1986,7 +1986,11 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to) carry+=hi; } for (; carry; buf0--) + { + if (buf0 < to->buf) + return E_DEC_OVERFLOW; ADD(*buf0, *buf0, 0, carry); + } } /* Now we have to check for -0.000 case */ diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 1b74ce50328..7b2eee5f821 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -259,6 +259,7 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \ --includedir=%{_includedir} \ --mandir=%{_mandir} \ --enable-thread-safe-client \ + --with-zlib-dir=bundled \ --with-readline ; \ # Add this for more debugging support # --with-debug diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index f46b1cf1784..949c3d5bf1c 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -14319,6 +14319,7 @@ static void test_bug12243() mysql_autocommit(mysql, TRUE); /* restore default */ } + /* Bug#11718: query with function, join and order by returns wrong type */ @@ -14366,6 +14367,58 @@ static void test_bug12925() } +/* + Bug#14210 "Simple query with > operator on large table gives server + crash" +*/ + +static void test_bug14210() +{ + MYSQL_STMT *stmt; + int rc, i; + const char *stmt_text; + ulong type; + + myheader("test_bug14210"); + + mysql_query(mysql, "drop table if exists t1"); + /* + To trigger the problem the table must be InnoDB, although the problem + itself is not InnoDB related. In case the table is MyISAM this test + is harmless. + */ + mysql_query(mysql, "create table t1 (a varchar(255)) type=InnoDB"); + rc= mysql_query(mysql, "insert into t1 (a) values (repeat('a', 256))"); + myquery(rc); + rc= mysql_query(mysql, "set @@session.max_heap_table_size=16384"); + /* Create a big enough table (more than max_heap_table_size) */ + for (i= 0; i < 8; i++) + { + rc= mysql_query(mysql, "insert into t1 (a) select a from t1"); + myquery(rc); + } + /* create statement */ + stmt= mysql_stmt_init(mysql); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + stmt_text= "select a from t1"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + ; + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + rc= mysql_query(mysql, "set @@session.max_heap_table_size=default"); + myquery(rc); +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -14621,6 +14674,7 @@ static struct my_tests_st my_tests[]= { { "test_bug11901", test_bug11901 }, { "test_bug11904", test_bug11904 }, { "test_bug12243", test_bug12243 }, + { "test_bug14210", test_bug14210 }, { 0, 0 } };