diff options
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | mysql-test/r/cache_innodb.result | 12 | ||||
-rw-r--r-- | mysql-test/r/change_user.result | 7 | ||||
-rw-r--r-- | mysql-test/r/greedy_optimizer.result | 77 | ||||
-rw-r--r-- | mysql-test/r/having.result | 7 | ||||
-rw-r--r-- | mysql-test/r/mysqlcheck.result | 2 | ||||
-rw-r--r-- | mysql-test/r/not_embedded_server.result | 7 | ||||
-rw-r--r-- | mysql-test/r/query_cache.result | 51 | ||||
-rw-r--r-- | mysql-test/t/change_user-master.opt | 1 | ||||
-rw-r--r-- | mysql-test/t/change_user.test | 29 | ||||
-rw-r--r-- | mysql-test/t/greedy_optimizer.test | 73 | ||||
-rw-r--r-- | mysql-test/t/having.test | 11 | ||||
-rw-r--r-- | mysql-test/t/mysqlcheck.test | 2 | ||||
-rw-r--r-- | mysql-test/t/not_embedded_server.test | 34 | ||||
-rw-r--r-- | mysql-test/t/query_cache.test | 27 | ||||
-rw-r--r-- | mysys/my_init.c | 8 | ||||
-rw-r--r-- | scripts/mysql_install_db.sh | 51 | ||||
-rw-r--r-- | sql/item.cc | 19 | ||||
-rw-r--r-- | sql/item.h | 3 | ||||
-rw-r--r-- | sql/item_func.cc | 9 | ||||
-rw-r--r-- | sql/item_func.h | 1 | ||||
-rw-r--r-- | sql/mysql_priv.h | 2 | ||||
-rw-r--r-- | sql/sql_cache.cc | 17 | ||||
-rw-r--r-- | sql/sql_select.cc | 27 | ||||
-rw-r--r-- | tests/mysql_client_test.c | 60 |
25 files changed, 464 insertions, 75 deletions
diff --git a/configure.in b/configure.in index 919ab765118..185ade4273f 100644 --- a/configure.in +++ b/configure.in @@ -10,7 +10,7 @@ AC_CANONICAL_SYSTEM # # When changing major version number please also check switch statement # in mysqlbinlog::check_master_version(). -AM_INIT_AUTOMAKE(mysql, 5.1.31) +AM_INIT_AUTOMAKE(mysql, 5.1.32) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 diff --git a/mysql-test/r/cache_innodb.result b/mysql-test/r/cache_innodb.result index 17cfcd69ec3..a6b86d8d82a 100644 --- a/mysql-test/r/cache_innodb.result +++ b/mysql-test/r/cache_innodb.result @@ -67,10 +67,10 @@ a 2 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 3 +Qcache_queries_in_cache 6 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 3 +Qcache_hits 0 insert into t1 values (3); insert into t2 values (3); insert into t1 values (4); @@ -91,14 +91,14 @@ a 2 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 1 +Qcache_queries_in_cache 2 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 4 +Qcache_hits 1 commit; show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 1 +Qcache_queries_in_cache 2 drop table t3,t2,t1; CREATE TABLE t1 (id int(11) NOT NULL auto_increment, PRIMARY KEY (id)); select count(*) from t1; @@ -217,5 +217,5 @@ Variable_name Value Qcache_queries_in_cache 1 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 2 +Qcache_hits 1 drop table t2; diff --git a/mysql-test/r/change_user.result b/mysql-test/r/change_user.result index a075c01fe61..70da464a612 100644 --- a/mysql-test/r/change_user.result +++ b/mysql-test/r/change_user.result @@ -44,3 +44,10 @@ IS_FREE_LOCK('bug31418') SELECT IS_USED_LOCK('bug31418'); IS_USED_LOCK('bug31418') NULL +FLUSH STATUS; +SHOW GLOBAL STATUS LIKE 'com_select'; +Variable_name Value +Com_select 112 +SHOW GLOBAL STATUS LIKE 'com_select'; +Variable_name Value +Com_select 112 diff --git a/mysql-test/r/greedy_optimizer.result b/mysql-test/r/greedy_optimizer.result index 9e8c66722e3..c0012c297d1 100644 --- a/mysql-test/r/greedy_optimizer.result +++ b/mysql-test/r/greedy_optimizer.result @@ -655,3 +655,80 @@ show status like 'Last_query_cost'; Variable_name Value Last_query_cost 794.837037 drop table t1,t2,t3,t4,t5,t6,t7; +CREATE TABLE t1 (a int, b int, d int, i int); +INSERT INTO t1 VALUES (1,1,1,1); +CREATE TABLE t2 (b int, c int, j int); +INSERT INTO t2 VALUES (1,1,1); +CREATE TABLE t2_1 (j int); +INSERT INTO t2_1 VALUES (1); +CREATE TABLE t3 (c int, f int); +INSERT INTO t3 VALUES (1,1); +CREATE TABLE t3_1 (f int); +INSERT INTO t3_1 VALUES (1); +CREATE TABLE t4 (d int, e int, k int); +INSERT INTO t4 VALUES (1,1,1); +CREATE TABLE t4_1 (k int); +INSERT INTO t4_1 VALUES (1); +CREATE TABLE t5 (g int, d int, h int, l int); +INSERT INTO t5 VALUES (1,1,1,1); +CREATE TABLE t5_1 (l int); +INSERT INTO t5_1 VALUES (1); +SET optimizer_search_depth = 3; +SELECT 1 +FROM t1 +LEFT JOIN ( +t2 JOIN t3 ON t3.c = t2.c +) ON t2.b = t1.b +LEFT JOIN ( +t4 JOIN t5 ON t5.d = t4.d +) ON t4.d = t1.d +; +1 +1 +SELECT 1 +FROM t1 +LEFT JOIN ( +t2 LEFT JOIN (t3 JOIN t3_1 ON t3.f = t3_1.f) ON t3.c = t2.c +) ON t2.b = t1.b +LEFT JOIN ( +t4 JOIN t5 ON t5.d = t4.d +) ON t4.d = t1.d +; +1 +1 +SELECT 1 +FROM t1 +LEFT JOIN ( +(t2 JOIN t2_1 ON t2.j = t2_1.j) JOIN t3 ON t3.c = t2.c +) ON t2.b = t1.b +LEFT JOIN ( +t4 JOIN t5 ON t5.d = t4.d +) ON t4.d = t1.d +; +1 +1 +SELECT 1 +FROM t1 +LEFT JOIN ( +t2 JOIN t3 ON t3.c = t2.c +) ON t2.b = t1.b +LEFT JOIN ( +(t4 JOIN t4_1 ON t4.k = t4_1.k) LEFT JOIN t5 ON t5.d = t4.d +) ON t4.d = t1.d +; +1 +1 +SELECT 1 +FROM t1 +LEFT JOIN ( +t2 JOIN t3 ON t3.c = t2.c +) ON t2.b = t1.b +LEFT JOIN ( +t4 LEFT JOIN (t5 JOIN t5_1 ON t5.l = t5_1.l) ON t5.d = t4.d +) ON t4.d = t1.d +; +1 +1 +SET optimizer_search_depth = DEFAULT; +DROP TABLE t1,t2,t2_1,t3,t3_1,t4,t4_1,t5,t5_1; +End of 5.0 tests diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result index a5a96fd4958..9c3cc8fc89e 100644 --- a/mysql-test/r/having.result +++ b/mysql-test/r/having.result @@ -424,3 +424,10 @@ select f1 from t1 group by f1 having max(f1)=f1; f1 set session sql_mode=''; drop table t1; +CREATE TABLE t1 ( a INT, b INT); +INSERT INTO t1 VALUES (1, 1), (2,2), (3, NULL); +SELECT b, COUNT(DISTINCT a) FROM t1 GROUP BY b HAVING b is NULL; +b COUNT(DISTINCT a) +NULL 1 +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index 313cba51ec9..2febfcf7eb4 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -146,7 +146,7 @@ CREATE TABLE `я` (a INT); SET NAMES DEFAULT; mysqlcheck --default-character-set="latin1" --databases test test.? -Error : Table 'test.?' doesn't exist +Error : Table doesn't exist error : Corrupt mysqlcheck --default-character-set="utf8" --databases test test.я OK diff --git a/mysql-test/r/not_embedded_server.result b/mysql-test/r/not_embedded_server.result index 1b734136e6c..f2ffe28895d 100644 --- a/mysql-test/r/not_embedded_server.result +++ b/mysql-test/r/not_embedded_server.result @@ -3,10 +3,3 @@ execute stmt1; ID USER HOST DB COMMAND TIME STATE INFO number root localhost test Query time executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND!='Daemon' deallocate prepare stmt1; -FLUSH STATUS; -SHOW GLOBAL STATUS LIKE 'com_select'; -Variable_name Value -Com_select 102 -SHOW GLOBAL STATUS LIKE 'com_select'; -Variable_name Value -Com_select 102 diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 3c8ff8faddc..0368fffa7c4 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1656,6 +1656,57 @@ Qcache_hits 1 DROP TABLE t1; SET GLOBAL concurrent_insert= @save_concurrent_insert; SET GLOBAL query_cache_size= default; +DROP TABLE IF EXISTS t1; +FLUSH STATUS; +SET GLOBAL query_cache_size=1048576; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3),(4),(5); +SHOW STATUS LIKE 'Qcache_queries_in_cache'; +Variable_name Value +Qcache_queries_in_cache 0 +SELECT * FROM t1; +a +1 +2 +3 +4 +5 +BEGIN; +SELECT * FROM t1; +a +1 +2 +3 +4 +5 +COMMIT; +SHOW STATUS LIKE 'Qcache_queries_in_cache'; +Variable_name Value +Qcache_queries_in_cache 2 +SHOW STATUS LIKE "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +SELECT * FROM t1; +a +1 +2 +3 +4 +5 +BEGIN; +SELECT * FROM t1; +a +1 +2 +3 +4 +5 +COMMIT; +SHOW STATUS LIKE "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +DROP TABLE t1; +SET GLOBAL query_cache_size= default; End of 5.0 tests CREATE TABLE t1 (a ENUM('rainbow')); INSERT INTO t1 VALUES (),(),(),(),(); diff --git a/mysql-test/t/change_user-master.opt b/mysql-test/t/change_user-master.opt new file mode 100644 index 00000000000..cef79bc8585 --- /dev/null +++ b/mysql-test/t/change_user-master.opt @@ -0,0 +1 @@ +--force-restart diff --git a/mysql-test/t/change_user.test b/mysql-test/t/change_user.test index f200c76196c..47e503a9afd 100644 --- a/mysql-test/t/change_user.test +++ b/mysql-test/t/change_user.test @@ -45,9 +45,26 @@ SELECT IS_USED_LOCK('bug31418'); # Bug#31222: com_% global status counters behave randomly with # mysql_change_user. # -# Moved to not_embedded_server.test due to Bug#34517: SHOW GLOBAL STATUS does -# not work properly in embedded server. -# -# TODO: move it back when Bug#34517 is fixed (don't forget to add -# --force-restart into change_user-master.opt). -# + +FLUSH STATUS; + +--disable_result_log +--disable_query_log + +let $i = 100; + +while ($i) +{ + dec $i; + + SELECT 1; +} + +--enable_query_log +--enable_result_log + +SHOW GLOBAL STATUS LIKE 'com_select'; + +--change_user + +SHOW GLOBAL STATUS LIKE 'com_select'; diff --git a/mysql-test/t/greedy_optimizer.test b/mysql-test/t/greedy_optimizer.test index b73f70c6a3e..5131c97f122 100644 --- a/mysql-test/t/greedy_optimizer.test +++ b/mysql-test/t/greedy_optimizer.test @@ -311,3 +311,76 @@ explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and show status like 'Last_query_cost'; drop table t1,t2,t3,t4,t5,t6,t7; + + +# +# Bug # 38795: Automatic search depth and nested join's results in server +# crash +# + +CREATE TABLE t1 (a int, b int, d int, i int); INSERT INTO t1 VALUES (1,1,1,1); +CREATE TABLE t2 (b int, c int, j int); INSERT INTO t2 VALUES (1,1,1); +CREATE TABLE t2_1 (j int); INSERT INTO t2_1 VALUES (1); +CREATE TABLE t3 (c int, f int); INSERT INTO t3 VALUES (1,1); +CREATE TABLE t3_1 (f int); INSERT INTO t3_1 VALUES (1); +CREATE TABLE t4 (d int, e int, k int); INSERT INTO t4 VALUES (1,1,1); +CREATE TABLE t4_1 (k int); INSERT INTO t4_1 VALUES (1); +CREATE TABLE t5 (g int, d int, h int, l int); INSERT INTO t5 VALUES (1,1,1,1); +CREATE TABLE t5_1 (l int); INSERT INTO t5_1 VALUES (1); + +SET optimizer_search_depth = 3; + +SELECT 1 +FROM t1 +LEFT JOIN ( + t2 JOIN t3 ON t3.c = t2.c +) ON t2.b = t1.b +LEFT JOIN ( + t4 JOIN t5 ON t5.d = t4.d +) ON t4.d = t1.d +; + +SELECT 1 +FROM t1 +LEFT JOIN ( + t2 LEFT JOIN (t3 JOIN t3_1 ON t3.f = t3_1.f) ON t3.c = t2.c +) ON t2.b = t1.b +LEFT JOIN ( + t4 JOIN t5 ON t5.d = t4.d +) ON t4.d = t1.d +; + +SELECT 1 +FROM t1 +LEFT JOIN ( + (t2 JOIN t2_1 ON t2.j = t2_1.j) JOIN t3 ON t3.c = t2.c +) ON t2.b = t1.b +LEFT JOIN ( + t4 JOIN t5 ON t5.d = t4.d +) ON t4.d = t1.d +; + +SELECT 1 +FROM t1 +LEFT JOIN ( + t2 JOIN t3 ON t3.c = t2.c +) ON t2.b = t1.b +LEFT JOIN ( + (t4 JOIN t4_1 ON t4.k = t4_1.k) LEFT JOIN t5 ON t5.d = t4.d +) ON t4.d = t1.d +; + +SELECT 1 +FROM t1 +LEFT JOIN ( + t2 JOIN t3 ON t3.c = t2.c +) ON t2.b = t1.b +LEFT JOIN ( + t4 LEFT JOIN (t5 JOIN t5_1 ON t5.l = t5_1.l) ON t5.d = t4.d +) ON t4.d = t1.d +; + +SET optimizer_search_depth = DEFAULT; +DROP TABLE t1,t2,t2_1,t3,t3_1,t4,t4_1,t5,t5_1; + +--echo End of 5.0 tests diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test index 683abfd3783..af9af4fe1fc 100644 --- a/mysql-test/t/having.test +++ b/mysql-test/t/having.test @@ -432,3 +432,14 @@ select f1 from t1 having max(f1)=f1; select f1 from t1 group by f1 having max(f1)=f1; set session sql_mode=''; drop table t1; + + +# +# Bug #38637: COUNT DISTINCT prevents NULL testing in HAVING clause +# +CREATE TABLE t1 ( a INT, b INT); +INSERT INTO t1 VALUES (1, 1), (2,2), (3, NULL); +SELECT b, COUNT(DISTINCT a) FROM t1 GROUP BY b HAVING b is NULL; +DROP TABLE t1; + +--echo End of 5.0 tests diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index b085cc5866a..7ecbc92f8f0 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -131,6 +131,8 @@ DROP TABLE `@`; CREATE TABLE `я` (a INT); SET NAMES DEFAULT; --echo mysqlcheck --default-character-set="latin1" --databases test +# Error returned depends on platform, replace it with "Table doesn't exist" +--replace_result "Can't find file: './test/@003f.frm' (errno: 22)" "Table doesn't exist" "Table 'test.?' doesn't exist" "Table doesn't exist" --exec $MYSQL_CHECK --default-character-set="latin1" --databases test --echo mysqlcheck --default-character-set="utf8" --databases test --exec $MYSQL_CHECK --default-character-set="utf8" --databases test diff --git a/mysql-test/t/not_embedded_server.test b/mysql-test/t/not_embedded_server.test index ffc13cf80f7..5beee5967a3 100644 --- a/mysql-test/t/not_embedded_server.test +++ b/mysql-test/t/not_embedded_server.test @@ -20,38 +20,4 @@ prepare stmt1 from ' SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND! execute stmt1; deallocate prepare stmt1; - -# -# Bug#31222: com_% global status counters behave randomly with -# mysql_change_user. -# -# Moved from change_user.test due to Bug#34517: SHOW GLOBAL STATUS does not -# work properly in embedded server. -# -# TODO: move it back when Bug#34517 is fixed. -# - -FLUSH STATUS; - ---disable_result_log ---disable_query_log - -let $i = 100; - -while ($i) -{ - dec $i; - - SELECT 1; -} - ---enable_query_log ---enable_result_log - -SHOW GLOBAL STATUS LIKE 'com_select'; - ---change_user - -SHOW GLOBAL STATUS LIKE 'com_select'; - # End of 5.1 tests diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index fe720ee68b7..6b1ef211fc1 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -1261,6 +1261,33 @@ DROP TABLE t1; SET GLOBAL concurrent_insert= @save_concurrent_insert; SET GLOBAL query_cache_size= default; +# +# Bug#36326: nested transaction and select +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +FLUSH STATUS; +SET GLOBAL query_cache_size=1048576; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3),(4),(5); +SHOW STATUS LIKE 'Qcache_queries_in_cache'; +SELECT * FROM t1; +BEGIN; +SELECT * FROM t1; +COMMIT; +SHOW STATUS LIKE 'Qcache_queries_in_cache'; +SHOW STATUS LIKE "Qcache_hits"; +SELECT * FROM t1; +BEGIN; +SELECT * FROM t1; +COMMIT; +SHOW STATUS LIKE "Qcache_hits"; +DROP TABLE t1; +SET GLOBAL query_cache_size= default; + --echo End of 5.0 tests # diff --git a/mysys/my_init.c b/mysys/my_init.c index 4b45d5ddc1a..0eec242818d 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -78,8 +78,12 @@ my_bool my_init(void) my_umask= 0660; /* Default umask for new files */ my_umask_dir= 0700; /* Default umask for new directories */ init_glob_errs(); -#if defined(THREAD) && defined(SAFE_MUTEX) +#if defined(THREAD) + if (my_thread_global_init()) + return 1; +# if defined(SAFE_MUTEX) safe_mutex_global_init(); /* Must be called early */ +# endif #endif #if defined(THREAD) && defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX) fastmutex_global_init(); /* Must be called early */ @@ -89,8 +93,6 @@ my_bool my_init(void) #if defined(HAVE_PTHREAD_INIT) pthread_init(); /* Must be called before DBUG_ENTER */ #endif - if (my_thread_global_init()) - return 1; #if !defined( __WIN__) && !defined(__NETWARE__) sigfillset(&my_signals); /* signals blocked by mf_brkhant */ #endif diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index 5a2409eeb6f..20b7973cb4e 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -21,6 +21,7 @@ basedir="" builddir="" ldata="@localstatedir@" +langdir="" srcdir="" args="" @@ -106,7 +107,7 @@ parse_arguments() # Note that the user will be passed to mysqld so that it runs # as 'user' (crucial e.g. if log-bin=/some_other_path/ # where a chown of datadir won't help) - user=`parse_arg "$arg"` ;; + user=`parse_arg "$arg"` ;; --skip-name-resolve) ip_only=1 ;; --verbose) verbose=1 ;; # Obsolete --rpm) in_rpm=1 ;; @@ -171,7 +172,20 @@ find_in_basedir() cannot_find_file() { echo - echo "FATAL ERROR: Could not find $*" + echo "FATAL ERROR: Could not find $1" + + shift + if test $# -ne 0 + then + echo + echo "The following directories were searched:" + echo + for dir in "$@" + do + echo " $dir" + done + fi + echo echo "If you compiled from source, you need to run 'make install' to" echo "copy the software into the correct location ready for operation." @@ -210,6 +224,11 @@ then elif test -n "$basedir" then print_defaults=`find_in_basedir my_print_defaults bin extra` + if test -z "$print_defaults" + then + cannot_find_file my_print_defaults $basedir/bin $basedir/extra + exit 1 + fi else print_defaults="@bindir@/my_print_defaults" fi @@ -232,7 +251,7 @@ then bindir="$basedir/client" extra_bindir="$basedir/extra" mysqld="$basedir/sql/mysqld" - mysqld_opt="--language=$srcdir/sql/share/english" + langdir="$srcdir/sql/share/english" pkgdatadir="$srcdir/scripts" scriptdir="$srcdir/scripts" elif test -n "$basedir" @@ -240,7 +259,23 @@ then bindir="$basedir/bin" extra_bindir="$bindir" mysqld=`find_in_basedir mysqld libexec sbin bin` + if test -z "$mysqld" + then + cannot_find_file mysqld $basedir/libexec $basedir/sbin $basedir/bin + exit 1 + fi + langdir=`find_in_basedir --dir errmsg.sys share/english share/mysql/english` + if test -z "$langdir" + then + cannot_find_file errmsg.sys $basedir/share/english $basedir/share/mysql/english + exit 1 + fi pkgdatadir=`find_in_basedir --dir fill_help_tables.sql share share/mysql` + if test -z "$pkgdatadir" + then + cannot_find_file fill_help_tables.sql $basedir/share $basedir/share/mysql + exit 1 + fi scriptdir="$basedir/scripts" else basedir="@prefix@" @@ -271,6 +306,16 @@ then exit 1 fi +if test -n "$langdir" +then + if test ! -f "$langdir/errmsg.sys" + then + cannot_find_file "$langdir/errmsg.sys" + exit 1 + fi + mysqld_opt="--language=$langdir" +fi + # Try to determine the hostname hostname=`@HOSTNAME@` diff --git a/sql/item.cc b/sql/item.cc index d3f933dc13f..2ee6de97ad0 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2090,6 +2090,12 @@ bool Item_field::val_bool_result() } +bool Item_field::is_null_result() +{ + return (null_value=result_field->is_null()); +} + + bool Item_field::eq(const Item *item, bool binary_cmp) const { Item *real_item= ((Item *) item)->real_item(); @@ -5800,6 +5806,15 @@ double Item_ref::val_result() } +bool Item_ref::is_null_result() +{ + if (result_field) + return (null_value=result_field->is_null()); + + return is_null(); +} + + longlong Item_ref::val_int_result() { if (result_field) @@ -5905,7 +5920,9 @@ String *Item_ref::val_str(String* tmp) bool Item_ref::is_null() { DBUG_ASSERT(fixed); - return (*ref)->is_null(); + bool tmp=(*ref)->is_null_result(); + null_value=(*ref)->null_value; + return tmp; } diff --git a/sql/item.h b/sql/item.h index 8c58f0cebe9..be9daf672f0 100644 --- a/sql/item.h +++ b/sql/item.h @@ -729,6 +729,7 @@ public: virtual my_decimal *val_decimal_result(my_decimal *val) { return val_decimal(val); } virtual bool val_bool_result() { return val_bool(); } + virtual bool is_null_result() { return is_null(); } /* bit map of tables used by item */ virtual table_map used_tables() const { return (table_map) 0L; } @@ -1436,6 +1437,7 @@ public: String *str_result(String* tmp); my_decimal *val_decimal_result(my_decimal *); bool val_bool_result(); + bool is_null_result(); bool send(Protocol *protocol, String *str_arg); void reset_field(Field *f); bool fix_fields(THD *, Item **); @@ -2178,6 +2180,7 @@ public: String *str_result(String* tmp); my_decimal *val_decimal_result(my_decimal *); bool val_bool_result(); + bool is_null_result(); bool send(Protocol *prot, String *tmp); void make_field(Send_field *field); bool fix_fields(THD *, Item **); diff --git a/sql/item_func.cc b/sql/item_func.cc index 3cf1671bfa7..ff0c22ecfa9 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4307,6 +4307,15 @@ my_decimal *Item_func_set_user_var::val_decimal_result(my_decimal *val) } +bool Item_func_set_user_var::is_null_result() +{ + DBUG_ASSERT(fixed == 1); + check(TRUE); + update(); // Store expression + return is_null(); +} + + void Item_func_set_user_var::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("(@")); diff --git a/sql/item_func.h b/sql/item_func.h index 512da28589a..e2937a4daf8 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1335,6 +1335,7 @@ public: longlong val_int_result(); String *str_result(String *str); my_decimal *val_decimal_result(my_decimal *); + bool is_null_result(); bool update_hash(void *ptr, uint length, enum Item_result type, CHARSET_INFO *cs, Derivation dv, bool unsigned_arg); bool send(Protocol *protocol, String *str_arg); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index c32ebc6d39d..9ce8077249c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -862,6 +862,8 @@ struct Query_cache_query_flags unsigned int client_protocol_41:1; unsigned int result_in_binary_protocol:1; unsigned int more_results_exists:1; + unsigned int in_trans:1; + unsigned int autocommit:1; unsigned int pkt_nr; uint character_set_client_num; uint character_set_results_num; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 2fca739f667..5e098edbd7f 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1001,6 +1001,8 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) flags.result_in_binary_protocol= (unsigned int) thd->protocol->type(); flags.more_results_exists= test(thd->server_status & SERVER_MORE_RESULTS_EXISTS); + flags.in_trans= test(thd->server_status & SERVER_STATUS_IN_TRANS); + flags.autocommit= test(thd->server_status & SERVER_STATUS_AUTOCOMMIT); flags.pkt_nr= net->pkt_nr; flags.character_set_client_num= thd->variables.character_set_client->number; @@ -1022,7 +1024,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) long %d, 4.1: %d, bin_proto: %d, more results %d, pkt_nr: %d, \ CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \ sql mode: 0x%lx, sort len: %lu, conncat len: %lu, div_precision: %lu, \ -def_week_frmt: %lu", +def_week_frmt: %lu, in_trans: %d, autocommit: %d", (int)flags.client_long_flag, (int)flags.client_protocol_41, (int)flags.result_in_binary_protocol, @@ -1037,7 +1039,10 @@ def_week_frmt: %lu", flags.max_sort_length, flags.group_concat_max_len, flags.div_precision_increment, - flags.default_week_format)); + flags.default_week_format, + (int)flags.in_trans, + (int)flags.autocommit)); + /* Make InnoDB to release the adaptive hash index latch before acquiring the query cache mutex. @@ -1269,6 +1274,8 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) flags.result_in_binary_protocol= (unsigned int)thd->protocol->type(); flags.more_results_exists= test(thd->server_status & SERVER_MORE_RESULTS_EXISTS); + flags.in_trans= test(thd->server_status & SERVER_STATUS_IN_TRANS); + flags.autocommit= test(thd->server_status & SERVER_STATUS_AUTOCOMMIT); flags.pkt_nr= thd->net.pkt_nr; flags.character_set_client_num= thd->variables.character_set_client->number; flags.character_set_results_num= @@ -1288,7 +1295,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) long %d, 4.1: %d, bin_proto: %d, more results %d, pkt_nr: %d, \ CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \ sql mode: 0x%lx, sort len: %lu, conncat len: %lu, div_precision: %lu, \ -def_week_frmt: %lu", +def_week_frmt: %lu, in_trans: %d, autocommit: %d", (int)flags.client_long_flag, (int)flags.client_protocol_41, (int)flags.result_in_binary_protocol, @@ -1303,7 +1310,9 @@ def_week_frmt: %lu", flags.max_sort_length, flags.group_concat_max_len, flags.div_precision_increment, - flags.default_week_format)); + flags.default_week_format, + (int)flags.in_trans, + (int)flags.autocommit)); memcpy((uchar *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)), (uchar*) &flags, QUERY_CACHE_FLAGS_SIZE); query_block = (Query_cache_block *) hash_search(&queries, (uchar*) sql, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 49c0958055e..49cacbe9272 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -109,7 +109,7 @@ static COND* substitute_for_best_equal_field(COND *cond, void *table_join_idx); static COND *simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top); -static bool check_interleaving_with_nj(JOIN_TAB *last, JOIN_TAB *next); +static bool check_interleaving_with_nj(JOIN_TAB *next); static void restore_prev_nj_state(JOIN_TAB *last); static void reset_nj_counters(List<TABLE_LIST> *join_list); static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list, @@ -4889,6 +4889,18 @@ greedy_search(JOIN *join, */ join->positions[idx]= best_pos; + /* + Update the interleaving state after extending the current partial plan + with a new table. + We are doing this here because best_extension_by_limited_search reverts + the interleaving state to the one of the non-extended partial plan + on exit. + */ + IF_DBUG(bool is_interleave_error= ) + check_interleaving_with_nj (best_table); + /* This has been already checked by best_extension_by_limited_search */ + DBUG_ASSERT(!is_interleave_error); + /* find the position of 'best_table' in 'join->best_ref' */ best_idx= idx; JOIN_TAB *pos= join->best_ref[best_idx]; @@ -4906,7 +4918,7 @@ greedy_search(JOIN *join, --size_remain; ++idx; - DBUG_EXECUTE("opt", print_plan(join, join->tables, + DBUG_EXECUTE("opt", print_plan(join, idx, record_count, read_time, read_time, "extended");); } while (TRUE); @@ -5064,7 +5076,7 @@ best_extension_by_limited_search(JOIN *join, table_map real_table_bit= s->table->map; if ((remaining_tables & real_table_bit) && !(remaining_tables & s->dependent) && - (!idx || !check_interleaving_with_nj(join->positions[idx-1].table, s))) + (!idx || !check_interleaving_with_nj(s))) { double current_record_count, current_read_time; @@ -5210,7 +5222,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, { table_map real_table_bit=s->table->map; if ((rest_tables & real_table_bit) && !(rest_tables & s->dependent) && - (!idx|| !check_interleaving_with_nj(join->positions[idx-1].table, s))) + (!idx|| !check_interleaving_with_nj(s))) { double records, best; best_access_path(join, s, thd, rest_tables, idx, record_count, @@ -8790,9 +8802,6 @@ static void reset_nj_counters(List<TABLE_LIST> *join_list) the partial join order. @endverbatim - @param join Join being processed - @param last_tab Last table in current partial join order (this function is - not called for empty partial join orders) @param next_tab Table we're going to extend the current partial join with @retval @@ -8802,10 +8811,10 @@ static void reset_nj_counters(List<TABLE_LIST> *join_list) TRUE Requested join order extension not allowed. */ -static bool check_interleaving_with_nj(JOIN_TAB *last_tab, JOIN_TAB *next_tab) +static bool check_interleaving_with_nj(JOIN_TAB *next_tab) { TABLE_LIST *next_emb= next_tab->table->pos_in_table_list->embedding; - JOIN *join= last_tab->join; + JOIN *join= next_tab->join; if (join->cur_embedding_map & ~next_tab->embedding_map) { diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 5f04dc48b4c..4f30d43f53f 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -17712,6 +17712,63 @@ static void test_bug40365(void) DBUG_VOID_RETURN; } + + +/** + Bug#36326: nested transaction and select +*/ + +#ifdef HAVE_QUERY_CACHE + +static void test_bug36326() +{ + int rc; + + DBUG_ENTER("test_bug36326"); + myheader("test_bug36326"); + + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE t1 (a INTEGER)"); + myquery(rc); + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)"); + myquery(rc); + rc= mysql_query(mysql, "SET GLOBAL query_cache_type = 1"); + myquery(rc); + rc= mysql_query(mysql, "SET GLOBAL query_cache_size = 1048576"); + myquery(rc); + DIE_UNLESS(!(mysql->server_status & SERVER_STATUS_IN_TRANS)); + DIE_UNLESS(mysql->server_status & SERVER_STATUS_AUTOCOMMIT); + rc= mysql_query(mysql, "BEGIN"); + myquery(rc); + DIE_UNLESS(mysql->server_status & SERVER_STATUS_IN_TRANS); + rc= mysql_query(mysql, "SELECT * FROM t1"); + myquery(rc); + rc= my_process_result(mysql); + DIE_UNLESS(rc == 1); + rc= mysql_rollback(mysql); + myquery(rc); + rc= mysql_query(mysql, "ROLLBACK"); + myquery(rc); + DIE_UNLESS(!(mysql->server_status & SERVER_STATUS_IN_TRANS)); + rc= mysql_query(mysql, "SELECT * FROM t1"); + myquery(rc); + DIE_UNLESS(!(mysql->server_status & SERVER_STATUS_IN_TRANS)); + rc= my_process_result(mysql); + DIE_UNLESS(rc == 1); + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + rc= mysql_query(mysql, "SET GLOBAL query_cache_size = 0"); + myquery(rc); + + DBUG_VOID_RETURN; +} + +#endif + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -18025,6 +18082,9 @@ static struct my_tests_st my_tests[]= { #ifdef HAVE_SPATIAL { "test_bug37956", test_bug37956 }, #endif +#ifdef HAVE_QUERY_CACHE + { "test_bug36326", test_bug36326 }, +#endif { 0, 0 } }; |