From cba07d5bfd547319fd5866d76170e18639827bdc Mon Sep 17 00:00:00 2001 From: Karen Langford Date: Wed, 26 Oct 2011 17:03:53 +0200 Subject: [PATCH 01/83] Raise version number after cloning 5.1.60 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 120717d6afa..080de523c1b 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.60], [], [mysql]) +AC_INIT([MySQL Server], [5.1.61], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 9fe16c24087bf149c389c94162d0de686d06772f Mon Sep 17 00:00:00 2001 From: Hery Ramilison Date: Wed, 26 Oct 2011 20:37:36 +0200 Subject: [PATCH 02/83] cloning 5.5.18 off --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7bac52ecdfb..508f021f35d 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=18 +MYSQL_VERSION_PATCH=20 MYSQL_VERSION_EXTRA= From beedf6b261b243ec0a2332162bface6ec7d58dd0 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Mon, 12 Dec 2011 14:07:02 +0100 Subject: [PATCH 03/83] Bug#12361113: CRASH WHEN "LOAD INDEX INTO CACHE" WITH TOO SMALL KEY CACHE The server crashed on division by zero because the key cache was not initialized and the block length was 0 which was used in a division. The fix was to not allow CACHE INDEX if the key cache was not initiallized. Thus never try LOAD INDEX INTO CACHE for an uninitialized key cache. Also added some windows files/directories to .bzrignore. --- .bzrignore | 9 +++++++++ myisam/mi_preload.c | 3 +++ mysql-test/r/key_cache.result | 16 ++++++++++++++++ mysql-test/t/key_cache.test | 16 ++++++++++++++++ sql/sql_table.cc | 5 +++++ 5 files changed, 49 insertions(+) diff --git a/.bzrignore b/.bzrignore index 2b5b42cb87f..184ed9fe235 100644 --- a/.bzrignore +++ b/.bzrignore @@ -8,6 +8,7 @@ *.core *.d *.da +*.dir *.exe *.gcda *.gcno @@ -25,6 +26,7 @@ *.pdb *.reject *.res +*.rule *.sbr *.so *.so.* @@ -32,13 +34,19 @@ *.user *.vcproj *.vcproj.cmake +*.vcxproj +*.vcxproj.filters */*.dir/* +Debug +MySql.sdf +Win32 */*_pure_*warnings */.deps */.libs/* */.pure */debug/* */release/* +RelWithDebInfo *~ .*.swp ./CMakeCache.txt @@ -83,6 +91,7 @@ BitKeeper/tmp/* BitKeeper/tmp/bkr3sAHD BitKeeper/tmp/gone CMakeFiles/* +CMakeFiles COPYING COPYING.LIB Docs/#manual.texi# diff --git a/myisam/mi_preload.c b/myisam/mi_preload.c index c73c70962ed..f53fcd2e1ee 100644 --- a/myisam/mi_preload.c +++ b/myisam/mi_preload.c @@ -54,6 +54,9 @@ int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves) if (!keys || !mi_is_any_key_active(key_map) || key_file_length == pos) DBUG_RETURN(0); + /* Preload into a non initialized key cache should never happen. */ + DBUG_ASSERT(share->key_cache->key_cache_inited); + block_length= keyinfo[0].block_length; if (ignore_leaves) diff --git a/mysql-test/r/key_cache.result b/mysql-test/r/key_cache.result index 9ada5dc0784..6513c4eb374 100644 --- a/mysql-test/r/key_cache.result +++ b/mysql-test/r/key_cache.result @@ -368,3 +368,19 @@ Variable_name Value key_cache_block_size 1536 SET GLOBAL key_cache_block_size= @bug28478_key_cache_block_size; DROP TABLE t1; +# +# Bug#12361113: crash when load index into cache +# +# Note that this creates an empty disabled key cache! +SET GLOBAL key_cache_none.key_cache_block_size = 1024; +CREATE TABLE t1 (a INT, b INTEGER NOT NULL, KEY (b) ) ENGINE = MYISAM; +INSERT INTO t1 VALUES (1, 1); +CACHE INDEX t1 in key_cache_none; +ERROR HY000: Unknown key cache 'key_cache_none' +# The bug crashed the server at LOAD INDEX below. Now it will succeed +# since the default cache is used due to CACHE INDEX failed for +# key_cache_none. +LOAD INDEX INTO CACHE t1; +Table Op Msg_type Msg_text +test.t1 preload_keys status OK +DROP TABLE t1; diff --git a/mysql-test/t/key_cache.test b/mysql-test/t/key_cache.test index 4c14dc96aaa..9d865b9b5fe 100644 --- a/mysql-test/t/key_cache.test +++ b/mysql-test/t/key_cache.test @@ -247,3 +247,19 @@ SET GLOBAL key_cache_block_size= @bug28478_key_cache_block_size; DROP TABLE t1; # End of 4.1 tests + +--echo # +--echo # Bug#12361113: crash when load index into cache +--echo # + +--echo # Note that this creates an empty disabled key cache! +SET GLOBAL key_cache_none.key_cache_block_size = 1024; +CREATE TABLE t1 (a INT, b INTEGER NOT NULL, KEY (b) ) ENGINE = MYISAM; +INSERT INTO t1 VALUES (1, 1); +--error ER_UNKNOWN_KEY_CACHE +CACHE INDEX t1 in key_cache_none; +--echo # The bug crashed the server at LOAD INDEX below. Now it will succeed +--echo # since the default cache is used due to CACHE INDEX failed for +--echo # key_cache_none. +LOAD INDEX INTO CACHE t1; +DROP TABLE t1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4320cef2c49..2bb758f8b86 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2680,6 +2680,11 @@ bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables, DBUG_RETURN(TRUE); } pthread_mutex_unlock(&LOCK_global_system_variables); + if (!key_cache->key_cache_inited) + { + my_error(ER_UNKNOWN_KEY_CACHE, MYF(0), key_cache_name->str); + DBUG_RETURN(TRUE); + } check_opt.key_cache= key_cache; DBUG_RETURN(mysql_admin_table(thd, tables, &check_opt, "assign_to_keycache", TL_READ_NO_INSERT, 0, 0, From e5cb28793385566e22d5a82efdf3f6cb8dbe5cbc Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Thu, 15 Dec 2011 16:59:18 +0100 Subject: [PATCH 04/83] Post push fix for merge.test and mysqlcheck.test on windows --- mysql-test/r/mysqlcheck.result | 1 + mysql-test/t/merge.test | 10 +++++++--- mysql-test/t/mysqlcheck.test | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index 5f1a0565b10..ffba0d443e7 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -147,6 +147,7 @@ DROP TABLE `@`; CREATE TABLE `я` (a INT); SET NAMES DEFAULT; mysqlcheck --default-character-set="latin1" --databases test +call mtr.add_suppression("Can't find file: '..test.@003f.frm'"); test.? Error : Table doesn't exist status : Operation failed diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index a6affbb0540..7954aed6a55 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -1817,9 +1817,13 @@ CREATE TABLE t1(a INT); --echo # Test reattach merge failure LOCK TABLES m1 READ; --echo # Replace 't1' with 't3' table using file operations. -remove_file $MYSQLD_DATADIR/test/t1.frm; -remove_file $MYSQLD_DATADIR/test/t1.MYI; -remove_file $MYSQLD_DATADIR/test/t1.MYD; +# move + remove is a work around for windows. +move_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/oldt1.frm; +move_file $MYSQLD_DATADIR/test/t1.MYI $MYSQLD_DATADIR/test/oldt1.MYI; +move_file $MYSQLD_DATADIR/test/t1.MYD $MYSQLD_DATADIR/test/oldt1.MYD; +remove_file $MYSQLD_DATADIR/test/oldt1.frm; +remove_file $MYSQLD_DATADIR/test/oldt1.MYI; +remove_file $MYSQLD_DATADIR/test/oldt1.MYD; copy_file $MYSQLD_DATADIR/test/t3.frm $MYSQLD_DATADIR/test/t1.frm; copy_file $MYSQLD_DATADIR/test/t3.MYI $MYSQLD_DATADIR/test/t1.MYI; copy_file $MYSQLD_DATADIR/test/t3.MYD $MYSQLD_DATADIR/test/t1.MYD; diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index 986b5aba385..bf99d48fd6a 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -138,6 +138,7 @@ 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" +call mtr.add_suppression("Can't find file: '..test.@003f.frm'"); --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 From 16036b5e61d8f48f352ac4e1f68a541f45f2ae34 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Fri, 16 Dec 2011 12:17:13 +0400 Subject: [PATCH 05/83] Test case for BUG11763712 is intended for 5.1 only. --- mysql-test/r/merge.result | 5 ---- mysql-test/t/merge.test | 53 --------------------------------------- 2 files changed, 58 deletions(-) diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index cd56b5eca5c..6e4e6c5a443 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -2403,11 +2403,6 @@ REPAIR TABLE m1; Table Op Msg_type Msg_text test.m1 repair note The storage engine for the table doesn't support repair DROP TABLE m1, t1; -# -# BUG#11763712 - 56458: KILLING A FLUSH TABLE FOR A MERGE/CHILD -# CRASHES SERVER -# -# Disabled in 5.5 by Mattias. TODO: FIX THIS! End of 5.1 tests # # An additional test case for Bug#27430 Crash in subquery code diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 64327400a4f..74110962299 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -1812,59 +1812,6 @@ REPAIR TABLE m1; # DROP TABLE m1, t1; - ---echo # ---echo # BUG#11763712 - 56458: KILLING A FLUSH TABLE FOR A MERGE/CHILD ---echo # CRASHES SERVER ---echo # ---echo # Disabled in 5.5 by Mattias. TODO: FIX THIS! -if (0) -{ -CREATE TABLE t1(a INT); -CREATE TABLE t2(a INT); -CREATE TABLE t3(a INT, b INT); -CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); - ---echo # Test reopen merge parent failure -LOCK TABLES m1 READ; ---echo # Remove 'm1' table using file operations. -remove_file $MYSQLD_DATADIR/test/m1.MRG; -remove_file $MYSQLD_DATADIR/test/m1.frm; ---error ER_NO_SUCH_TABLE -FLUSH TABLES; -UNLOCK TABLES; -CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); - ---echo # Test reopen merge child failure -LOCK TABLES m1 READ; ---echo # Remove 't1' table using file operations. -remove_file $MYSQLD_DATADIR/test/t1.frm; -remove_file $MYSQLD_DATADIR/test/t1.MYI; -remove_file $MYSQLD_DATADIR/test/t1.MYD; ---error ER_NO_SUCH_TABLE -FLUSH TABLES; -UNLOCK TABLES; -CREATE TABLE t1(a INT); - ---echo # Test reattach merge failure -LOCK TABLES m1 READ; ---echo # Replace 't1' with 't3' table using file operations. -# move + remove is a work around for windows. -move_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/oldt1.frm; -move_file $MYSQLD_DATADIR/test/t1.MYI $MYSQLD_DATADIR/test/oldt1.MYI; -move_file $MYSQLD_DATADIR/test/t1.MYD $MYSQLD_DATADIR/test/oldt1.MYD; -remove_file $MYSQLD_DATADIR/test/oldt1.frm; -remove_file $MYSQLD_DATADIR/test/oldt1.MYI; -remove_file $MYSQLD_DATADIR/test/oldt1.MYD; -copy_file $MYSQLD_DATADIR/test/t3.frm $MYSQLD_DATADIR/test/t1.frm; -copy_file $MYSQLD_DATADIR/test/t3.MYI $MYSQLD_DATADIR/test/t1.MYI; -copy_file $MYSQLD_DATADIR/test/t3.MYD $MYSQLD_DATADIR/test/t1.MYD; ---error ER_CANT_REOPEN_TABLE -FLUSH TABLES; -UNLOCK TABLES; -DROP TABLE t1, t2, t3, m1; -} - --echo End of 5.1 tests --echo # From bad3e4179c5471728fb0dc3d72b81db02129128f Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Mon, 19 Dec 2011 14:55:30 -0800 Subject: [PATCH 06/83] Fixed LP bug #906322. If the sorted table belongs to a dependent subquery then the function create_sort_index() should not clear TABLE:: select and TABLE::select for this table after the sort of the table has been performed, because these members are needed for the second execution of the subquery. --- mysql-test/r/subselect.result | 2 -- mysql-test/suite/innodb/r/innodb_mysql.result | 6 +++--- mysql-test/suite/innodb_plugin/r/innodb_mysql.result | 6 +++--- sql/sql_select.cc | 2 -- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 1a56940a560..1f3432ecde1 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4631,8 +4631,6 @@ SELECT * FROM t1 WHERE EXISTS (SELECT DISTINCT a FROM t2 WHERE t1.a < t2.a ORDER BY b); pk a 1 10 -3 30 -2 20 DROP TABLE t1,t2; CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a), KEY b (b)); INSERT INTO t1 VALUES (1,NULL), (9,NULL); diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result index 42aca8b6464..666d6b7591f 100644 --- a/mysql-test/suite/innodb/r/innodb_mysql.result +++ b/mysql-test/suite/innodb/r/innodb_mysql.result @@ -1739,7 +1739,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED t1 ALL c3,c2 c3 5 5 Using filesort +2 DERIVED t1 ALL c3,c2 c3 5 5 Using where; Using filesort DROP TABLE t1; CREATE TABLE t1 (c1 REAL, c2 REAL, c3 REAL, KEY (c3), KEY (c2, c3)) ENGINE=InnoDB; @@ -1753,7 +1753,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED t1 ALL c3,c2 c3 9 5 Using filesort +2 DERIVED t1 ALL c3,c2 c3 9 5 Using where; Using filesort DROP TABLE t1; CREATE TABLE t1 (c1 DECIMAL(12,2), c2 DECIMAL(12,2), c3 DECIMAL(12,2), KEY (c3), KEY (c2, c3)) @@ -1768,7 +1768,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED t1 ALL c3,c2 c3 7 5 Using filesort +2 DERIVED t1 ALL c3,c2 c3 7 5 Using where; Using filesort DROP TABLE t1; End of 5.1 tests drop table if exists t1, t2, t3; diff --git a/mysql-test/suite/innodb_plugin/r/innodb_mysql.result b/mysql-test/suite/innodb_plugin/r/innodb_mysql.result index 86d83f82b76..987a04eb59d 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_mysql.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_mysql.result @@ -1739,7 +1739,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED t1 ALL c3,c2 c3 5 5 Using filesort +2 DERIVED t1 ALL c3,c2 c3 5 5 Using where; Using filesort DROP TABLE t1; CREATE TABLE t1 (c1 REAL, c2 REAL, c3 REAL, KEY (c3), KEY (c2, c3)) ENGINE=InnoDB; @@ -1753,7 +1753,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED t1 ALL c3,c2 c3 9 5 Using filesort +2 DERIVED t1 ALL c3,c2 c3 9 5 Using where; Using filesort DROP TABLE t1; CREATE TABLE t1 (c1 DECIMAL(12,2), c2 DECIMAL(12,2), c3 DECIMAL(12,2), KEY (c3), KEY (c2, c3)) @@ -1768,7 +1768,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED t1 ALL c3,c2 c3 7 5 Using filesort +2 DERIVED t1 ALL c3,c2 c3 7 5 Using where; Using filesort DROP TABLE t1; End of 5.1 tests drop table if exists t1, t2, t3; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3e6fac841b2..219e0ebe406 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14466,11 +14466,9 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, table->sort.io_cache= NULL; select->cleanup(); // filesort did select - tab->select= 0; table->quick_keys.clear_all(); // as far as we cleanup select->quick table->sort.io_cache= tablesort_result_cache; } - tab->select_cond=0; tab->last_inner= 0; tab->first_unmatched= 0; tab->type=JT_ALL; // Read with normal read_record From 27380e4fb522062daa0d7775a3205363a5c1b110 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 20 Dec 2011 01:56:41 -0800 Subject: [PATCH 07/83] Fixed LP bug #794005. The function st_table::mark_virtual_columns_for_write() did not take into account the fact that for any table the value of st_table::vfield is 0 when there are no virtual columns in the table definition. --- mysql-test/r/view.result | 11 +++++++++++ mysql-test/t/view.test | 16 ++++++++++++++++ sql/table.cc | 3 +++ 3 files changed, 30 insertions(+) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 40142c5e0a7..22fd4eb1722 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -3926,3 +3926,14 @@ drop table t1,t2; # ----------------------------------------------------------------- # -- End of 5.1 tests. # ----------------------------------------------------------------- +# +# Bug #794005: crash in st_table::mark_virtual_columns_for_write +# +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); +CREATE VIEW v2 AS SELECT * FROM t2; +CREATE VIEW v1 AS SELECT * FROM v2; +CREATE OR REPLACE ALGORITHM = TEMPTABLE VIEW v2 AS SELECT * FROM t1; +UPDATE v1 SET a = 10; +DROP VIEW v1,v2; +DROP TABLE t1,t2; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 644fbe0443f..462118af4ea 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -3976,3 +3976,19 @@ drop table t1,t2; --echo # ----------------------------------------------------------------- --echo # -- End of 5.1 tests. --echo # ----------------------------------------------------------------- + +--echo # +--echo # Bug #794005: crash in st_table::mark_virtual_columns_for_write +--echo # + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); + +CREATE VIEW v2 AS SELECT * FROM t2; +CREATE VIEW v1 AS SELECT * FROM v2; +CREATE OR REPLACE ALGORITHM = TEMPTABLE VIEW v2 AS SELECT * FROM t1; + +UPDATE v1 SET a = 10; + +DROP VIEW v1,v2; +DROP TABLE t1,t2; diff --git a/sql/table.cc b/sql/table.cc index ca5e4678c52..ca14b2ef4d2 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5161,6 +5161,9 @@ void st_table::mark_virtual_columns_for_write(bool insert_fl) Field **vfield_ptr, *tmp_vfield; bool bitmap_updated= FALSE; + if (!vfield) + return; + for (vfield_ptr= vfield; *vfield_ptr; vfield_ptr++) { tmp_vfield= *vfield_ptr; From 7b29727a5a730d9baef822418e899f8ac5302587 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 21 Dec 2011 12:45:53 +0200 Subject: [PATCH 08/83] Supression condition made wider to cover some other system cases. --- mysql-test/valgrind.supp | 130 +++------------------------------------ 1 file changed, 7 insertions(+), 123 deletions(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 26e2c1261ab..30d77fa3e72 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -386,134 +386,18 @@ fun:__libc_start_main } +# +# dlclose can allocate memory for error message, the memory will be +# freed by dlerror or other dl* function. +# { - dlclose memory loss from udf_free + memory "loss" from dlclose error messages Memcheck:Leak - fun:calloc - fun:_dlerror_run + fun:*alloc + ... fun:dlclose - fun:_Z8udf_freev } -{ - dlsym memory loss from udf_free on SuSE 11.1 x64 variant 2 - Memcheck:Leak - fun:calloc - obj:/lib*/ld-*.so - fun:dlclose - fun:udf_free -} - -{ - dlclose memory loss from plugin variant 1 - Memcheck:Leak - fun:calloc - fun:_dlerror_run - fun:dlclose - fun:plugin_dl_del(st_mysql_lex_string const*) -} - -{ - dlclose memory loss from plugin variant 2 - Memcheck:Leak - fun:malloc - fun:_dl_close_worker - fun:_dl_close - fun:_dl_catch_error - fun:_dlerror_run - fun:dlclose - fun:_Z15free_plugin_memP12st_plugin_dl - fun:_Z13plugin_dl_delPK19st_mysql_lex_string -} - -{ - dlclose memory loss from plugin variant 3 - Memcheck:Leak - fun:malloc - fun:_dl_scope_free - fun:_dl_close_worker - fun:_dl_close - fun:_dl_catch_error - fun:_dlerror_run - fun:dlclose - fun:_Z15free_plugin_memP12st_plugin_dl - fun:_Z13plugin_dl_delPK19st_mysql_lex_string -} - -{ - dlclose memory loss from plugin variant 4 - Memcheck:Leak - fun:malloc - obj:/lib*/ld-*.so - obj:/lib*/ld-*.so - obj:/lib*/ld-*.so - obj:/lib*/libdl-*.so - fun:dlclose - fun:_ZL15free_plugin_memP12st_plugin_dl - fun:_ZL13plugin_dl_delPK19st_mysql_lex_string -} - -{ - dlclose memory loss from plugin variant 5 - Memcheck:Leak - fun:malloc - obj:/lib*/ld-*.so - obj:/lib*/ld-*.so - obj:/lib*/ld-*.so - obj:/lib*/ld-*.so - obj:/lib*/libdl-*.so - fun:dlclose - fun:_ZL15free_plugin_memP12st_plugin_dl -} - -{ - dlclose memory loss from plugin variant 6, seen on Ubuntu Jaunty i686 - Memcheck:Leak - fun:malloc - fun:_dl_scope_free - fun:_dl_close_worker - fun:_dl_close - fun:dlclose_doit - fun:_dl_catch_error - fun:_dlerror_run - fun:dlclose - fun:_ZL15free_plugin_memP12st_plugin_dl - fun:_ZL13plugin_dl_delPK19st_mysql_lex_string -} - -{ - dlclose memory loss from plugin variant 7, seen on Ubuntu Jaunty i686 - Memcheck:Leak - fun:malloc - fun:_dl_close_worker - fun:_dl_close - fun:dlclose_doit - fun:_dl_catch_error - fun:_dlerror_run - fun:dlclose - fun:_ZL15free_plugin_memP12st_plugin_dl - fun:_ZL13plugin_dl_delPK19st_mysql_lex_string -} - -{ - dlclose memory loss from plugin variant 8 - Memcheck:Leak - fun:calloc - fun:_dlerror_run - fun:dlclose - fun:_Z15free_plugin_memP12st_plugin_dl - fun:_Z13plugin_dl_delPK19st_mysql_lex_string -} - -{ - dlclose memory loss from plugin variant 9 - Memcheck:Leak - fun:calloc - fun:_dlerror_run - fun:dlclose - fun:_ZL15free_plugin_memP12st_plugin_dl - fun:_ZL13plugin_dl_delPK19st_mysql_lex_string -} { dlsym memory loss from plugin on SuSE 11.1 x64 From 2be9a419f5e680dbb9b02fe6ce1f07d2442ae938 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 21 Dec 2011 13:23:15 +0200 Subject: [PATCH 09/83] Fixes lp:907049 "Server started with skip-aria crashes on an attempt to connect to it" sql/sql_parse.cc: Only call ha_maria::implicit_commit if aria is enabled --- sql/sql_parse.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 41f308a2ce4..8c51ea69618 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -190,7 +190,8 @@ bool end_active_trans(THD *thd) if (ha_commit(thd)) error=1; #ifdef WITH_MARIA_STORAGE_ENGINE - ha_maria::implicit_commit(thd, TRUE); + if (ha_storage_engine_is_enabled(maria_hton)) + ha_maria::implicit_commit(thd, TRUE); #endif } thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); @@ -1297,6 +1298,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, char *beginning_of_next_stmt= (char*) end_of_stmt; #ifdef WITH_MARIA_STORAGE_ENGINE + if (ha_storage_engine_is_enabled(maria_hton)) ha_maria::implicit_commit(thd, FALSE); #endif @@ -1722,7 +1724,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->transaction.stmt.reset(); #ifdef WITH_MARIA_STORAGE_ENGINE - ha_maria::implicit_commit(thd, FALSE); + if (ha_storage_engine_is_enabled(maria_hton)) + ha_maria::implicit_commit(thd, FALSE); #endif if (!(sql_command_flags[thd->lex->sql_command] & CF_CHANGES_DATA)) From a5e92c7e6d8a6540a63038e4b982599cec2d077f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 22 Dec 2011 11:07:04 +0100 Subject: [PATCH 10/83] compilation warning - unused variable --- storage/maria/ha_maria.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 99a1e2cc903..04a97da9d8d 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -2430,8 +2430,8 @@ int ha_maria::extra_opt(enum ha_extra_function operation, ulong cache_size) int ha_maria::delete_all_rows() { - THD *thd= table->in_use; #ifdef EXTRA_DEBUG + THD *thd= table->in_use; TRN *trn= file->trn; if (trn && ! (trnman_get_flags(trn) & TRN_STATE_INFO_LOGGED)) { From 0e8f71b2bcd8430fa0f1677fa605a6b0fc5daf7b Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 22 Dec 2011 15:50:33 +0100 Subject: [PATCH 11/83] LPBUG#906638 : Fixes to build oqgraph with boost 1.48 - dijkstra_shortest_paths() needs a Graph as first parameter, in case of reverse_graph we now need to use its m_g member - use boost::tuples::tie() on all places where tie() was used . Reason - fix the build with Visual Studio 10 SP1 (which includes std:tr1:tie, thus creating ambiguity) --- storage/oqgraph/graphcore.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/storage/oqgraph/graphcore.cc b/storage/oqgraph/graphcore.cc index 0b856ac253f..ba179989ea3 100644 --- a/storage/oqgraph/graphcore.cc +++ b/storage/oqgraph/graphcore.cc @@ -414,7 +414,7 @@ namespace open_query { if (record_weight && u != v) { typename graph_traits::out_edge_iterator ei, ei_end; - for (tie(ei, ei_end)= out_edges(v, g); ei != ei_end; ++ei) + for (boost::tuples::tie(ei, ei_end)= out_edges(v, g); ei != ei_end; ++ei) { if (target(*ei, g) == u) { @@ -479,14 +479,14 @@ namespace open_query if (in_degree(dest, g) >= out_degree(orig, g)) { graph_traits::out_edge_iterator ei, ei_end; - tie(ei, ei_end)= out_edges(orig, g); + boost::tuples::tie(ei, ei_end)= out_edges(orig, g); if ((ei= find_if(ei, ei_end, target_equals(dest, g))) != ei_end) return *ei; } else { graph_traits::in_edge_iterator ei, ei_end; - tie(ei, ei_end)= in_edges(dest, g); + boost::tuples::tie(ei, ei_end)= in_edges(dest, g); if ((ei= find_if(ei, ei_end, source_equals(orig, g))) != ei_end) return *ei; } @@ -727,7 +727,7 @@ namespace open_query if ((cursor= new (std::nothrow) stack_cursor(share)) && orig) { graph_traits::out_edge_iterator ei, ei_end; - for (tie(ei, ei_end)= out_edges(*orig, share->g); ei != ei_end; ++ei) + for (boost::tuples::tie(ei, ei_end)= out_edges(*orig, share->g); ei != ei_end; ++ei) { Vertex v= target(*ei, share->g); static_cast(cursor)-> @@ -741,7 +741,7 @@ namespace open_query dest) { graph_traits::in_edge_iterator ei, ei_end; - for (tie(ei, ei_end)= in_edges(*dest, share->g); ei != ei_end; ++ei) + for (boost::tuples::tie(ei, ei_end)= in_edges(*dest, share->g); ei != ei_end; ++ei) { Vertex v= source(*ei, share->g); static_cast(cursor)-> @@ -876,7 +876,7 @@ namespace open_query switch (ALGORITHM & op) { case DIJKSTRAS: - dijkstra_shortest_paths(r, *dest, + dijkstra_shortest_paths(r.m_g, *dest, weight_map( share->weightmap ). @@ -1067,7 +1067,7 @@ int edges_cursor::fetch_row(const row &row_info, row &result) edge_iterator it, end; reference ref; size_t count= position; - for (tie(it, end)= edges(share->g); count && it != end; ++it, --count) + for (boost::tuples::tie(it, end)= edges(share->g); count && it != end; ++it, --count) ; if (it != end) ref= reference(position+1, *it); From c9259f166bfcc757338c957f806e3d18637da17a Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 27 Dec 2011 13:19:13 -0800 Subject: [PATCH 12/83] Fixed LP bug #904345. The MIN/MAX optimizer code from the function opt_sum_query erroneously did not take into account conjunctive conditions that did not depend on any table, yet were not identified as constant items. These could be items containing rand() or PS/SP parameters. These items are supposed to be evaluated at the execution phase. That's why if such conditions can be extracted from the WHERE condition the MIN/MAX optimization is not applied as currently it is always done at the optimization phase. (In 5.3 expensive subqueries are also evaluated only at the execution phase. So, if a constant condition with such subquery can be extracted from the WHERE clause the MIN/MAX optimization should not be applied in 5.3.) IF an IN/ALL/SOME predicate with a constant left part is transformed into an EXISTS subquery the resulting subquery should not be considered uncacheable if the right part of the predicate is not uncacheable. Backported the function dbug_print_item() from 5.3. The function is used only for debugging. --- mysql-test/r/func_group.result | 40 +++++++++++++++++++++++- mysql-test/r/ps_11bugs.result | 6 ++-- mysql-test/r/select.result | 8 ++--- mysql-test/r/select_pkeycache.result | 8 ++--- mysql-test/r/subselect.result | 14 ++++----- mysql-test/suite/pbxt/r/ps_11bugs.result | 6 ++-- mysql-test/suite/pbxt/r/select.result | 8 ++--- mysql-test/suite/pbxt/r/subselect.result | 4 +-- mysql-test/t/func_group.test | 27 +++++++++++++++- sql/item.cc | 21 +++++++++++++ sql/item_subselect.cc | 13 +++++--- sql/opt_sum.cc | 3 +- 12 files changed, 123 insertions(+), 35 deletions(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 2ff1cd2ec4a..de5672941c7 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1767,4 +1767,42 @@ MAX(a) 10 drop table t1; # -End of 5.1 tests +# Bug #904345: MIN/MAX optimization with constant FALSE condition +# +CREATE TABLE t1 (a int NOT NULL, KEY(a)); +INSERT INTO t1 VALUES (10), (8), (11), (7), (15), (12), (9); +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES +(8,2), (6,9), (8,4), (5,3), (9,1); +EXPLAIN EXTENDED +SELECT MAX(a) FROM t1 WHERE (1,2) IN (SELECT 3,4) AND a<10; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible HAVING +Warnings: +Note 1003 select max(`test`.`t1`.`a`) AS `MAX(a)` from `test`.`t1` where 0 +SELECT MAX(a) FROM t1 WHERE (1,2) IN (SELECT 3,4) AND a<10; +MAX(a) +NULL +EXPLAIN EXTENDED +SELECT MAX(a) FROM t1 WHERE (1,2) IN (SELECT a,b FROM t2 WHERE b<5) and a<10; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where +Warnings: +Note 1003 select max(`test`.`t1`.`a`) AS `MAX(a)` from `test`.`t1` where 0 +SELECT MAX(a) FROM t1 WHERE (1,2) IN (SELECT a,b FROM t2 WHERE b<5) and a<10; +MAX(a) +NULL +EXPLAIN EXTENDED +SELECT MAX(a) FROM t1 WHERE RAND()*0<>0 AND a<10; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range a a 4 NULL 4 100.00 Using where; Using index +Warnings: +Note 1003 select max(`test`.`t1`.`a`) AS `MAX(a)` from `test`.`t1` where (((rand() * 0) <> 0) and (`test`.`t1`.`a` < 10)) +SELECT MAX(a) FROM t1 WHERE RAND()*0<>0 AND a<10; +MAX(a) +NULL +DROP TABLE t1,t2; +# +End of 5.2 tests diff --git a/mysql-test/r/ps_11bugs.result b/mysql-test/r/ps_11bugs.result index 5c11163ab9e..3b4d525aeb4 100644 --- a/mysql-test/r/ps_11bugs.result +++ b/mysql-test/r/ps_11bugs.result @@ -120,9 +120,9 @@ create table t1 (a int primary key); insert into t1 values (1); explain select * from t1 where 3 in (select (1+1) union select 1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables -2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible HAVING -3 DEPENDENT UNION NULL NULL NULL NULL NULL NULL NULL Impossible HAVING +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible HAVING +3 UNION NULL NULL NULL NULL NULL NULL NULL Impossible HAVING NULL UNION RESULT ALL NULL NULL NULL NULL NULL select * from t1 where 3 in (select (1+1) union select 1); a diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 5453345d50c..e2c2dcaced4 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2778,10 +2778,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away explain select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +1 SIMPLE t1 index key1 key1 5 NULL 4 Using where; Using index explain select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +1 SIMPLE t1 range key1 key1 5 NULL 3 Using where; Using index select max(key1) from t1 where key1 <= 0.6158; max(key1) 0.615800023078918 @@ -2800,10 +2800,10 @@ max(key1) min(key2) 0.615800023078918 1.37619996070862 select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; max(key1) -0.615800023078918 +0.384499996900558 select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; min(key1) -0.376199990510941 +0.384499996900558 DROP TABLE t1,t2; CREATE TABLE t1 (i BIGINT UNSIGNED NOT NULL); INSERT INTO t1 VALUES (10); diff --git a/mysql-test/r/select_pkeycache.result b/mysql-test/r/select_pkeycache.result index 5453345d50c..e2c2dcaced4 100644 --- a/mysql-test/r/select_pkeycache.result +++ b/mysql-test/r/select_pkeycache.result @@ -2778,10 +2778,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away explain select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +1 SIMPLE t1 index key1 key1 5 NULL 4 Using where; Using index explain select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +1 SIMPLE t1 range key1 key1 5 NULL 3 Using where; Using index select max(key1) from t1 where key1 <= 0.6158; max(key1) 0.615800023078918 @@ -2800,10 +2800,10 @@ max(key1) min(key2) 0.615800023078918 1.37619996070862 select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; max(key1) -0.615800023078918 +0.384499996900558 select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; min(key1) -0.376199990510941 +0.384499996900558 DROP TABLE t1,t2; CREATE TABLE t1 (i BIGINT UNSIGNED NOT NULL); INSERT INTO t1 VALUES (10); diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 1f3432ecde1..65e76d04c1f 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1302,7 +1302,7 @@ SELECT 0 IN (SELECT 1 FROM t1 a); EXPLAIN EXTENDED SELECT 0 IN (SELECT 1 FROM t1 a); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used -2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE Warnings: Note 1003 select (0,(select 1 from `test`.`t1` `a` where 0)) AS `0 IN (SELECT 1 FROM t1 a)` INSERT INTO t1 (pseudo) VALUES ('test1'); @@ -1312,7 +1312,7 @@ SELECT 0 IN (SELECT 1 FROM t1 a); EXPLAIN EXTENDED SELECT 0 IN (SELECT 1 FROM t1 a); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used -2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE Warnings: Note 1003 select (0,(select 1 from `test`.`t1` `a` where 0)) AS `0 IN (SELECT 1 FROM t1 a)` drop table t1; @@ -4476,15 +4476,15 @@ INSERT INTO t1 VALUES (1),(2); EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 GROUP BY a); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 -2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort +2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort Warnings: -Note 1003 select 1 AS `1` from `test`.`t1` where (1,(select 1 from `test`.`t1` group by `test`.`t1`.`a` having 1)) +Note 1003 select 1 AS `1` from `test`.`t1` where 1 EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables -2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary; Using filesort +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using temporary; Using filesort Warnings: -Note 1003 select 1 AS `1` from `test`.`t1` where (1,(select 1 from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` having 1)) +Note 1003 select 1 AS `1` from `test`.`t1` where 0 DROP TABLE t1; # # Bug#45061: Incorrectly market field caused wrong result. diff --git a/mysql-test/suite/pbxt/r/ps_11bugs.result b/mysql-test/suite/pbxt/r/ps_11bugs.result index fad35b97b24..0be781bca27 100644 --- a/mysql-test/suite/pbxt/r/ps_11bugs.result +++ b/mysql-test/suite/pbxt/r/ps_11bugs.result @@ -120,9 +120,9 @@ create table t1 (a int primary key); insert into t1 values (1); explain select * from t1 where 3 in (select (1+1) union select 1); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables -2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible HAVING -3 DEPENDENT UNION NULL NULL NULL NULL NULL NULL NULL Impossible HAVING +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible HAVING +3 UNION NULL NULL NULL NULL NULL NULL NULL Impossible HAVING NULL UNION RESULT ALL NULL NULL NULL NULL NULL select * from t1 where 3 in (select (1+1) union select 1); a diff --git a/mysql-test/suite/pbxt/r/select.result b/mysql-test/suite/pbxt/r/select.result index c06dd06ea3e..b98f980f821 100644 --- a/mysql-test/suite/pbxt/r/select.result +++ b/mysql-test/suite/pbxt/r/select.result @@ -2786,10 +2786,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away explain select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +1 SIMPLE t1 index key1 key1 5 NULL 4 Using where; Using index explain select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +1 SIMPLE t1 index key1 key1 5 NULL 4 Using where; Using index select max(key1) from t1 where key1 <= 0.6158; max(key1) 0.615800023078918 @@ -2808,10 +2808,10 @@ max(key1) min(key2) 0.615800023078918 1.37619996070862 select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; max(key1) -0.615800023078918 +0.384499996900558 select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; min(key1) -0.376199990510941 +0.384499996900558 DROP TABLE t1,t2; CREATE TABLE t1 (i BIGINT UNSIGNED NOT NULL); INSERT INTO t1 VALUES (10); diff --git a/mysql-test/suite/pbxt/r/subselect.result b/mysql-test/suite/pbxt/r/subselect.result index 0cdec48e192..63b289d259e 100644 --- a/mysql-test/suite/pbxt/r/subselect.result +++ b/mysql-test/suite/pbxt/r/subselect.result @@ -1177,7 +1177,7 @@ SELECT 0 IN (SELECT 1 FROM t1 a); EXPLAIN EXTENDED SELECT 0 IN (SELECT 1 FROM t1 a); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used -2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE Warnings: Note 1003 select (0,(select 1 from `test`.`t1` `a` where 0)) AS `0 IN (SELECT 1 FROM t1 a)` INSERT INTO t1 (pseudo) VALUES ('test1'); @@ -1187,7 +1187,7 @@ SELECT 0 IN (SELECT 1 FROM t1 a); EXPLAIN EXTENDED SELECT 0 IN (SELECT 1 FROM t1 a); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used -2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE Warnings: Note 1003 select (0,(select 1 from `test`.`t1` `a` where 0)) AS `0 IN (SELECT 1 FROM t1 a)` drop table t1; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 8c2be79ee7d..84afe328aeb 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -1150,4 +1150,29 @@ SELECT MAX(a) FROM t1 WHERE a NOT BETWEEN 3 AND 9; drop table t1; --echo # ---echo End of 5.1 tests +--echo # Bug #904345: MIN/MAX optimization with constant FALSE condition +--echo # + +CREATE TABLE t1 (a int NOT NULL, KEY(a)); +INSERT INTO t1 VALUES (10), (8), (11), (7), (15), (12), (9); + +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES + (8,2), (6,9), (8,4), (5,3), (9,1); + +EXPLAIN EXTENDED +SELECT MAX(a) FROM t1 WHERE (1,2) IN (SELECT 3,4) AND a<10; +SELECT MAX(a) FROM t1 WHERE (1,2) IN (SELECT 3,4) AND a<10; + +EXPLAIN EXTENDED +SELECT MAX(a) FROM t1 WHERE (1,2) IN (SELECT a,b FROM t2 WHERE b<5) and a<10; +SELECT MAX(a) FROM t1 WHERE (1,2) IN (SELECT a,b FROM t2 WHERE b<5) and a<10; + +EXPLAIN EXTENDED +SELECT MAX(a) FROM t1 WHERE RAND()*0<>0 AND a<10; +SELECT MAX(a) FROM t1 WHERE RAND()*0<>0 AND a<10; + +DROP TABLE t1,t2; + +--echo # +--echo End of 5.2 tests diff --git a/sql/item.cc b/sql/item.cc index c08333e4b80..72adb9d0b52 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7915,6 +7915,27 @@ void view_error_processor(THD *thd, void *data) ((TABLE_LIST *)data)->hide_view_error(thd); } +#ifndef DBUG_OFF + +/* Debugger help function */ +static char dbug_item_print_buf[256]; + +const char *dbug_print_item(Item *item) +{ + char *buf= dbug_item_print_buf; + String str(buf, sizeof(dbug_item_print_buf), &my_charset_bin); + str.length(0); + if (!item) + return "(Item*)NULL"; + item->print(&str ,QT_ORDINARY); + if (str.c_ptr() == buf) + return buf; + else + return "Couldn't fit into buffer"; +} + +#endif /*DBUG_OFF*/ + /***************************************************************************** ** Instantiate templates *****************************************************************************/ diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index fa9eff0d95b..82d2313aa2b 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1117,8 +1117,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, (Item**)optimizer->get_cache(), (char *)"", (char *)in_left_expr_name); - - master_unit->uncacheable|= UNCACHEABLE_DEPENDENT; + if (!left_expr->const_item()) + master_unit->uncacheable|= UNCACHEABLE_DEPENDENT; } if (!abort_on_null && left_expr->maybe_null && !pushed_cond_guards) { @@ -1127,7 +1127,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, pushed_cond_guards[0]= TRUE; } - select_lex->uncacheable|= UNCACHEABLE_DEPENDENT; + if (!left_expr->const_item()) + select_lex->uncacheable|= UNCACHEABLE_DEPENDENT; if (join->having || select_lex->with_sum_func || select_lex->group_list.elements) { @@ -1338,7 +1339,8 @@ Item_in_subselect::row_value_transformer(JOIN *join) optimizer->keep_top_level_cache(); thd->lex->current_select= current; - master_unit->uncacheable|= UNCACHEABLE_DEPENDENT; + if (!left_expr->const_item()) + master_unit->uncacheable|= UNCACHEABLE_DEPENDENT; if (!abort_on_null && left_expr->maybe_null && !pushed_cond_guards) { @@ -1350,7 +1352,8 @@ Item_in_subselect::row_value_transformer(JOIN *join) } } - select_lex->uncacheable|= UNCACHEABLE_DEPENDENT; + if (!left_expr->const_item()) + select_lex->uncacheable|= UNCACHEABLE_DEPENDENT; if (is_having_used) { /* diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index f8a81eac380..27a848cb0ec 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -608,7 +608,8 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, if (!cond) DBUG_RETURN(TRUE); Field *field= field_part->field; - if (!(cond->used_tables() & field->table->map)) + if (!(cond->used_tables() & field->table->map) && + test(cond->used_tables() & ~PSEUDO_TABLE_BITS)) { /* Condition doesn't restrict the used table */ DBUG_RETURN(TRUE); From 31805e621495e33d4dcf4e4b2180d42367f90894 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 27 Dec 2011 19:13:53 -0800 Subject: [PATCH 13/83] Fixed LP bug #879860. The MIN/MAX optimization cannot be applied to a subquery if its WHERE clause contains a conjunctive condition depending on an outer reference. --- mysql-test/r/func_group.result | 23 +++++++++++++++++++++++ mysql-test/t/func_group.test | 19 +++++++++++++++++++ sql/opt_sum.cc | 4 ++++ 3 files changed, 46 insertions(+) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index de5672941c7..3608f587572 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1805,4 +1805,27 @@ MAX(a) NULL DROP TABLE t1,t2; # +# Bug #879860: MIN/MAX for subquery returning empty set +# +CREATE TABLE t1 (a int PRIMARY KEY); +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 (a int NOT NULL); +INSERT INTO t2 VALUES (10); +CREATE TABLE t3 ( a int, b int); +INSERT INTO t3 VALUES (19,1), (20,5); +EXPLAIN EXTENDED +SELECT (SELECT MIN(t1.a) FROM t1,t2 WHERE t2.a = t3.b) FROM t3; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 2 100.00 +2 DEPENDENT SUBQUERY t1 system NULL NULL NULL NULL 1 100.00 +2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 1 100.00 +Warnings: +Note 1276 Field or reference 'test.t3.b' of SELECT #2 was resolved in SELECT #1 +Note 1003 select (select min('1') from `test`.`t1` join `test`.`t2` where ('10' = `test`.`t3`.`b`)) AS `(SELECT MIN(t1.a) FROM t1,t2 WHERE t2.a = t3.b)` from `test`.`t3` +SELECT (SELECT MIN(t1.a) FROM t1,t2 WHERE t2.a = t3.b) FROM t3; +(SELECT MIN(t1.a) FROM t1,t2 WHERE t2.a = t3.b) +NULL +NULL +DROP TABLE t1,t2,t3; +# End of 5.2 tests diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 84afe328aeb..3939d53cb31 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -1174,5 +1174,24 @@ SELECT MAX(a) FROM t1 WHERE RAND()*0<>0 AND a<10; DROP TABLE t1,t2; +--echo # +--echo # Bug #879860: MIN/MAX for subquery returning empty set +--echo # + +CREATE TABLE t1 (a int PRIMARY KEY); +INSERT INTO t1 VALUES (1); + +CREATE TABLE t2 (a int NOT NULL); +INSERT INTO t2 VALUES (10); + +CREATE TABLE t3 ( a int, b int); +INSERT INTO t3 VALUES (19,1), (20,5); + +EXPLAIN EXTENDED +SELECT (SELECT MIN(t1.a) FROM t1,t2 WHERE t2.a = t3.b) FROM t3; +SELECT (SELECT MIN(t1.a) FROM t1,t2 WHERE t2.a = t3.b) FROM t3; + +DROP TABLE t1,t2,t3; + --echo # --echo End of 5.2 tests diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 27a848cb0ec..cd6e7a4ffaa 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -608,6 +608,10 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, if (!cond) DBUG_RETURN(TRUE); Field *field= field_part->field; + if (cond->used_tables() & OUTER_REF_TABLE_BIT) + { + DBUG_RETURN(FALSE); + } if (!(cond->used_tables() & field->table->map) && test(cond->used_tables() & ~PSEUDO_TABLE_BITS)) { From 5ab628e0240ae280c0b5b03e1d64b2242cd7265e Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Wed, 28 Dec 2011 18:47:01 -0800 Subject: [PATCH 14/83] Fixed LP bug #777654. The method Item_sum_num::fix_fields() calculated the value of the flag Item_sum_num::maybe_null in some cases incorrectly. --- mysql-test/r/sum_distinct.result | 12 ++++++++++++ mysql-test/t/sum_distinct.test | 12 ++++++++++++ sql/item_sum.cc | 3 +-- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/sum_distinct.result b/mysql-test/r/sum_distinct.result index c615817f52d..2746f5a09f4 100644 --- a/mysql-test/r/sum_distinct.result +++ b/mysql-test/r/sum_distinct.result @@ -95,3 +95,15 @@ SELECT SUM(DISTINCT id % 11) FROM t1; SUM(DISTINCT id % 11) 55 DROP TABLE t1; +# +# Bug #777654: empty subselect in FROM clause returning +# SUM(DISTINCT) over non-nullable field +# +CREATE TABLE t1 (a int NOT NULL) ; +SELECT SUM(DISTINCT a) FROM t1; +SUM(DISTINCT a) +NULL +SELECT * FROM (SELECT SUM(DISTINCT a) FROM t1) AS t; +SUM(DISTINCT a) +NULL +DROP TABLE t1; diff --git a/mysql-test/t/sum_distinct.test b/mysql-test/t/sum_distinct.test index c58155a8e25..633a72fddc8 100644 --- a/mysql-test/t/sum_distinct.test +++ b/mysql-test/t/sum_distinct.test @@ -93,3 +93,15 @@ SELECT SUM(DISTINCT id) FROM t1; SELECT SUM(DISTINCT id % 11) FROM t1; DROP TABLE t1; + +--echo # +--echo # Bug #777654: empty subselect in FROM clause returning +--echo # SUM(DISTINCT) over non-nullable field +--echo # + +CREATE TABLE t1 (a int NOT NULL) ; + +SELECT SUM(DISTINCT a) FROM t1; +SELECT * FROM (SELECT SUM(DISTINCT a) FROM t1) AS t; + +DROP TABLE t1; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index ce7602b7f03..ac6ddc0fd54 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -568,13 +568,12 @@ Item_sum_num::fix_fields(THD *thd, Item **ref) return TRUE; decimals=0; - maybe_null=0; + maybe_null= sum_func() != COUNT_FUNC; for (uint i=0 ; i < arg_count ; i++) { if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1)) return TRUE; set_if_bigger(decimals, args[i]->decimals); - maybe_null |= args[i]->maybe_null; } result_field=0; max_length=float_length(decimals); From 40c42468bcbe215a971f93edb9af27545156b8a7 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 29 Dec 2011 15:09:20 -0800 Subject: [PATCH 15/83] Fixed LP bug #806057. A table expression with a natural join or a USING clause is transformed into an equivalent expression with equi-join ON conditions. If a reference to a virtual column happened to occur only in these generated equi-join conditions then it was not erroneously marked in the TABLE::vcol_set bitmap. This could lead to wrong results for queries containing natural join expressions or USING clauses. --- .../suite/vcol/r/vcol_select_myisam.result | 30 +++++++++++++++++++ .../suite/vcol/t/vcol_select_myisam.test | 20 +++++++++++++ sql/sql_base.cc | 7 ++++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/vcol/r/vcol_select_myisam.result b/mysql-test/suite/vcol/r/vcol_select_myisam.result index 45e4defd315..04ae7e0f7cd 100644 --- a/mysql-test/suite/vcol/r/vcol_select_myisam.result +++ b/mysql-test/suite/vcol/r/vcol_select_myisam.result @@ -262,3 +262,33 @@ NULL explain select sum(c) from t1 group by b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using temporary; Using filesort +# +# Bug #806057: join with USING over a virtual column +# +CREATE TABLE t1 (b int); +INSERT INTO t1 VALUES (NULL),( 78), (185), (0), (154); +CREATE TABLE t2 (a int, b int AS (a) VIRTUAL); +INSERT INTO t2 VALUES (187,187), (9,9), (187,187); +Warnings: +Warning 1647 The value specified for computed column 'b' in table 't2' ignored +Warning 1647 The value specified for computed column 'b' in table 't2' ignored +Warning 1647 The value specified for computed column 'b' in table 't2' ignored +EXPLAIN EXTENDED +SELECT * FROM t1 JOIN t2 USING (b); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer +Warnings: +Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where (`test`.`t1`.`b` = `test`.`t2`.`b`) +SELECT * FROM t1 JOIN t2 USING (b); +b a +EXPLAIN EXTENDED +SELECT * FROM t1 NATURAL JOIN t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer +Warnings: +Note 1003 select `test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where (`test`.`t1`.`b` = `test`.`t2`.`b`) +SELECT * FROM t1 NATURAL JOIN t2; +b a +DROP TABLE t1,t2; diff --git a/mysql-test/suite/vcol/t/vcol_select_myisam.test b/mysql-test/suite/vcol/t/vcol_select_myisam.test index 855e02ac113..c14faba576d 100644 --- a/mysql-test/suite/vcol/t/vcol_select_myisam.test +++ b/mysql-test/suite/vcol/t/vcol_select_myisam.test @@ -48,3 +48,23 @@ eval SET @@session.storage_engine = 'MyISAM'; #------------------------------------------------------------------------------# # Cleanup --source suite/vcol/inc/vcol_cleanup.inc + +--echo # +--echo # Bug #806057: join with USING over a virtual column +--echo # + +CREATE TABLE t1 (b int); +INSERT INTO t1 VALUES (NULL),( 78), (185), (0), (154); + +CREATE TABLE t2 (a int, b int AS (a) VIRTUAL); +INSERT INTO t2 VALUES (187,187), (9,9), (187,187); + +EXPLAIN EXTENDED +SELECT * FROM t1 JOIN t2 USING (b); +SELECT * FROM t1 JOIN t2 USING (b); + +EXPLAIN EXTENDED +SELECT * FROM t1 NATURAL JOIN t2; +SELECT * FROM t1 NATURAL JOIN t2; + +DROP TABLE t1,t2; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 4616b5c2430..bd02bbca7ea 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7151,11 +7151,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, if (!(eq_cond= new Item_func_eq(item_ident_1, item_ident_2))) goto err; /* Out of memory. */ + if (field_1 && field_1->vcol_info) + field_1->table->mark_virtual_col(field_1); + if (field_2 && field_2->vcol_info) + field_2->table->mark_virtual_col(field_2); + /* Add the new equi-join condition to the ON clause. Notice that fix_fields() is applied to all ON conditions in setup_conds() so we don't do it here. - */ + */ add_join_on((table_ref_1->outer_join & JOIN_TYPE_RIGHT ? table_ref_1 : table_ref_2), eq_cond); From 74fdbec68e81fb30a82ab5f9ff66b748d506f909 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 29 Dec 2011 21:55:17 -0800 Subject: [PATCH 16/83] Fixed LP bug #848652. The cause of this bug was the same as for bug 902356 fixed for 5.3. --- mysql-test/r/join_outer_innodb.result | 8 ++++++++ mysql-test/t/join_outer_innodb.test | 15 +++++++++++++++ sql/sql_select.cc | 7 ++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/join_outer_innodb.result b/mysql-test/r/join_outer_innodb.result index e8a2d6f668b..c8bc9758408 100644 --- a/mysql-test/r/join_outer_innodb.result +++ b/mysql-test/r/join_outer_innodb.result @@ -17,3 +17,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 index NULL fkey 5 NULL 5 Using index 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.fkey 1 Using where DROP TABLE t1,t2; +CREATE TABLE t1(a int, b int, KEY (a), PRIMARY KEY (b)) ENGINE=InnoDB; +CREATE TABLE t2 (b int, PRIMARY KEY (b)); +INSERT INTO t2 VALUES (4),(9); +SELECT STRAIGHT_JOIN t1.a FROM t1 RIGHT JOIN t2 ON t1.b = t2.b +WHERE (t1.b NOT BETWEEN 1 AND 7 OR t1.a IS NULL AND t1.b = t2.b) AND t2.b = 4 +GROUP BY 1; +a +DROP TABLE t1,t2; diff --git a/mysql-test/t/join_outer_innodb.test b/mysql-test/t/join_outer_innodb.test index 40add7f488f..565bb72b152 100644 --- a/mysql-test/t/join_outer_innodb.test +++ b/mysql-test/t/join_outer_innodb.test @@ -24,3 +24,18 @@ SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id WHERE t1.name LIKE 'A%' OR FALSE; DROP TABLE t1,t2; + +# +# Bug #848652: crash with RIGHT JOIN and GROUP BY +# + +CREATE TABLE t1(a int, b int, KEY (a), PRIMARY KEY (b)) ENGINE=InnoDB; + +CREATE TABLE t2 (b int, PRIMARY KEY (b)); +INSERT INTO t2 VALUES (4),(9); + +SELECT STRAIGHT_JOIN t1.a FROM t1 RIGHT JOIN t2 ON t1.b = t2.b + WHERE (t1.b NOT BETWEEN 1 AND 7 OR t1.a IS NULL AND t1.b = t2.b) AND t2.b = 4 +GROUP BY 1; + +DROP TABLE t1,t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8b7261a8712..5963a1c318a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13725,8 +13725,8 @@ find_field_in_item_list (Field *field, void *data) while ((item= li++)) { - if (item->type() == Item::FIELD_ITEM && - ((Item_field*) item)->field->eq(field)) + if (item->real_item()->type() == Item::FIELD_ITEM && + ((Item_field*) (item->real_item()))->field->eq(field)) { part_found= 1; break; @@ -13994,7 +13994,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, uint used_pk_parts= 0; if (used_key_parts > used_index_parts) used_pk_parts= used_key_parts-used_index_parts; - rec_per_key= keyinfo->rec_per_key[used_key_parts-1]; + rec_per_key= used_key_parts ? + keyinfo->rec_per_key[used_key_parts-1] : 1; /* Take into account the selectivity of the used pk prefix */ if (used_pk_parts) { From a0afa025a3f949efe0f414c2bf562139c4069f88 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 2 Jan 2012 23:52:31 +0100 Subject: [PATCH 17/83] Fix embedded/windows tests- move COND_manager and LOCK_manager to sql_manager.cc, to prevent race condition that results into accessing already destroyed critical section --- sql/mysql_priv.h | 4 ++-- sql/mysqld.cc | 4 ---- sql/sql_manager.cc | 12 ++++++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 065425c4c96..ed23ecb50fe 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -2091,7 +2091,7 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_lock_db, LOCK_mapped_file,LOCK_user_locks, LOCK_status, LOCK_error_log, LOCK_delayed_insert, LOCK_short_uuid_generator, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, - LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock, + LOCK_slave_list, LOCK_active_mi, LOCK_global_read_lock, LOCK_global_system_variables, LOCK_user_conn, LOCK_prepared_stmt_count, LOCK_bytes_sent, LOCK_bytes_received, LOCK_connection_count; @@ -2109,7 +2109,7 @@ extern pthread_mutex_t LOCK_stats; extern int mysqld_server_started; extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; extern rw_lock_t LOCK_system_variables_hash; -extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; +extern pthread_cond_t COND_refresh, COND_thread_count; extern pthread_cond_t COND_global_read_lock; extern pthread_attr_t connection_attrib; extern I_List threads; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0d0ad919515..aa27ea0f582 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1516,7 +1516,6 @@ static void clean_up_mutexes() (void) pthread_mutex_destroy(&LOCK_delayed_insert); (void) pthread_mutex_destroy(&LOCK_delayed_status); (void) pthread_mutex_destroy(&LOCK_delayed_create); - (void) pthread_mutex_destroy(&LOCK_manager); (void) pthread_mutex_destroy(&LOCK_crypt); (void) pthread_mutex_destroy(&LOCK_bytes_sent); (void) pthread_mutex_destroy(&LOCK_bytes_received); @@ -1557,7 +1556,6 @@ static void clean_up_mutexes() (void) pthread_cond_destroy(&COND_global_read_lock); (void) pthread_cond_destroy(&COND_thread_cache); (void) pthread_cond_destroy(&COND_flush_thread_cache); - (void) pthread_cond_destroy(&COND_manager); DBUG_VOID_RETURN; } @@ -3817,7 +3815,6 @@ static int init_thread_environment() (void) pthread_mutex_init(&LOCK_delayed_insert,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_delayed_status,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_delayed_create,MY_MUTEX_INIT_SLOW); - (void) pthread_mutex_init(&LOCK_manager,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST); @@ -3857,7 +3854,6 @@ static int init_thread_environment() (void) pthread_cond_init(&COND_global_read_lock,NULL); (void) pthread_cond_init(&COND_thread_cache,NULL); (void) pthread_cond_init(&COND_flush_thread_cache,NULL); - (void) pthread_cond_init(&COND_manager,NULL); #ifdef HAVE_REPLICATION (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST); (void) pthread_cond_init(&COND_rpl_status, NULL); diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc index cf0a73d0ce7..57fe5072dcd 100644 --- a/sql/sql_manager.cc +++ b/sql/sql_manager.cc @@ -44,6 +44,7 @@ static struct handler_cb * volatile cb_list; bool mysql_manager_submit(void (*action)()) { bool result= FALSE; + DBUG_ASSERT(manager_thread_in_use); struct handler_cb * volatile *cb; pthread_mutex_lock(&LOCK_manager); cb= &cb_list; @@ -75,8 +76,9 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused))) pthread_detach_this_thread(); manager_thread = pthread_self(); + (void) pthread_cond_init(&COND_manager,NULL); + (void) pthread_mutex_init(&LOCK_manager,NULL); manager_thread_in_use = 1; - for (;;) { pthread_mutex_lock(&LOCK_manager); @@ -123,6 +125,8 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused))) } } manager_thread_in_use = 0; + (void) pthread_mutex_destroy(&LOCK_manager); + (void) pthread_cond_destroy(&COND_manager); DBUG_LEAVE; // Can't use DBUG_RETURN after my_thread_end my_thread_end(); return (NULL); @@ -149,14 +153,14 @@ void stop_handle_manager() { DBUG_ENTER("stop_handle_manager"); abort_manager = true; - pthread_mutex_lock(&LOCK_manager); if (manager_thread_in_use) { + pthread_mutex_lock(&LOCK_manager); DBUG_PRINT("quit", ("initiate shutdown of handle manager thread: 0x%lx", (ulong)manager_thread)); - pthread_cond_signal(&COND_manager); + pthread_cond_signal(&COND_manager); + pthread_mutex_unlock(&LOCK_manager); } - pthread_mutex_unlock(&LOCK_manager); DBUG_VOID_RETURN; } From d63fc00f35e40315848133991ca6f336e3f87eb9 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 5 Jan 2012 11:06:52 +0200 Subject: [PATCH 18/83] Fix of LP BUG#793589 Wrong result with double ORDER BY Problem was in caching 'eq_ref' dependency between calls of remove_const() for ORDER BY and GROUP BY lists. --- mysql-test/r/order_by.result | 54 ++++++++++++++++++++++++++++++++++++ mysql-test/t/order_by.test | 29 +++++++++++++++++++ sql/sql_select.cc | 9 ++++++ 3 files changed, 92 insertions(+) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 0c522aef290..88d4e729c1f 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -1672,3 +1672,57 @@ select 1 order by max(1) + min(1); 1 1 End of 5.1 tests +# +# Fix of LP BUG#793589 Wrong result with double ORDER BY +# +CREATE TABLE t1 ( b int) ; +INSERT INTO t1 VALUES (8),(9); +CREATE TABLE t2 ( a int, b int, PRIMARY KEY (a)) ; +INSERT INTO t2 VALUES (6,7),(7,7),(8,1),(9,7),(10,1),(11,5),(12,2),(13,0),(14,1),(15,8),(16,1),(17,1),(18,9),(19,1),(20,5); +SELECT t2.b AS field1 FROM t1, t2 WHERE t1.b = t2.a GROUP BY field1 ORDER BY t1.b, field1; +field1 +1 +7 +SELECT t2.b, t1.b FROM t1, t2 WHERE t1.b = t2.a GROUP BY t2.b ORDER BY t1.b, t2.b; +b b +1 8 +7 9 +SELECT t2.b,t1.b FROM t1, t2 WHERE t1.b = t2.a GROUP BY t2.b ORDER BY t1.b; +b b +1 8 +7 9 +SELECT t2.b FROM t1, t2 WHERE t1.b = t2.a GROUP BY t2.b ORDER BY t1.b; +b +1 +7 +# field1 removed from ORDER BY +explain extended +SELECT t2.b AS field1 FROM t1, t2 WHERE t1.b = t2.a GROUP BY field1 ORDER BY t1.b, field1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 100.00 +Warnings: +Note 1003 select `test`.`t2`.`b` AS `field1` from `test`.`t1` join `test`.`t2` where (`test`.`t2`.`a` = `test`.`t1`.`b`) group by `test`.`t2`.`b` order by `test`.`t1`.`b` +explain extended +SELECT t2.b, t1.b FROM t1, t2 WHERE t1.b = t2.a GROUP BY t2.b ORDER BY t1.b, t2.b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 100.00 +Warnings: +Note 1003 select `test`.`t2`.`b` AS `b`,`test`.`t1`.`b` AS `b` from `test`.`t1` join `test`.`t2` where (`test`.`t2`.`a` = `test`.`t1`.`b`) group by `test`.`t2`.`b` order by `test`.`t1`.`b` +explain extended +SELECT t2.b,t1.b FROM t1, t2 WHERE t1.b = t2.a GROUP BY t2.b ORDER BY t1.b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 100.00 +Warnings: +Note 1003 select `test`.`t2`.`b` AS `b`,`test`.`t1`.`b` AS `b` from `test`.`t1` join `test`.`t2` where (`test`.`t2`.`a` = `test`.`t1`.`b`) group by `test`.`t2`.`b` order by `test`.`t1`.`b` +explain extended +SELECT t2.b FROM t1, t2 WHERE t1.b = t2.a GROUP BY t2.b ORDER BY t1.b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 100.00 +Warnings: +Note 1003 select `test`.`t2`.`b` AS `b` from `test`.`t1` join `test`.`t2` where (`test`.`t2`.`a` = `test`.`t1`.`b`) group by `test`.`t2`.`b` order by `test`.`t1`.`b` +drop table t1,t2; +End of 5.2 tests diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 2a5f74a3a13..add256a7451 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -1518,3 +1518,32 @@ DROP TABLE t1; select 1 order by max(1) + min(1); --echo End of 5.1 tests + +--echo # +--echo # Fix of LP BUG#793589 Wrong result with double ORDER BY +--echo # +CREATE TABLE t1 ( b int) ; +INSERT INTO t1 VALUES (8),(9); + +CREATE TABLE t2 ( a int, b int, PRIMARY KEY (a)) ; +INSERT INTO t2 VALUES (6,7),(7,7),(8,1),(9,7),(10,1),(11,5),(12,2),(13,0),(14,1),(15,8),(16,1),(17,1),(18,9),(19,1),(20,5); + +SELECT t2.b AS field1 FROM t1, t2 WHERE t1.b = t2.a GROUP BY field1 ORDER BY t1.b, field1; +SELECT t2.b, t1.b FROM t1, t2 WHERE t1.b = t2.a GROUP BY t2.b ORDER BY t1.b, t2.b; +SELECT t2.b,t1.b FROM t1, t2 WHERE t1.b = t2.a GROUP BY t2.b ORDER BY t1.b; +SELECT t2.b FROM t1, t2 WHERE t1.b = t2.a GROUP BY t2.b ORDER BY t1.b; + +--echo # field1 removed from ORDER BY +explain extended +SELECT t2.b AS field1 FROM t1, t2 WHERE t1.b = t2.a GROUP BY field1 ORDER BY t1.b, field1; +explain extended +SELECT t2.b, t1.b FROM t1, t2 WHERE t1.b = t2.a GROUP BY t2.b ORDER BY t1.b, t2.b; +explain extended +SELECT t2.b,t1.b FROM t1, t2 WHERE t1.b = t2.a GROUP BY t2.b ORDER BY t1.b; +explain extended +SELECT t2.b FROM t1, t2 WHERE t1.b = t2.a GROUP BY t2.b ORDER BY t1.b; + + +drop table t1,t2; + +--echo End of 5.2 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b066ad1544d..3af05c3015a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7368,6 +7368,15 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, table_map ref; DBUG_ENTER("remove_const"); + /* + Cleanup to avoid interference of calls of this function for + ORDER BY and GROUP BY + */ + for (JOIN_TAB *tab= join->join_tab + join->const_tables; + tab < join->join_tab + join->tables; + tab++) + tab->cached_eq_ref_table= FALSE; + prev_ptr= &first_order; *simple_order= *join->join_tab[join->const_tables].on_expr_ref ? 0 : 1; From d725c52d27cb206bb0dc17c629535655a11885c2 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sat, 7 Jan 2012 10:23:46 +0200 Subject: [PATCH 19/83] Fixed wrong merge --- sql/sql_parse.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8aed1229f5b..1510ea7bf10 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -190,7 +190,6 @@ bool end_active_trans(THD *thd) if (ha_commit(thd)) error=1; #ifdef WITH_ARIA_STORAGE_ENGINE - ha_maria::implicit_commit(thd, TRUE); if (ha_storage_engine_is_enabled(maria_hton)) ha_maria::implicit_commit(thd, TRUE); #endif @@ -1664,7 +1663,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->transaction.stmt.reset(); #ifdef WITH_ARIA_STORAGE_ENGINE - ha_maria::implicit_commit(thd, FALSE); if (ha_storage_engine_is_enabled(maria_hton)) ha_maria::implicit_commit(thd, FALSE); #endif From 629cdab80827e7ad6bb23f7c8dc20724eb87f4d9 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sun, 8 Jan 2012 20:29:05 +0200 Subject: [PATCH 20/83] Fixed compiler and test failures found by buildbot configure.in: Added testing of STRNDUP (not found on solaris) mysql-test/include/wait_until_connected_again.inc: Also test for error 2005 (can happen on windows) mysql-test/include/wait_until_disconnected.inc: Also test for error 2005 (can happen on windows) mysql-test/suite/innodb_plugin/r/innodb_bug30423.result: Number of rows is not stable (found difference on Solaris) mysql-test/suite/innodb_plugin/t/innodb_bug30423.test: Number of rows is not stable (found difference on Solaris) plugin/auth_pam/auth_pam.c: Use internal strndup if it doesn't exist on system (solaris) Changed code so that it should also compile on solaris. --- configure.in | 2 +- .../include/wait_until_connected_again.inc | 2 +- .../include/wait_until_disconnected.inc | 2 +- .../innodb_plugin/r/innodb_bug30423.result | 6 ++-- .../innodb_plugin/t/innodb_bug30423.test | 1 + plugin/auth_pam/auth_pam.c | 33 +++++++++++++++++-- 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/configure.in b/configure.in index a592fb76a0e..9c3cbd283dc 100644 --- a/configure.in +++ b/configure.in @@ -2033,7 +2033,7 @@ dnl Checks for library functions. AC_FUNC_ALLOCA AC_PROG_GCC_TRADITIONAL AC_TYPE_SIGNAL -AC_CHECK_FUNCS(re_comp regcomp strdup) +AC_CHECK_FUNCS(re_comp regcomp strdup strndup) dnl Sun compilers have their own vis.h that is about something dnl totally different. So, not to change the libedit source, we diff --git a/mysql-test/include/wait_until_connected_again.inc b/mysql-test/include/wait_until_connected_again.inc index aff92141a8b..96240e36db7 100644 --- a/mysql-test/include/wait_until_connected_again.inc +++ b/mysql-test/include/wait_until_connected_again.inc @@ -14,7 +14,7 @@ while ($mysql_errno) # Strangely enough, the server might return "Too many connections" # while being shutdown, thus 1040 is an "allowed" error # See BUG#36228 - --error 0,1040,1053,2002,2003,2006,2013 + --error 0,1040,1053,2002,2003,2005,2006,2013 show status; dec $counter; diff --git a/mysql-test/include/wait_until_disconnected.inc b/mysql-test/include/wait_until_disconnected.inc index c274fbbe089..71361682442 100644 --- a/mysql-test/include/wait_until_disconnected.inc +++ b/mysql-test/include/wait_until_disconnected.inc @@ -12,7 +12,7 @@ while (!$mysql_errno) # Strangely enough, the server might return "Too many connections" # while being shutdown, thus 1040 is an "allowed" error. # See BUG#36228. - --error 0,1040,1053,2002,2003,2006,2013 + --error 0,1040,1053,2002,2003,2005,2006,2013 show status; dec $counter; diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug30423.result b/mysql-test/suite/innodb_plugin/r/innodb_bug30423.result index a19809366ae..6071587e888 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_bug30423.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug30423.result @@ -48,9 +48,9 @@ ON orgs.org_id=sa_opportunities.org_id LEFT JOIN bug30243_2 contacts ON orgs.org_id=contacts.org_id ; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE orgs index NULL org_id 4 NULL 128 Using index -1 SIMPLE sa_opportunities ref org_id org_id 5 test.orgs.org_id 1 Using index -1 SIMPLE contacts ref contacts$org_id contacts$org_id 5 test.orgs.org_id 1 Using index +1 SIMPLE orgs index NULL org_id 4 NULL # Using index +1 SIMPLE sa_opportunities ref org_id org_id 5 test.orgs.org_id # Using index +1 SIMPLE contacts ref contacts$org_id contacts$org_id 5 test.orgs.org_id # Using index select @@innodb_stats_method; @@innodb_stats_method nulls_ignored diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug30423.test b/mysql-test/suite/innodb_plugin/t/innodb_bug30423.test index 458c2967e19..da490589400 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug30423.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug30423.test @@ -140,6 +140,7 @@ analyze table bug30243_3; # Following query plan shows that we get the correct rows per # unique value (should be approximately 1 row per value) +--replace_column 9 # explain SELECT COUNT(*), 0 FROM bug30243_1 orgs LEFT JOIN bug30243_3 sa_opportunities diff --git a/plugin/auth_pam/auth_pam.c b/plugin/auth_pam/auth_pam.c index 45c49975f6e..0d9cf2ae0af 100644 --- a/plugin/auth_pam/auth_pam.c +++ b/plugin/auth_pam/auth_pam.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -8,6 +9,24 @@ struct param { MYSQL_PLUGIN_VIO *vio; }; +/* It least solaris doesn't have strndup */ + +#ifndef HAVE_STRNDUP +char *strndup(const char *from, size_t length) +{ + char *ptr; + size_t max_length= strlen(from); + if (length > max_length) + length= max_length; + if ((ptr= (char*) malloc(length+1)) != 0) + { + memcpy((char*) ptr, (char*) from, length); + ptr[length]=0; + } + return ptr; +} +#endif + static int conv(int n, const struct pam_message **msg, struct pam_response **resp, void *data) { @@ -71,13 +90,21 @@ static int conv(int n, const struct pam_message **msg, #define DO(X) if ((status = (X)) != PAM_SUCCESS) goto end +#ifdef SOLARIS +typedef void** pam_get_item_3_arg; +#else +typedef const void** pam_get_item_3_arg; +#endif + static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) { pam_handle_t *pamh = NULL; int status; const char *new_username; struct param param; - struct pam_conv c = { &conv, ¶m }; + /* The following is written in such a way to make also solaris happy */ + struct pam_conv pam_start_arg = { &conv, NULL }; + pam_start_arg.appdata_ptr= (char*) ¶m; /* get the service name, as specified in @@ -90,10 +117,10 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) param.ptr = param.buf + 1; param.vio = vio; - DO( pam_start(service, info->user_name, &c, &pamh) ); + DO( pam_start(service, info->user_name, &pam_start_arg, &pamh) ); DO( pam_authenticate (pamh, 0) ); DO( pam_acct_mgmt(pamh, 0) ); - DO( pam_get_item(pamh, PAM_USER, (const void**)&new_username) ); + DO( pam_get_item(pamh, PAM_USER, (pam_get_item_3_arg) &new_username) ); if (new_username && strcmp(new_username, info->user_name)) strncpy(info->authenticated_as, new_username, From 39ebfa51ef1dbb2807ea46063e6a5936103ffb01 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 10 Jan 2012 19:23:00 +0100 Subject: [PATCH 21/83] Fix MDEV-49 : version_compile_machine server variable is 'unknown' for x64 builds --- include/config-win.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/config-win.h b/include/config-win.h index 9369c72e83d..86fcc61aa9b 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -45,8 +45,8 @@ #define MACHINE_TYPE "ia64" #elif defined(_M_IX86) #define MACHINE_TYPE "ia32" -#elif defined(_M_ALPHA) -#define MACHINE_TYPE "axp" +#elif defined(_M_X64) +#define MACHINE_TYPE "x64" #else #define MACHINE_TYPE "unknown" /* Define to machine type name */ #endif From 22876a5495b5ddb9a310a56953a1b572946712c1 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 10 Jan 2012 19:26:47 +0100 Subject: [PATCH 22/83] MDEV-50 : Fix default compilation comment --- win/cmake/mysql_version.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/cmake/mysql_version.cmake b/win/cmake/mysql_version.cmake index 79e6a18ee1d..e6b64d3003e 100644 --- a/win/cmake/mysql_version.cmake +++ b/win/cmake/mysql_version.cmake @@ -81,7 +81,7 @@ IF(NOT MYSQL_UNIX_ADDR) SET(MYSQL_UNIX_ADDR "/tmp/mysql.sock") ENDIF() IF(NOT COMPILATION_COMMENT) - SET(COMPILATION_COMMENT "Source distribution") + SET(COMPILATION_COMMENT "mariadb.org binary distribution") ENDIF() From 6dfe0956d64b41a2e4eda0f40feaad799cd84058 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 13 Jan 2012 12:23:19 -0800 Subject: [PATCH 23/83] Back-ported the test cases for bug #12763207 from mysql-5.6 code line into 5.2 Completed the fix for this bug. Note: in 5.3 the affected 'if' statement in Item_in_subselect::single_value_transformer() starting with the condition (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) should be removed altogether. The change from table.cc is not needed either. This is because in 5.3 - min/max transformation for subqueries are done at the optimization phase - evaluation of the expensive subqueries is done at the execution phase. Added an EXPLAIN EXTENDED to the test case for bug #12329653. --- mysql-test/r/subselect.result | 53 +++++++++++++++++++++++++++++++++++ mysql-test/t/subselect.test | 53 +++++++++++++++++++++++++++++++++++ sql/item_subselect.cc | 3 +- sql/table.cc | 1 + 4 files changed, 109 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 65e76d04c1f..5063b4c6db9 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4568,6 +4568,13 @@ CREATE TABLE t1(a1 int); INSERT INTO t1 VALUES (1),(2); SELECT @@session.sql_mode INTO @old_sql_mode; SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; +EXPLAIN EXTENDED +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT a1 FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 +2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 +Warnings: +Note 1003 select 1 AS `1` from `test`.`t1` where 1 SELECT 1 FROM t1 WHERE 1 < SOME (SELECT a1 FROM t1); 1 1 @@ -5088,4 +5095,50 @@ NULL NULL 5 DROP TABLE t1, t2, t3; +# +# Bug#12763207 - ASSERT IN SUBSELECT::SINGLE_VALUE_TRANSFORMER +# +CREATE TABLE t1(a1 int); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2(a1 int); +INSERT INTO t2 VALUES (3); +SELECT @@session.sql_mode INTO @old_sql_mode; +SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT 2 FROM t2); +1 +1 +1 +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT 2.0 FROM t2); +1 +1 +1 +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT 'a' FROM t2); +1 +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT a1 FROM t2); +1 +1 +1 +SET SESSION sql_mode=@old_sql_mode; +DROP TABLE t1, t2; +create table t2(i int); +insert into t2 values(0); +SELECT @@session.sql_mode INTO @old_sql_mode; +SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; +CREATE VIEW v1 AS +SELECT 'f' FROM t2 UNION SELECT 'x' FROM t2 +; +CREATE TABLE t1 ( +pk int NOT NULL, +col_varchar_key varchar(1) DEFAULT NULL, +PRIMARY KEY (pk), +KEY col_varchar_key (col_varchar_key) +); +SELECT t1.pk +FROM t1 +WHERE t1.col_varchar_key < ALL ( SELECT * FROM v1 ) +; +pk +SET SESSION sql_mode=@old_sql_mode; +drop table t2, t1; +drop view v1; End of 5.2 tests diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index b918e800dd5..e4ed6188f25 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -3460,6 +3460,8 @@ SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; ## First a simpler query, illustrating the transformation ## '1 < some (...)' => '1 < max(...)' +EXPLAIN EXTENDED +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT a1 FROM t1); SELECT 1 FROM t1 WHERE 1 < SOME (SELECT a1 FROM t1); ## The query which made the server crash. @@ -3958,4 +3960,55 @@ INSERT INTO t3 VALUES (0),(0); SELECT a1.f3 AS r FROM t2 AS a1 , t1 WHERE a1.f3 < ALL ( SELECT f3 FROM t3 WHERE f3 = 1 ) ; DROP TABLE t1, t2, t3; +--echo # +--echo # Bug#12763207 - ASSERT IN SUBSELECT::SINGLE_VALUE_TRANSFORMER +--echo # + +CREATE TABLE t1(a1 int); +INSERT INTO t1 VALUES (1),(2); + +CREATE TABLE t2(a1 int); +INSERT INTO t2 VALUES (3); + +SELECT @@session.sql_mode INTO @old_sql_mode; +SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; + +## All these are subject to the transformation +## '1 < some (...)' => '1 < max(...)' +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT 2 FROM t2); +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT 2.0 FROM t2); +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT 'a' FROM t2); +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT a1 FROM t2); + +SET SESSION sql_mode=@old_sql_mode; + +DROP TABLE t1, t2; + +create table t2(i int); +insert into t2 values(0); + +SELECT @@session.sql_mode INTO @old_sql_mode; +SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; + +CREATE VIEW v1 AS +SELECT 'f' FROM t2 UNION SELECT 'x' FROM t2 +; + +CREATE TABLE t1 ( + pk int NOT NULL, + col_varchar_key varchar(1) DEFAULT NULL, + PRIMARY KEY (pk), + KEY col_varchar_key (col_varchar_key) +); + +SELECT t1.pk +FROM t1 +WHERE t1.col_varchar_key < ALL ( SELECT * FROM v1 ) +; + +SET SESSION sql_mode=@old_sql_mode; + +drop table t2, t1; +drop view v1; + --echo End of 5.2 tests diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 82d2313aa2b..2828ae8c4ec 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1057,7 +1057,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, print_where(item, "rewrite with MIN/MAX", QT_ORDINARY);); if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) { - DBUG_ASSERT(select_lex->non_agg_field_used()); + DBUG_ASSERT(item->get_arg(0)->real_item()->type() != Item::FIELD_ITEM || + select_lex->non_agg_field_used()); select_lex->set_non_agg_field_used(false); } diff --git a/sql/table.cc b/sql/table.cc index ca14b2ef4d2..a3df9023805 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4467,6 +4467,7 @@ Item *Field_iterator_table::create_item(THD *thd) { select->non_agg_fields.push_back(item); item->marker= select->cur_pos_in_select_list; + select->set_non_agg_field_used(true); } return item; } From 4de7978a3f3e716a6b1b280ce1f30dd501e31545 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 13 Jan 2012 19:00:50 -0800 Subject: [PATCH 24/83] Back-ported the fix and the test case for bug #50257 from mariadb-5.3 code line. Adjusted results for a few test cases. --- mysql-test/r/index_merge_myisam.result | 2 +- mysql-test/r/subselect.result | 20 ++++++++++++++++--- mysql-test/suite/innodb/r/innodb_mysql.result | 6 +++--- .../suite/innodb_plugin/r/innodb_mysql.result | 6 +++--- mysql-test/suite/pbxt/r/subselect.result | 4 ++-- mysql-test/t/subselect.test | 15 ++++++++++++-- sql/sql_select.cc | 3 +-- 7 files changed, 40 insertions(+), 16 deletions(-) diff --git a/mysql-test/r/index_merge_myisam.result b/mysql-test/r/index_merge_myisam.result index df570e1f4ae..ad44f241f5c 100644 --- a/mysql-test/r/index_merge_myisam.result +++ b/mysql-test/r/index_merge_myisam.result @@ -1486,7 +1486,7 @@ EXPLAIN SELECT t1.f1 FROM t1 WHERE (SELECT COUNT(*) FROM t2 WHERE t2.f3 = 'h' AND t2.f2 = t1.f1) = 0 AND t1.f1 = 2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system PRIMARY NULL NULL NULL 1 -2 DEPENDENT SUBQUERY t2 ref f2,f3 f2 5 1 Using where +2 DEPENDENT SUBQUERY t2 ref f2,f3 f2 5 const 1 Using where DROP TABLE t1,t2; # # Generic @@optimizer_switch tests (move those into a separate file if diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 5063b4c6db9..f1e65f0fb1f 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -363,9 +363,9 @@ INSERT INTO t8 (pseudo,email) VALUES ('2joce1','2test1'); EXPLAIN EXTENDED SELECT pseudo,(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce')) FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t8 const PRIMARY PRIMARY 37 const 1 100.00 Using index -4 SUBQUERY t8 const PRIMARY PRIMARY 37 1 100.00 Using index +4 SUBQUERY t8 const PRIMARY PRIMARY 37 const 1 100.00 Using index 2 SUBQUERY t8 const PRIMARY PRIMARY 37 const 1 100.00 -3 SUBQUERY t8 const PRIMARY PRIMARY 37 1 100.00 Using index +3 SUBQUERY t8 const PRIMARY PRIMARY 37 const 1 100.00 Using index Warnings: Note 1003 select 'joce' AS `pseudo`,(select 'test' from `test`.`t8` where 1) AS `(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'))` from `test`.`t8` where 1 SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo,email FROM @@ -4780,7 +4780,6 @@ EXPLAIN EXTENDED SELECT DISTINCT 1 FROM t1, WHERE t1.a = d1.a; ERROR 42S22: Unknown column 'd1.a' in 'where clause' DROP TABLE t1; -End of 5.1 tests. Set up test tables. CREATE TABLE t1 ( t1_id INT UNSIGNED, @@ -5141,4 +5140,19 @@ pk SET SESSION sql_mode=@old_sql_mode; drop table t2, t1; drop view v1; +# +# BUG#50257: Missing info in REF column of the EXPLAIN +# lines for subselects +# +CREATE TABLE t1 (a INT, b INT, INDEX (a)); +INSERT INTO t1 VALUES (3, 10), (2, 20), (7, 10), (5, 20); +EXPLAIN SELECT * FROM (SELECT * FROM t1 WHERE a=7) t; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY system NULL NULL NULL NULL 1 +2 DERIVED t1 ref a a 5 const 1 Using where +EXPLAIN SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t1 WHERE a=7); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 +2 SUBQUERY t1 ref a a 5 const 1 Using where; Using index +DROP TABLE t1; End of 5.2 tests diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result index 666d6b7591f..e022bd961d6 100644 --- a/mysql-test/suite/innodb/r/innodb_mysql.result +++ b/mysql-test/suite/innodb/r/innodb_mysql.result @@ -1739,7 +1739,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED t1 ALL c3,c2 c3 5 5 Using where; Using filesort +2 DERIVED t1 ALL c3,c2 c3 5 const 5 Using where; Using filesort DROP TABLE t1; CREATE TABLE t1 (c1 REAL, c2 REAL, c3 REAL, KEY (c3), KEY (c2, c3)) ENGINE=InnoDB; @@ -1753,7 +1753,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED t1 ALL c3,c2 c3 9 5 Using where; Using filesort +2 DERIVED t1 ALL c3,c2 c3 9 const 5 Using where; Using filesort DROP TABLE t1; CREATE TABLE t1 (c1 DECIMAL(12,2), c2 DECIMAL(12,2), c3 DECIMAL(12,2), KEY (c3), KEY (c2, c3)) @@ -1768,7 +1768,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED t1 ALL c3,c2 c3 7 5 Using where; Using filesort +2 DERIVED t1 ALL c3,c2 c3 7 const 5 Using where; Using filesort DROP TABLE t1; End of 5.1 tests drop table if exists t1, t2, t3; diff --git a/mysql-test/suite/innodb_plugin/r/innodb_mysql.result b/mysql-test/suite/innodb_plugin/r/innodb_mysql.result index 987a04eb59d..49e8b44b018 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_mysql.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_mysql.result @@ -1739,7 +1739,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED t1 ALL c3,c2 c3 5 5 Using where; Using filesort +2 DERIVED t1 ALL c3,c2 c3 5 const 5 Using where; Using filesort DROP TABLE t1; CREATE TABLE t1 (c1 REAL, c2 REAL, c3 REAL, KEY (c3), KEY (c2, c3)) ENGINE=InnoDB; @@ -1753,7 +1753,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED t1 ALL c3,c2 c3 9 5 Using where; Using filesort +2 DERIVED t1 ALL c3,c2 c3 9 const 5 Using where; Using filesort DROP TABLE t1; CREATE TABLE t1 (c1 DECIMAL(12,2), c2 DECIMAL(12,2), c3 DECIMAL(12,2), KEY (c3), KEY (c2, c3)) @@ -1768,7 +1768,7 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 -2 DERIVED t1 ALL c3,c2 c3 7 5 Using where; Using filesort +2 DERIVED t1 ALL c3,c2 c3 7 const 5 Using where; Using filesort DROP TABLE t1; End of 5.1 tests drop table if exists t1, t2, t3; diff --git a/mysql-test/suite/pbxt/r/subselect.result b/mysql-test/suite/pbxt/r/subselect.result index 63b289d259e..0b5c98324f4 100644 --- a/mysql-test/suite/pbxt/r/subselect.result +++ b/mysql-test/suite/pbxt/r/subselect.result @@ -363,9 +363,9 @@ INSERT INTO t8 (pseudo,email) VALUES ('2joce1','2test1'); EXPLAIN EXTENDED SELECT pseudo,(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce')) FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t8 const PRIMARY PRIMARY 37 const 1 100.00 Using index -4 SUBQUERY t8 const PRIMARY PRIMARY 37 1 100.00 Using index +4 SUBQUERY t8 const PRIMARY PRIMARY 37 const 1 100.00 Using index 2 SUBQUERY t8 const PRIMARY PRIMARY 37 const 1 100.00 -3 SUBQUERY t8 const PRIMARY PRIMARY 37 1 100.00 Using index +3 SUBQUERY t8 const PRIMARY PRIMARY 37 const 1 100.00 Using index Warnings: Note 1003 select 'joce' AS `pseudo`,(select 'test' from `test`.`t8` where 1) AS `(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'))` from `test`.`t8` where 1 SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo,email FROM diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index e4ed6188f25..1f3c102770c 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -3710,8 +3710,6 @@ WHERE t1.a = d1.a; DROP TABLE t1; ---echo End of 5.1 tests. - # # Bug #47904 Incorrect results w/ table subquery, derived SQs, and LEFT JOIN on index # @@ -4011,4 +4009,17 @@ SET SESSION sql_mode=@old_sql_mode; drop table t2, t1; drop view v1; +--echo # +--echo # BUG#50257: Missing info in REF column of the EXPLAIN +--echo # lines for subselects +--echo # + +CREATE TABLE t1 (a INT, b INT, INDEX (a)); +INSERT INTO t1 VALUES (3, 10), (2, 20), (7, 10), (5, 20); + +EXPLAIN SELECT * FROM (SELECT * FROM t1 WHERE a=7) t; +EXPLAIN SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t1 WHERE a=7); + +DROP TABLE t1; + --echo End of 5.2 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3af05c3015a..3cf0800a62f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5913,8 +5913,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, if (keyuse->null_rejecting) j->ref.null_rejecting |= 1 << i; keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables; - if (!keyuse->used_tables && - !(join->select_options & SELECT_DESCRIBE)) + if (!keyuse->used_tables &&!thd->lex->describe) { // Compare against constant store_key_item tmp(thd, keyinfo->key_part[i].field, key_buff + maybe_null, From 4b7919368ebd14ec09eef1e8508ebbab71b86e0c Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sat, 14 Jan 2012 00:02:02 -0800 Subject: [PATCH 25/83] Back-ported the test case for bug #12616253 from mariadb-5.3 that was actually a duplicate of LP bug #888456 fixed in mariadb-5.2. --- mysql-test/r/subselect.result | 41 +++++++++++++++++++++++++++++++++++ mysql-test/t/subselect.test | 21 ++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index f1e65f0fb1f..101869e2843 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5155,4 +5155,45 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 2 SUBQUERY t1 ref a a 5 const 1 Using where; Using index DROP TABLE t1; +# +# BUG#12616253 - WRONG RESULT WITH EXISTS(SUBQUERY) (MISSING ROWS) +# (duplicate of LP bug #888456) +CREATE TABLE t1 (f1 varchar(1)); +INSERT INTO t1 VALUES ('v'),('s'); +CREATE TABLE t2 (f1_key varchar(1), KEY (f1_key)); +INSERT INTO t2 VALUES ('j'),('v'),('c'),('m'),('d'), +('d'),('y'),('t'),('d'),('s'); +EXPLAIN +SELECT table1.f1, table2.f1_key FROM t1 AS table1, t2 AS table2 +WHERE EXISTS (SELECT DISTINCT f1_key FROM t2 +WHERE f1_key != table2.f1_key AND f1_key >= table1.f1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY table1 ALL NULL NULL NULL NULL 2 +1 PRIMARY table2 index NULL f1_key 4 NULL 10 Using where; Using index; Using join buffer +2 DEPENDENT SUBQUERY t2 index f1_key f1_key 4 NULL 10 Using where; Using index; Using temporary +SELECT table1.f1, table2.f1_key FROM t1 AS table1, t2 AS table2 +WHERE EXISTS (SELECT DISTINCT f1_key FROM t2 +WHERE f1_key != table2.f1_key AND f1_key >= table1.f1); +f1 f1_key +v j +s j +v v +s v +v c +s c +v m +s m +v d +s d +v d +s d +v y +s y +v t +s t +v d +s d +v s +s s +DROP TABLE t1,t2; End of 5.2 tests diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 1f3c102770c..24aad3a145d 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4022,4 +4022,25 @@ EXPLAIN SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t1 WHERE a=7); DROP TABLE t1; +--echo # +--echo # BUG#12616253 - WRONG RESULT WITH EXISTS(SUBQUERY) (MISSING ROWS) +--echo # (duplicate of LP bug #888456) + +CREATE TABLE t1 (f1 varchar(1)); +INSERT INTO t1 VALUES ('v'),('s'); + +CREATE TABLE t2 (f1_key varchar(1), KEY (f1_key)); +INSERT INTO t2 VALUES ('j'),('v'),('c'),('m'),('d'), +('d'),('y'),('t'),('d'),('s'); + +EXPLAIN +SELECT table1.f1, table2.f1_key FROM t1 AS table1, t2 AS table2 + WHERE EXISTS (SELECT DISTINCT f1_key FROM t2 + WHERE f1_key != table2.f1_key AND f1_key >= table1.f1); +SELECT table1.f1, table2.f1_key FROM t1 AS table1, t2 AS table2 + WHERE EXISTS (SELECT DISTINCT f1_key FROM t2 + WHERE f1_key != table2.f1_key AND f1_key >= table1.f1); + +DROP TABLE t1,t2; + --echo End of 5.2 tests From 1417606b1f4c5f8a4c24f6a93a77586f9cf5975c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 29 Dec 2011 22:52:13 +0100 Subject: [PATCH 26/83] on windows: don't link all plugins with mysqld, only do it for storage engines. --- storage/mysql_storage_engine.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/storage/mysql_storage_engine.cmake b/storage/mysql_storage_engine.cmake index cbe9a310d67..cc3659d51c9 100644 --- a/storage/mysql_storage_engine.cmake +++ b/storage/mysql_storage_engine.cmake @@ -42,7 +42,7 @@ IF(NOT SOURCE_SUBLIBS) ADD_DEFINITIONS(-DMYSQL_DYNAMIC_PLUGIN) ADD_VERSION_INFO(${${engine}_LIB} SHARED ${engine}_SOURCES) ADD_LIBRARY(${${engine}_LIB} MODULE ${${engine}_SOURCES}) - TARGET_LINK_LIBRARIES (${${engine}_LIB} mysqlservices mysqld) + TARGET_LINK_LIBRARIES (${${engine}_LIB} mysqlservices) IF(${engine}_LIBS) TARGET_LINK_LIBRARIES(${${engine}_LIB} ${${engine}_LIBS}) ENDIF(${engine}_LIBS) @@ -61,6 +61,8 @@ IF(NOT SOURCE_SUBLIBS) ${CMAKE_SOURCE_DIR}/extra/yassl/include) IF(${ENGINE_BUILD_TYPE} STREQUAL "STATIC") ADD_DEFINITIONS(-DWITH_${engine}_STORAGE_ENGINE -DMYSQL_SERVER) + ELSEIF(${ENGINE_BUILD_TYPE} STREQUAL "DYNAMIC") + TARGET_LINK_LIBRARIES (${${engine}_LIB} mysqld) ENDIF(${ENGINE_BUILD_TYPE} STREQUAL "STATIC") ENDIF(NOT SOURCE_SUBLIBS) ENDMACRO(MYSQL_STORAGE_ENGINE) From b8b7b4eb6bef26d05257272be02674ae5514ded9 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 30 Dec 2011 13:57:03 +0100 Subject: [PATCH 27/83] plugin renamed socket_peercred -> unix_socket. test added. --- mysql-test/suite/plugins/r/unix_socket.result | 30 ++++++++++ mysql-test/suite/plugins/t/unix_socket.test | 56 +++++++++++++++++++ plugin/auth/auth_socket.c | 18 +----- 3 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 mysql-test/suite/plugins/r/unix_socket.result create mode 100644 mysql-test/suite/plugins/t/unix_socket.test diff --git a/mysql-test/suite/plugins/r/unix_socket.result b/mysql-test/suite/plugins/r/unix_socket.result new file mode 100644 index 00000000000..45bf608cc93 --- /dev/null +++ b/mysql-test/suite/plugins/r/unix_socket.result @@ -0,0 +1,30 @@ +install plugin unix_socket soname 'auth_socket.so'; +# +# with named user +# +create user USER identified via unix_socket; +# +# name match = ok +# +select user(), current_user(), database(); +user() current_user() database() +USER@localhost USER@% test +# +# name does not match = failure +# +drop user USER; +# +# and now with anonymous user +# +grant SELECT ON test.* TO '' identified via unix_socket; +# +# name match = ok +# +select user(), current_user(), database(); +user() current_user() database() +USER@localhost @% test +# +# name does not match = failure +# +delete from mysql.user where user=''; +uninstall plugin unix_socket; diff --git a/mysql-test/suite/plugins/t/unix_socket.test b/mysql-test/suite/plugins/t/unix_socket.test new file mode 100644 index 00000000000..fc2e6c5b3c6 --- /dev/null +++ b/mysql-test/suite/plugins/t/unix_socket.test @@ -0,0 +1,56 @@ +--source include/not_embedded.inc + +if (!$AUTH_SOCKET_SO) { + skip No auth_socket plugin; +} + +let $plugindir=`SELECT @@global.plugin_dir`; + +eval install plugin unix_socket soname '$AUTH_SOCKET_SO'; + +--echo # +--echo # with named user +--echo # + +--replace_result $USER USER +eval create user $USER identified via unix_socket; + +--write_file $MYSQLTEST_VARDIR/tmp/peercred_test.txt +--replace_result $USER USER +select user(), current_user(), database(); +EOF + +--echo # +--echo # name match = ok +--echo # +--exec $MYSQL_TEST -u $USER --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/peercred_test.txt + +--echo # +--echo # name does not match = failure +--echo # +--error 1 +--exec $MYSQL_TEST -u foobar --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/peercred_test.txt + +--replace_result $USER USER +eval drop user $USER; + +--echo # +--echo # and now with anonymous user +--echo # +grant SELECT ON test.* TO '' identified via unix_socket; +--echo # +--echo # name match = ok +--echo # +--exec $MYSQL_TEST -u $USER --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/peercred_test.txt + +--echo # +--echo # name does not match = failure +--echo # +--error 1 +--exec $MYSQL_TEST -u foobar --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/peercred_test.txt + +# restoring mysql.user to the original state. +delete from mysql.user where user=''; +uninstall plugin unix_socket; +--remove_file $MYSQLTEST_VARDIR/tmp/peercred_test.txt + diff --git a/plugin/auth/auth_socket.c b/plugin/auth/auth_socket.c index cc406dac331..89d24e46f3c 100644 --- a/plugin/auth/auth_socket.c +++ b/plugin/auth/auth_socket.c @@ -83,27 +83,11 @@ static struct st_mysql_auth socket_auth_handler= socket_auth }; -mysql_declare_plugin(socket_auth) -{ - MYSQL_AUTHENTICATION_PLUGIN, - &socket_auth_handler, - "socket_peercred", - "Sergei Golubchik", - "Unix Socket based authentication", - PLUGIN_LICENSE_GPL, - NULL, - NULL, - 0x0100, - NULL, - NULL, - NULL -} -mysql_declare_plugin_end; maria_declare_plugin(socket_auth) { MYSQL_AUTHENTICATION_PLUGIN, &socket_auth_handler, - "socket_peercred", + "unix_socket", "Sergei Golubchik", "Unix Socket based authentication", PLUGIN_LICENSE_GPL, From 3c1125d4cafdf352ea84d2ff8e06738c4aec2156 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 12 Jan 2012 20:12:14 +0100 Subject: [PATCH 28/83] fixes for get_password(): 1. on windows: don't hang when there's no console, that is, _getch() returns -1. 2. on windows: _getch() returns an int, not char. to distinguish between (char)255 and (int)-1 3. everywhere. isspace(pos[-1]) == ' ' never worked, isspace() returns a boolean, not a char. the never-worked loop was removed to preserve the existing behavior. --- libmysql/get_password.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/libmysql/get_password.c b/libmysql/get_password.c index 747d598d72a..21200acf512 100644 --- a/libmysql/get_password.c +++ b/libmysql/get_password.c @@ -82,9 +82,9 @@ void get_tty_password_buff(const char *opt_message, char *to, size_t length) _cputs(opt_message ? opt_message : "Enter password: "); for (;;) { - char tmp; + int tmp; tmp=_getch(); - if (tmp == '\b' || (int) tmp == 127) + if (tmp == '\b' || tmp == 127) { if (pos != to) { @@ -93,15 +93,13 @@ void get_tty_password_buff(const char *opt_message, char *to, size_t length) continue; } } - if (tmp == '\n' || tmp == '\r' || tmp == 3) + if (tmp == -1 || tmp == '\n' || tmp == '\r' || tmp == 3) break; if (iscntrl(tmp) || pos == end) continue; _cputs("*"); - *(pos++) = tmp; + *(pos++) = (char)tmp; } - while (pos != to && isspace(pos[-1]) == ' ') - pos--; /* Allow dummy space at end */ *pos=0; _cputs("\n"); } @@ -148,8 +146,6 @@ static void get_password(char *to,uint length,int fd, my_bool echo) } *(pos++) = tmp; } - while (pos != to && isspace(pos[-1]) == ' ') - pos--; /* Allow dummy space at end */ *pos=0; return; } From f523df0a04b5c43103d9628f8c714b81b735e838 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 12 Jan 2012 20:12:46 +0100 Subject: [PATCH 29/83] openpam compatibility --- plugin/auth_pam/auth_pam.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/auth_pam/auth_pam.c b/plugin/auth_pam/auth_pam.c index 0d9cf2ae0af..ee13b37f793 100644 --- a/plugin/auth_pam/auth_pam.c +++ b/plugin/auth_pam/auth_pam.c @@ -131,7 +131,7 @@ end: return status == PAM_SUCCESS ? CR_OK : CR_ERROR; } -static struct st_mysql_auth pam_info = +static struct st_mysql_auth info = { MYSQL_AUTHENTICATION_INTERFACE_VERSION, "dialog", @@ -141,7 +141,7 @@ static struct st_mysql_auth pam_info = maria_declare_plugin(pam) { MYSQL_AUTHENTICATION_PLUGIN, - &pam_info, + &info, "pam", "Sergei Golubchik", "PAM based authentication", From a1e3fa93c74d50de3160545d3d9c18ca06dfcc7e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 12 Jan 2012 20:13:22 +0100 Subject: [PATCH 30/83] lp:893522 more problems found by PVS Studio --- sql/scheduler.cc | 2 +- sql/winservice.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/scheduler.cc b/sql/scheduler.cc index 6dd93640dc5..d301b205b58 100644 --- a/sql/scheduler.cc +++ b/sql/scheduler.cc @@ -514,7 +514,7 @@ static void libevent_connection_close(THD *thd) thd->killed= THD::KILL_CONNECTION; // Avoid error messages - if (thd->net.vio->sd >= 0) // not already closed + if (thd->net.vio->type != VIO_CLOSED) // not already closed { end_connection(thd); close_connection(thd, 0, 1); diff --git a/sql/winservice.c b/sql/winservice.c index 562f047fa79..3ec91c26835 100644 --- a/sql/winservice.c +++ b/sql/winservice.c @@ -116,7 +116,7 @@ int get_mysql_service_properties(const wchar_t *bin_path, wcscat(mysqld_path, L".exe"); if(wcsicmp(file_part, L"mysqld.exe") != 0 && - wcsicmp(file_part, L"mysqld.exe") != 0 && + wcsicmp(file_part, L"mysqld-debug.exe") != 0 && wcsicmp(file_part, L"mysqld-nt.exe") != 0) { /* The service executable is not mysqld. */ @@ -244,4 +244,4 @@ int get_mysql_service_properties(const wchar_t *bin_path, end: LocalFree((HLOCAL)args); return retval; -} \ No newline at end of file +} From e4c61d263bd452200440f38284294170246c73b0 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 12 Jan 2012 20:13:41 +0100 Subject: [PATCH 31/83] lp:901693 dialog.c:perform_dialog treats every password prompt as first --- plugin/auth/dialog.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin/auth/dialog.c b/plugin/auth/dialog.c index 24765c17d1c..6b54096f8ea 100644 --- a/plugin/auth/dialog.c +++ b/plugin/auth/dialog.c @@ -290,6 +290,8 @@ static int perform_dialog(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) if (res) return CR_ERROR; + first= 0; + /* repeat unless it was the last question */ } while ((cmd & 1) != 1); From 5438d57315a3cb2b75f63f83de7e50d12645e421 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 13 Jan 2012 14:35:49 +0200 Subject: [PATCH 32/83] Added Handler_read_rnd_deleted, number of deleted rows found with ha_read_rnd_first. --- mysql-test/r/create.result | 1 + mysql-test/r/derived_view.result | 10 +++++++++ mysql-test/r/join_outer.result | 3 +++ mysql-test/r/join_outer_jcl6.result | 3 +++ mysql-test/r/null_key.result | 1 + mysql-test/r/partition.result | 6 +++++ mysql-test/r/partition_pruning.result | 10 +++++++-- mysql-test/r/ps.result | 4 ++++ mysql-test/r/select_pkeycache.result | 1 + mysql-test/r/status.result | 30 ++++++++++++++++++++++++- mysql-test/r/status_user.result | 1 + mysql-test/suite/pbxt/r/null_key.result | 1 + mysql-test/suite/pbxt/r/update.result | 6 +++++ mysql-test/t/partition_pruning.test | 2 ++ mysql-test/t/status.test | 10 +++++++++ sql/ha_partition.cc | 2 ++ sql/mysqld.cc | 1 + sql/sql_class.h | 10 ++++++++- 18 files changed, 98 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 96abcd34b92..07b3f85d924 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1556,6 +1556,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 7 drop table t1,t2; CREATE TABLE t1(c1 VARCHAR(33), KEY USING BTREE (c1)); diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index cee19237230..7636f79189c 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -79,6 +79,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 flush status; select * from (select * from t1 where f1 in (2,3)) tt where f11=2; @@ -91,6 +92,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 12 for merged views create view v1 as select * from t1; @@ -162,6 +164,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 flush status; select * from v4 where f2 in (1,3); @@ -174,6 +177,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 12 for materialized derived tables explain for simple derived @@ -224,6 +228,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 flush status; select * from t1 join (select * from t2 group by f2) tt on f1=f2; @@ -238,6 +243,7 @@ Handler_read_key 11 Handler_read_next 3 Handler_read_prev 0 Handler_read_rnd 11 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 36 for materialized views drop view v1,v2,v3; @@ -311,6 +317,7 @@ Handler_read_key 22 Handler_read_next 22 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 60 explain showing late materialization flush status; @@ -326,6 +333,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 flush status; select * from t1 join v2 on f1=f2; @@ -340,6 +348,7 @@ Handler_read_key 11 Handler_read_next 3 Handler_read_prev 0 Handler_read_rnd 11 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 36 explain extended select * from v1 join v4 on f1=f2; id select_type table type possible_keys key key_len ref rows filtered Extra @@ -433,6 +442,7 @@ Handler_read_key 2 Handler_read_next 2 Handler_read_prev 0 Handler_read_rnd 8 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 39 flush status; merged in merged derived join merged in merged derived diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 9e84010d5ce..60defea291b 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1240,6 +1240,7 @@ Handler_read_key 5 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 6 DROP TABLE t1,t2; CREATE TABLE t1 (c int PRIMARY KEY, e int NOT NULL); @@ -1499,6 +1500,7 @@ Handler_read_key 4 Handler_read_next 5 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 1048581 flush status; select sum(t3.b) from t2 left join t3 on t3.a=t2.a and t2.a <> 10; @@ -1511,6 +1513,7 @@ Handler_read_key 4 Handler_read_next 5 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 1048581 drop table t1,t2,t3; # diff --git a/mysql-test/r/join_outer_jcl6.result b/mysql-test/r/join_outer_jcl6.result index ab9e437c6bf..767d0544f1b 100644 --- a/mysql-test/r/join_outer_jcl6.result +++ b/mysql-test/r/join_outer_jcl6.result @@ -1251,6 +1251,7 @@ Handler_read_key 5 Handler_read_next 9 Handler_read_prev 0 Handler_read_rnd 3 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 6 DROP TABLE t1,t2; CREATE TABLE t1 (c int PRIMARY KEY, e int NOT NULL); @@ -1510,6 +1511,7 @@ Handler_read_key 4 Handler_read_next 5 Handler_read_prev 0 Handler_read_rnd 5 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 1048581 flush status; select sum(t3.b) from t2 left join t3 on t3.a=t2.a and t2.a <> 10; @@ -1522,6 +1524,7 @@ Handler_read_key 4 Handler_read_next 5 Handler_read_prev 0 Handler_read_rnd 5 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 1048581 drop table t1,t2,t3; # diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result index 488110b88e3..a21f9190069 100644 --- a/mysql-test/r/null_key.result +++ b/mysql-test/r/null_key.result @@ -427,6 +427,7 @@ Handler_read_key 6 Handler_read_next 2 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 5 DROP TABLE t1,t2,t3,t4; CREATE TABLE t1 ( diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index adf7ddac8b7..866a6fc1197 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -382,6 +382,7 @@ Handler_read_key 2 Handler_read_next 4 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 EXPLAIN PARTITIONS SELECT c1 FROM t2 WHERE (c1 > 10 AND c1 < 13) OR (c1 > 17 AND c1 < 20); id select_type table partitions type possible_keys key key_len ref rows Extra @@ -400,6 +401,7 @@ Handler_read_key 2 Handler_read_next 4 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 DROP TABLE t1,t2; CREATE TABLE `t1` ( @@ -430,6 +432,7 @@ Handler_read_key 1 Handler_read_next 2 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 EXPLAIN PARTITIONS SELECT c1 FROM t2 WHERE (c1 > 2 AND c1 < 5); id select_type table partitions type possible_keys key key_len ref rows Extra @@ -446,6 +449,7 @@ Handler_read_key 1 Handler_read_next 2 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 EXPLAIN PARTITIONS SELECT c1 FROM t1 WHERE (c1 > 12 AND c1 < 15); id select_type table partitions type possible_keys key key_len ref rows Extra @@ -462,6 +466,7 @@ Handler_read_key 1 Handler_read_next 2 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 EXPLAIN PARTITIONS SELECT c1 FROM t2 WHERE (c1 > 12 AND c1 < 15); id select_type table partitions type possible_keys key key_len ref rows Extra @@ -478,6 +483,7 @@ Handler_read_key 1 Handler_read_next 2 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 DROP TABLE t1,t2; create table t1 (a int) partition by list ((a/3)*10 div 1) diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index 6d6371e263f..d5594c7453e 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -2639,7 +2639,10 @@ flush status; delete from t2 where b > 5; show status like 'Handler_read_rnd_next'; Variable_name Value -Handler_read_rnd_next 1215 +Handler_read_rnd_next 815 +show status like 'Handler_read_rnd_deleted'; +Variable_name Value +Handler_read_rnd_deleted 400 show status like 'Handler_read_key'; Variable_name Value Handler_read_key 0 @@ -2653,7 +2656,10 @@ flush status; delete from t2 where b < 5 or b > 3; show status like 'Handler_read_rnd_next'; Variable_name Value -Handler_read_rnd_next 1215 +Handler_read_rnd_next 515 +show status like 'Handler_read_rnd_deleted'; +Variable_name Value +Handler_read_rnd_deleted 700 show status like 'Handler_read_key'; Variable_name Value Handler_read_key 0 diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 08944da6182..09b3c1a3c67 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -3082,6 +3082,7 @@ Handler_read_key 1 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 flush status; execute st; @@ -3094,6 +3095,7 @@ Handler_read_key 1 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 flush status; select * from t1 use index() where a=3; @@ -3106,6 +3108,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 8 flush status; execute st; @@ -3118,6 +3121,7 @@ Handler_read_key 1 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 deallocate prepare st; drop table t1; diff --git a/mysql-test/r/select_pkeycache.result b/mysql-test/r/select_pkeycache.result index fc0f7283981..9648860619b 100644 --- a/mysql-test/r/select_pkeycache.result +++ b/mysql-test/r/select_pkeycache.result @@ -4342,6 +4342,7 @@ Handler_read_key 2 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 6 DROP TABLE t1, t2; CREATE TABLE t1 (f1 bigint(20) NOT NULL default '0', diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index 5579728e0b2..b0744726390 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -281,6 +281,7 @@ Handler_read_key 4 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 7 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 23 Handler_rollback 0 Handler_savepoint 0 @@ -296,7 +297,34 @@ Created_tmp_files 0 Created_tmp_tables 2 Handler_tmp_update 2 Handler_tmp_write 7 -Rows_tmp_read 34 +Rows_tmp_read 35 +drop table t1; +CREATE TABLE t1 (i int(11) DEFAULT NULL, KEY i (i) ) ENGINE=MyISAM; +insert into t1 values (1),(2),(3),(4),(5); +flush status; +select * from t1 where i=5 union select * from t1 where i=5; +i +5 +show status like "handler%"; +Variable_name Value +Handler_commit 0 +Handler_delete 0 +Handler_discover 0 +Handler_prepare 0 +Handler_read_first 0 +Handler_read_key 2 +Handler_read_next 2 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_deleted 1 +Handler_read_rnd_next 2 +Handler_rollback 0 +Handler_savepoint 0 +Handler_savepoint_rollback 0 +Handler_tmp_update 0 +Handler_tmp_write 2 +Handler_update 0 +Handler_write 0 drop table t1; set @@global.concurrent_insert= @old_concurrent_insert; SET GLOBAL log_output = @old_log_output; diff --git a/mysql-test/r/status_user.result b/mysql-test/r/status_user.result index bc5f0aff7e4..17c44df1d3c 100644 --- a/mysql-test/r/status_user.result +++ b/mysql-test/r/status_user.result @@ -106,6 +106,7 @@ Handler_read_key 3 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 5 Handler_rollback 2 Handler_savepoint 0 diff --git a/mysql-test/suite/pbxt/r/null_key.result b/mysql-test/suite/pbxt/r/null_key.result index bef8c92419a..cc2b417b263 100644 --- a/mysql-test/suite/pbxt/r/null_key.result +++ b/mysql-test/suite/pbxt/r/null_key.result @@ -427,5 +427,6 @@ Handler_read_key 6 Handler_read_next 2 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 5 DROP TABLE t1,t2,t3,t4; diff --git a/mysql-test/suite/pbxt/r/update.result b/mysql-test/suite/pbxt/r/update.result index 9154583fa81..46321d6f3bf 100644 --- a/mysql-test/suite/pbxt/r/update.result +++ b/mysql-test/suite/pbxt/r/update.result @@ -276,6 +276,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 flush status; update t1 set a=9999 order by a limit 1; @@ -290,6 +291,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 2 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 18 flush status; delete from t1 order by a limit 1; @@ -300,6 +302,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 1 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 9 flush status; delete from t1 order by a desc limit 1; @@ -310,6 +313,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 1 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 8 alter table t1 disable keys; Warnings: @@ -323,6 +327,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 1 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 7 select * from t1; a b @@ -376,6 +381,7 @@ Handler_read_key 1 Handler_read_next 1 Handler_read_prev 0 Handler_read_rnd 1 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 drop table t1, t2; create table t1(f1 int, `*f2` int); diff --git a/mysql-test/t/partition_pruning.test b/mysql-test/t/partition_pruning.test index f1ec8964769..f12593d746f 100644 --- a/mysql-test/t/partition_pruning.test +++ b/mysql-test/t/partition_pruning.test @@ -1086,12 +1086,14 @@ show status like 'Handler_read_key'; flush status; delete from t2 where b > 5; show status like 'Handler_read_rnd_next'; +show status like 'Handler_read_rnd_deleted'; show status like 'Handler_read_key'; show status like 'Handler_read_prev'; show status like 'Handler_read_next'; flush status; delete from t2 where b < 5 or b > 3; show status like 'Handler_read_rnd_next'; +show status like 'Handler_read_rnd_deleted'; show status like 'Handler_read_key'; show status like 'Handler_read_prev'; show status like 'Handler_read_next'; diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index 46e454363cc..8cc938c923e 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -368,6 +368,16 @@ show status like 'Handler%'; show status like '%tmp%'; drop table t1; +# +# Test of handler status counts +# +CREATE TABLE t1 (i int(11) DEFAULT NULL, KEY i (i) ) ENGINE=MyISAM; +insert into t1 values (1),(2),(3),(4),(5); +flush status; +select * from t1 where i=5 union select * from t1 where i=5; +show status like "handler%"; +drop table t1; + # End of 5.3 tests # Restore global concurrent_insert value. Keep in the end of the test file. diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 290224850c7..03a879815e8 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -3938,6 +3938,8 @@ int ha_partition::rnd_next(uchar *buf) int result= HA_ERR_END_OF_FILE; uint part_id= m_part_spec.start_part; DBUG_ENTER("ha_partition::rnd_next"); + + /* upper level will increment this once again at end of call */ decrement_statistics(&SSV::ha_read_rnd_next_count); if (NO_CURRENT_PART_ID == part_id) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1a60d996fed..1312675f7b4 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8294,6 +8294,7 @@ SHOW_VAR status_vars[]= { {"Handler_read_next", (char*) offsetof(STATUS_VAR, ha_read_next_count), SHOW_LONG_STATUS}, {"Handler_read_prev", (char*) offsetof(STATUS_VAR, ha_read_prev_count), SHOW_LONG_STATUS}, {"Handler_read_rnd", (char*) offsetof(STATUS_VAR, ha_read_rnd_count), SHOW_LONG_STATUS}, + {"Handler_read_rnd_deleted", (char*) offsetof(STATUS_VAR, ha_read_rnd_deleted_count), SHOW_LONG_STATUS}, {"Handler_read_rnd_next", (char*) offsetof(STATUS_VAR, ha_read_rnd_next_count), SHOW_LONG_STATUS}, {"Handler_rollback", (char*) offsetof(STATUS_VAR, ha_rollback_count), SHOW_LONG_STATUS}, {"Handler_savepoint", (char*) offsetof(STATUS_VAR, ha_savepoint_count), SHOW_LONG_STATUS}, diff --git a/sql/sql_class.h b/sql/sql_class.h index da82ed5beed..f7d44eeec52 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -571,6 +571,7 @@ typedef struct system_status_var ulong ha_read_prev_count; ulong ha_read_rnd_count; ulong ha_read_rnd_next_count; + ulong ha_read_rnd_deleted_count; /* This number doesn't include calls to the default implementation and calls made by range access. The intent is to count only calls made by @@ -3747,10 +3748,17 @@ inline int handler::ha_ft_read(uchar *buf) inline int handler::ha_rnd_next(uchar *buf) { - increment_statistics(&SSV::ha_read_rnd_next_count); int error= rnd_next(buf); if (!error) + { update_rows_read(); + increment_statistics(&SSV::ha_read_rnd_next_count); + } + else if (error == HA_ERR_RECORD_DELETED) + increment_statistics(&SSV::ha_read_rnd_deleted_count); + else + increment_statistics(&SSV::ha_read_rnd_next_count); + table->status=error ? STATUS_NOT_FOUND: 0; return error; } From 6b4c132bc771631e85ca647f0dc4fc098859101a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 17 Jan 2012 15:16:00 +0200 Subject: [PATCH 33/83] Removed unused code merged from 5.2. In 5.3 we fix this problem by checking if we put max/min group function without GROUP BY artificially in case of MODE_ONLY_FULL_GROUP_BY sql mode. --- sql/item_subselect.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 699c6e11cc1..ed556f05466 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1672,10 +1672,6 @@ bool Item_allany_subselect::transform_into_max_min(JOIN *join) DBUG_EXECUTE("where", print_where(item, "rewrite with MIN/MAX", QT_ORDINARY);); - if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) - { - select_lex->set_non_agg_field_used(false); - } save_allow_sum_func= thd->lex->allow_sum_func; thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level; From 69327e2987f7d5a2749860d269cdb4d75b646f24 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 18 Jan 2012 12:53:50 +0200 Subject: [PATCH 34/83] Adjust test results after Monty's push of the new handler counter Handler_read_rnd_deleted. --- mysql-test/r/insert_select.result | 1 + mysql-test/r/join.result | 2 ++ mysql-test/r/select.result | 1 + mysql-test/r/select_jcl6.result | 3 ++- mysql-test/r/subselect3.result | 1 + mysql-test/r/subselect3_jcl6.result | 1 + mysql-test/r/subselect_cache.result | 34 +++++++++++++++++++++++++++-- mysql-test/r/update.result | 14 ++++++++++-- mysql-test/r/view.result | 2 ++ 9 files changed, 54 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index cf3c0b0731e..636eecc085b 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -697,6 +697,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 1 DROP TABLE t1; CREATE TABLE t1 ( diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 8a8b9a690a9..b1cfd80490d 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -860,6 +860,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 5 drop table t1, t2, t3; create table t1 (a int); @@ -1269,6 +1270,7 @@ Handler_read_key 1 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 1 DROP TABLE t1, t2; End of 5.1 tests diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index fc0f7283981..9648860619b 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4342,6 +4342,7 @@ Handler_read_key 2 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 6 DROP TABLE t1, t2; CREATE TABLE t1 (f1 bigint(20) NOT NULL default '0', diff --git a/mysql-test/r/select_jcl6.result b/mysql-test/r/select_jcl6.result index 2d3add1b922..88411e3482f 100644 --- a/mysql-test/r/select_jcl6.result +++ b/mysql-test/r/select_jcl6.result @@ -4353,7 +4353,8 @@ Handler_read_key 2 Handler_read_next 10 Handler_read_prev 0 Handler_read_rnd 10 -Handler_read_rnd_next 7 +Handler_read_rnd_deleted 1 +Handler_read_rnd_next 6 DROP TABLE t1, t2; CREATE TABLE t1 (f1 bigint(20) NOT NULL default '0', f2 int(11) NOT NULL default '0', diff --git a/mysql-test/r/subselect3.result b/mysql-test/r/subselect3.result index ae629ccb928..3f83ac59fed 100644 --- a/mysql-test/r/subselect3.result +++ b/mysql-test/r/subselect3.result @@ -124,6 +124,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 50 select 'No key lookups, seq reads: 29= 5 reads from t2 + 4 * 6 reads from t1.' Z; Z diff --git a/mysql-test/r/subselect3_jcl6.result b/mysql-test/r/subselect3_jcl6.result index 7d20f81fbb9..38284345fc2 100644 --- a/mysql-test/r/subselect3_jcl6.result +++ b/mysql-test/r/subselect3_jcl6.result @@ -134,6 +134,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 50 select 'No key lookups, seq reads: 29= 5 reads from t2 + 4 * 6 reads from t1.' Z; Z diff --git a/mysql-test/r/subselect_cache.result b/mysql-test/r/subselect_cache.result index 1dd1655c2a6..1f9fcdeca6e 100644 --- a/mysql-test/r/subselect_cache.result +++ b/mysql-test/r/subselect_cache.result @@ -36,6 +36,7 @@ Handler_read_key 7 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 31 set optimizer_switch='subquery_cache=off'; flush status; @@ -62,6 +63,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 61 set optimizer_switch='subquery_cache=on'; #single value subquery test (where) @@ -87,6 +89,7 @@ Handler_read_key 7 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 31 set optimizer_switch='subquery_cache=off'; flush status; @@ -111,6 +114,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 61 set optimizer_switch='subquery_cache=on'; #single value subquery test (having) @@ -136,6 +140,7 @@ Handler_read_key 7 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 31 set optimizer_switch='subquery_cache=off'; flush status; @@ -160,6 +165,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 61 set optimizer_switch='subquery_cache=on'; #single value subquery test (OUTER JOIN ON) @@ -257,6 +263,7 @@ Handler_read_key 7 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 442 set optimizer_switch='subquery_cache=off'; flush status; @@ -353,6 +360,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 472 set optimizer_switch='subquery_cache=on'; #single value subquery test (GROUP BY) @@ -374,6 +382,7 @@ Handler_read_key 17 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 4 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 36 set optimizer_switch='subquery_cache=off'; flush status; @@ -394,6 +403,7 @@ Handler_read_key 10 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 4 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 86 set optimizer_switch='subquery_cache=on'; #single value subquery test (distinct GROUP BY) @@ -415,6 +425,7 @@ Handler_read_key 17 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 4 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 41 set optimizer_switch='subquery_cache=off'; flush status; @@ -435,6 +446,7 @@ Handler_read_key 10 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 4 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 91 set optimizer_switch='subquery_cache=on'; #single value subquery test (ORDER BY) @@ -462,6 +474,7 @@ Handler_read_key 7 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 10 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 42 set optimizer_switch='subquery_cache=off'; flush status; @@ -488,6 +501,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 10 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 72 set optimizer_switch='subquery_cache=on'; #single value subquery test (distinct ORDER BY) @@ -509,7 +523,8 @@ Handler_read_key 7 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 4 -Handler_read_rnd_next 37 +Handler_read_rnd_deleted 1 +Handler_read_rnd_next 36 set optimizer_switch='subquery_cache=off'; flush status; select distinct a from t1 ORDER BY (select d from t2 where b=c); @@ -529,7 +544,8 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 4 -Handler_read_rnd_next 67 +Handler_read_rnd_deleted 1 +Handler_read_rnd_next 66 set optimizer_switch='subquery_cache=on'; #single value subquery test (LEFT JOIN ON) flush status; @@ -626,6 +642,7 @@ Handler_read_key 70 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 141 set optimizer_switch='subquery_cache=off'; flush status; @@ -722,6 +739,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 671 set optimizer_switch='subquery_cache=on'; #single value subquery test (PS) @@ -1345,6 +1363,7 @@ Handler_read_key 11 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 145 set optimizer_switch='subquery_cache=on'; flush status; @@ -1373,6 +1392,7 @@ Handler_read_key 32 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 84 #several subqueries (several levels) set optimizer_switch='subquery_cache=off'; @@ -1404,6 +1424,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 127 set optimizer_switch='subquery_cache=on'; flush status; @@ -1432,6 +1453,7 @@ Handler_read_key 13 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 69 #clean up drop table t1,t2; @@ -1621,6 +1643,7 @@ Handler_read_key 15 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 8 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 57 set optimizer_switch='subquery_cache=on'; flush status; @@ -1645,6 +1668,7 @@ Handler_read_key 21 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 8 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 37 argument of aggregate function as parameter of subquery (illegal use) set optimizer_switch='subquery_cache=off'; @@ -1670,6 +1694,7 @@ Handler_read_key 15 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 8 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 57 set optimizer_switch='subquery_cache=on'; flush status; @@ -1694,6 +1719,7 @@ Handler_read_key 22 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 8 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 41 drop table t1,t2; #test of flattening subquery optimisations and cache @@ -1734,6 +1760,7 @@ Handler_read_key 15 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 16 alter table t2 drop primary key; set optimizer_switch='default,semijoin=off,materialization=off,subquery_cache=off'; @@ -1770,6 +1797,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 151 set optimizer_switch='default,semijoin=off,materialization=off,subquery_cache=on'; explain select * from t1 where a in (select pk from t2); @@ -1805,6 +1833,7 @@ Handler_read_key 15 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 43 set optimizer_switch='default,semijoin=off,materialization=on,subquery_cache=on'; explain select * from t1 where a in (select pk from t2); @@ -1840,6 +1869,7 @@ Handler_read_key 18 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 27 drop table t0,t1,t2; set optimizer_switch='default'; diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index 63baf639487..4062a92901d 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -276,6 +276,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 flush status; update t1 set a=9999 order by a limit 1; @@ -287,6 +288,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 2 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 9 flush status; delete from t1 order by a limit 1; @@ -297,6 +299,7 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 flush status; delete from t1 order by a desc limit 1; @@ -307,7 +310,8 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 1 -Handler_read_rnd_next 9 +Handler_read_rnd_deleted 1 +Handler_read_rnd_next 8 alter table t1 disable keys; flush status; delete from t1 order by a limit 1; @@ -318,7 +322,8 @@ Handler_read_key 0 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 1 -Handler_read_rnd_next 9 +Handler_read_rnd_deleted 2 +Handler_read_rnd_next 7 select * from t1; a b 0 0 @@ -371,6 +376,7 @@ Handler_read_key 1 Handler_read_next 1 Handler_read_prev 0 Handler_read_rnd 1 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 drop table t1, t2; create table t1(f1 int, `*f2` int); @@ -408,6 +414,7 @@ Handler_read_key 1 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 SELECT user_id FROM t1 WHERE request_id=999999999999999999999999999999; user_id @@ -418,6 +425,7 @@ Handler_read_key 2 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 UPDATE t1 SET user_id=null WHERE request_id=9999999999999; show status like '%Handler_read%'; @@ -427,6 +435,7 @@ Handler_read_key 3 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 UPDATE t1 SET user_id=null WHERE request_id=999999999999999999999999999999; show status like '%Handler_read%'; @@ -436,6 +445,7 @@ Handler_read_key 3 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 DROP TABLE t1; CREATE TABLE t1 ( diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 644f7f7289e..f3d68e67b61 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -3959,6 +3959,7 @@ Handler_read_key 1 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 17 CREATE VIEW v AS SELECT * FROM t2; EXPLAIN EXTENDED @@ -3980,6 +3981,7 @@ Handler_read_key 1 Handler_read_next 0 Handler_read_prev 0 Handler_read_rnd 0 +Handler_read_rnd_deleted 0 Handler_read_rnd_next 17 DROP VIEW v; DROP TABLE t1, t2; From 746dbbe583f8528b34065b0669136842128e27b2 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Wed, 18 Jan 2012 03:31:20 -0800 Subject: [PATCH 35/83] Fixed LP bug #917990. If the expression for a derived table of a query contained a LIMIT clause the estimate of the number of rows in this derived table returned by the EXPLAIN command could be badly off since the optimizer ignored the limit number from the LIMIT clause when getting the estimate. The call of the method SELECT_LEX_UNIT->set_limit added in the code of mysql_derived_optimize() will be needed also in maria-5.5 where parameters in the LIMIT clause are supported. --- mysql-test/r/derived_view.result | 17 +++++++++++++++++ mysql-test/r/view.result | 2 +- mysql-test/suite/vcol/r/vcol_view_innodb.result | 4 ++-- mysql-test/suite/vcol/r/vcol_view_myisam.result | 4 ++-- mysql-test/t/derived_view.test | 14 ++++++++++++++ sql/sql_derived.cc | 1 + sql/sql_select.cc | 1 + 7 files changed, 38 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index cee19237230..416c68ffb46 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -1879,5 +1879,22 @@ ORDER BY CONCAT(alias2.col_varchar_nokey); col_varchar_key pk col_varchar_key col_varchar_nokey set max_heap_table_size= @tmp_882994; drop table t1,t2,t3; +# +# LP bug #917990: Bad estimate of #rows for derived table with LIMIT +# +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES +(8), (3), (4), (7), (9), (5), (1), (2); +SELECT * FROM (SELECT * FROM t1 LIMIT 3) t; +a +8 +3 +4 +EXPLAIN +SELECT * FROM (SELECT * FROM t1 LIMIT 3) t; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 3 +2 DERIVED t1 ALL NULL NULL NULL NULL 8 +DROP TABLE t1; set optimizer_switch=@exit_optimizer_switch; set join_cache_level=@exit_join_cache_level; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 644f7f7289e..8a71d00291c 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -304,7 +304,7 @@ a+1 4 explain select * from v1; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ALL NULL NULL NULL NULL 4 +1 PRIMARY ALL NULL NULL NULL NULL 2 2 DERIVED t1 ALL NULL NULL NULL NULL 4 Using filesort drop view v1; drop table t1; diff --git a/mysql-test/suite/vcol/r/vcol_view_innodb.result b/mysql-test/suite/vcol/r/vcol_view_innodb.result index 94c311fb8b9..d117b030f94 100644 --- a/mysql-test/suite/vcol/r/vcol_view_innodb.result +++ b/mysql-test/suite/vcol/r/vcol_view_innodb.result @@ -107,7 +107,7 @@ MariaDB-5.3: the following EXPLAIN produces incorrect #rows for table t1. MariaDB-5.3: this is expected to go away when FROM subquery optimizations are pushed explain select * from v1; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ALL NULL NULL NULL NULL 4 +1 PRIMARY ALL NULL NULL NULL NULL 2 2 DERIVED t1 ALL NULL NULL NULL NULL 4 Using filesort drop view v1; create view v1 as select c+1 from t1 order by 1 desc limit 2; @@ -119,7 +119,7 @@ MariaDB-5.3: the following EXPLAIN produces incorrect #rows for table t1. MariaDB-5.3: this is expected to go away when FROM subquery optimizations are pushed explain select * from v1; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ALL NULL NULL NULL NULL 4 +1 PRIMARY ALL NULL NULL NULL NULL 2 2 DERIVED t1 ALL NULL NULL NULL NULL 4 Using filesort drop view v1; drop table t1; diff --git a/mysql-test/suite/vcol/r/vcol_view_myisam.result b/mysql-test/suite/vcol/r/vcol_view_myisam.result index b96e003e1cc..fe48be4c794 100644 --- a/mysql-test/suite/vcol/r/vcol_view_myisam.result +++ b/mysql-test/suite/vcol/r/vcol_view_myisam.result @@ -107,7 +107,7 @@ MariaDB-5.3: the following EXPLAIN produces incorrect #rows for table t1. MariaDB-5.3: this is expected to go away when FROM subquery optimizations are pushed explain select * from v1; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ALL NULL NULL NULL NULL 4 +1 PRIMARY ALL NULL NULL NULL NULL 2 2 DERIVED t1 ALL NULL NULL NULL NULL 4 Using filesort drop view v1; create view v1 as select c+1 from t1 order by 1 desc limit 2; @@ -119,7 +119,7 @@ MariaDB-5.3: the following EXPLAIN produces incorrect #rows for table t1. MariaDB-5.3: this is expected to go away when FROM subquery optimizations are pushed explain select * from v1; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ALL NULL NULL NULL NULL 4 +1 PRIMARY ALL NULL NULL NULL NULL 2 2 DERIVED t1 ALL NULL NULL NULL NULL 4 Using filesort drop view v1; drop table t1; diff --git a/mysql-test/t/derived_view.test b/mysql-test/t/derived_view.test index b674350af0a..f8ba1f347f3 100644 --- a/mysql-test/t/derived_view.test +++ b/mysql-test/t/derived_view.test @@ -1277,6 +1277,20 @@ ORDER BY CONCAT(alias2.col_varchar_nokey); set max_heap_table_size= @tmp_882994; drop table t1,t2,t3; +--echo # +--echo # LP bug #917990: Bad estimate of #rows for derived table with LIMIT +--echo # + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES + (8), (3), (4), (7), (9), (5), (1), (2); + +SELECT * FROM (SELECT * FROM t1 LIMIT 3) t; +EXPLAIN +SELECT * FROM (SELECT * FROM t1 LIMIT 3) t; + +DROP TABLE t1; + # The following command must be the last one the file set optimizer_switch=@exit_optimizer_switch; set join_cache_level=@exit_join_cache_level; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 0e104520fac..0955f9c0982 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -753,6 +753,7 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived) if (!derived->is_merged_derived()) { JOIN *join= first_select->join; + unit->set_limit(first_select); unit->optimized= TRUE; if ((res= join->optimize())) goto err; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fe52bc05465..dc13e1ddcab 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3581,6 +3581,7 @@ make_join_statistics(JOIN *join, List &tables_list, for (i= 0; i < join->table_count ; i++) records*= join->best_positions[i].records_read ? (ha_rows)join->best_positions[i].records_read : 1; + set_if_smaller(records, unit->select_limit_cnt); join->select_lex->increase_derived_records(records); } } From 88f451aa6e6c09b199f5e00f48500157c7f3e245 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 18 Jan 2012 14:52:56 +0100 Subject: [PATCH 36/83] multi-delete should ignore semi-join internal temp tables, when looking for tables to delete from --- sql/sql_delete.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 722b6f7478f..3ce375190a7 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -715,7 +715,7 @@ multi_delete::initialize_tables(JOIN *join) for (JOIN_TAB *tab= first_linear_tab(join, WITH_CONST_TABLES); tab; - tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS)) + tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS)) { if (tab->table->map & tables_to_delete_from) { From 0e975ded65510a85173a6d05b9fd4824fbfd07af Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 19 Jan 2012 13:46:59 +0100 Subject: [PATCH 37/83] Fix compiler warning on Windows. --- storage/xtradb/row/row0sel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/xtradb/row/row0sel.c b/storage/xtradb/row/row0sel.c index 4ae55b47b5b..226b19359bb 100644 --- a/storage/xtradb/row/row0sel.c +++ b/storage/xtradb/row/row0sel.c @@ -3455,6 +3455,7 @@ row_search_idx_cond_check( } ut_error; + return(ICP_ABORTED_BY_USER); /* Keep compiler happy */ } /********************************************************************//** From 8bedf1ea1c328fabea14a1ce232794d73814b6d7 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 19 Jan 2012 23:44:43 +0400 Subject: [PATCH 38/83] BUG#912538: Wrong result (missing rows) with semijoin=on, firstmatch=on, ... - setup_semijoin_dups_elimination() would incorrectly set join_tab->do_firstmatch when the join order had outer tables interleaved with inner. --- mysql-test/r/subselect_sj2.result | 14 ++++++++++ mysql-test/r/subselect_sj2_jcl6.result | 23 +++++++++++++--- mysql-test/r/subselect_sj2_mat.result | 14 ++++++++++ mysql-test/t/subselect_sj2.test | 14 ++++++++++ sql/opt_subselect.cc | 37 +++++++++++++++++++++----- 5 files changed, 91 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/subselect_sj2.result b/mysql-test/r/subselect_sj2.result index 8df3bd8f9b8..4e9672446a3 100644 --- a/mysql-test/r/subselect_sj2.result +++ b/mysql-test/r/subselect_sj2.result @@ -889,5 +889,19 @@ a b b a c c NULL NULL DROP VIEW v1; DROP TABLE t1,t2,t3,t4; +# +# BUG#912538: Wrong result (missing rows) with semijoin=on, firstmatch=on, ... +# +CREATE TABLE t1 ( a INT NOT NULL, UNIQUE KEY(a) ); +INSERT INTO t1 VALUES (1),(2),(3),(4); +CREATE TABLE t2 ( b INT, c INT ) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1,1); +SELECT * FROM t1, t2 WHERE c IN (SELECT c FROM t1, t2 WHERE a = b); +a b c +1 1 1 +2 1 1 +3 1 1 +4 1 1 +DROP TABLE t1,t2; # This must be the last in the file: set optimizer_switch=@subselect_sj2_tmp; diff --git a/mysql-test/r/subselect_sj2_jcl6.result b/mysql-test/r/subselect_sj2_jcl6.result index 222d34d9bf4..1b7d65275ab 100644 --- a/mysql-test/r/subselect_sj2_jcl6.result +++ b/mysql-test/r/subselect_sj2_jcl6.result @@ -903,6 +903,20 @@ a b b a c c NULL NULL DROP VIEW v1; DROP TABLE t1,t2,t3,t4; +# +# BUG#912538: Wrong result (missing rows) with semijoin=on, firstmatch=on, ... +# +CREATE TABLE t1 ( a INT NOT NULL, UNIQUE KEY(a) ); +INSERT INTO t1 VALUES (1),(2),(3),(4); +CREATE TABLE t2 ( b INT, c INT ) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1,1); +SELECT * FROM t1, t2 WHERE c IN (SELECT c FROM t1, t2 WHERE a = b); +a b c +1 1 1 +2 1 1 +3 1 1 +4 1 1 +DROP TABLE t1,t2; # This must be the last in the file: set optimizer_switch=@subselect_sj2_tmp; # @@ -924,9 +938,9 @@ SELECT t3.* FROM t1 JOIN t3 ON t3.b = t1.b WHERE c IN (SELECT t4.b FROM t4 JOIN t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 1 Using where -1 PRIMARY t2 ALL NULL NULL NULL NULL 1 +1 PRIMARY t2 ALL NULL NULL NULL NULL 1 FirstMatch(t3) 1 PRIMARY t1 ref b b 4 test.t3.b 1 Using index -1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t2) +1 PRIMARY t4 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t1) SELECT t3.* FROM t1 JOIN t3 ON t3.b = t1.b WHERE c IN (SELECT t4.b FROM t4 JOIN t2); b c @@ -952,12 +966,13 @@ EXPLAIN SELECT * FROM t1, t2 WHERE b IN (SELECT a FROM t3, t4 WHERE b = pk); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 -1 PRIMARY t4 ALL NULL NULL NULL NULL 1 Using where +1 PRIMARY t4 ALL NULL NULL NULL NULL 1 Using where; FirstMatch(t2) 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 -1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.b 1 Using where; FirstMatch(t4) +1 PRIMARY t3 eq_ref PRIMARY PRIMARY 4 test.t4.b 1 Using where; FirstMatch(t1) SELECT * FROM t1, t2 WHERE b IN (SELECT a FROM t3, t4 WHERE b = pk); pk a b 1 6 8 +2 8 8 set optimizer_switch=@tmp_optimizer_switch; set join_cache_level=default; DROP TABLE t1,t2,t3,t4; diff --git a/mysql-test/r/subselect_sj2_mat.result b/mysql-test/r/subselect_sj2_mat.result index 252f3c73a55..64d1ce2ef74 100644 --- a/mysql-test/r/subselect_sj2_mat.result +++ b/mysql-test/r/subselect_sj2_mat.result @@ -891,6 +891,20 @@ a b b a c c NULL NULL DROP VIEW v1; DROP TABLE t1,t2,t3,t4; +# +# BUG#912538: Wrong result (missing rows) with semijoin=on, firstmatch=on, ... +# +CREATE TABLE t1 ( a INT NOT NULL, UNIQUE KEY(a) ); +INSERT INTO t1 VALUES (1),(2),(3),(4); +CREATE TABLE t2 ( b INT, c INT ) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1,1); +SELECT * FROM t1, t2 WHERE c IN (SELECT c FROM t1, t2 WHERE a = b); +a b c +1 1 1 +2 1 1 +3 1 1 +4 1 1 +DROP TABLE t1,t2; # This must be the last in the file: set optimizer_switch=@subselect_sj2_tmp; set optimizer_switch=default; diff --git a/mysql-test/t/subselect_sj2.test b/mysql-test/t/subselect_sj2.test index 9a664ee9881..30dc20087d1 100644 --- a/mysql-test/t/subselect_sj2.test +++ b/mysql-test/t/subselect_sj2.test @@ -1076,5 +1076,19 @@ SELECT * FROM t3 LEFT JOIN (v1,t2) ON t3.a = t2.a DROP VIEW v1; DROP TABLE t1,t2,t3,t4; +--echo # +--echo # BUG#912538: Wrong result (missing rows) with semijoin=on, firstmatch=on, ... +--echo # +CREATE TABLE t1 ( a INT NOT NULL, UNIQUE KEY(a) ); +INSERT INTO t1 VALUES (1),(2),(3),(4); + +# t2 needs to be InnoDB +CREATE TABLE t2 ( b INT, c INT ) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1,1); + +SELECT * FROM t1, t2 WHERE c IN (SELECT c FROM t1, t2 WHERE a = b); + +DROP TABLE t1,t2; + --echo # This must be the last in the file: set optimizer_switch=@subselect_sj2_tmp; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 1719b5a53d5..8e043b17bcf 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -4162,16 +4162,39 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, } case SJ_OPT_FIRST_MATCH: { - JOIN_TAB *j, *jump_to= tab-1; + JOIN_TAB *j; + JOIN_TAB *jump_to= tab-1; for (j= tab; j != tab + pos->n_sj_tables; j++) { - /* - NOTE: this loop probably doesn't do the right thing for the case - where FirstMatch's duplicate-generating range is interleaved with - "unrelated" tables (as specified in WL#3750, section 2.2). - */ if (!j->emb_sj_nest) - jump_to= tab; + { + /* + Got a table that's not within any semi-join nest. This is a case + like this: + + SELECT * FROM ot1, nt1 WHERE ot1.col IN (SELECT expr FROM it1, it2) + + with a join order of + + + ot1 it1 nt1 nt2 + | ^ + | +-------- 'j' point here + +------------- SJ_OPT_FIRST_MATCH was set for this table as + it's the first one that produces duplicates + + */ + DBUG_ASSERT(j != tab); /* table ntX must have an itX before it */ + + /* + If the table right before us is an inner table (like it1 in the + picture), it should be set to jump back to previous outer-table + */ + if (j[-1].emb_sj_nest) + j[-1].do_firstmatch= jump_to; + + jump_to= j; /* Jump back to us */ + } else { j->first_sj_inner_tab= tab; From 9f60aa27f707dea88e8882c5aaf096dce35a3a72 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 20 Jan 2012 02:11:53 +0400 Subject: [PATCH 39/83] BUG#912513: Wrong result (missing rows) with join_cache_hashed+materialization+semijoin=on - equality substitution code was geared towards processing WHERE/ON clauses. that is, it assumed that it was doing substitions on the code that = wasn't attached to any particular join_tab yet = was going to be fed to make_join_select() which would take the condition apart and attach various parts of it to tables inside/outside semi-joins. - However, somebody added equality substition for ref access. That is, if we have a ref access on TBL.key=expr, they would do equality substition in 'expr'. This possibility wasn't accounted for. - Fixed equality substition code by adding a mode that does equality substition under assumption that the processed expression will be attached to a certain particular table TBL. --- mysql-test/r/subselect_sj_jcl6.result | 29 +++++++++++++++ mysql-test/t/subselect_sj_jcl6.test | 26 ++++++++++++++ sql/item.cc | 6 ++-- sql/item.h | 11 ++++++ sql/item_cmpfunc.cc | 10 ++++-- sql/item_cmpfunc.h | 2 +- sql/sql_select.cc | 51 ++++++++++++++++++++++----- 7 files changed, 121 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index 21a8ea39457..faa4140d375 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -2264,6 +2264,35 @@ w 5 19:11:10 set optimizer_switch=@save_optimizer_switch; set join_cache_level=default; DROP TABLE t1,t2,t3; +# +# BUG#912513: Wrong result (missing rows) with join_cache_hashed+materialization+semijoin=on +# +set @os_912513= @@optimizer_switch; +set @jcl_912513= @@join_cache_level; +SET optimizer_switch = 'semijoin=on,materialization=on,join_cache_hashed=on'; +SET join_cache_level = 3; +CREATE TABLE t1 ( a INT, b INT, KEY(a) ); +INSERT INTO t1 VALUES +(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7); +CREATE TABLE t2 ( c INT ); +INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6),(7); +SELECT alias1.* FROM +t1 AS alias1 INNER JOIN t1 AS alias2 +ON alias2.a = alias1.b +WHERE alias1.b IN ( +SELECT a FROM t1, t2 +); +a b +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +DROP table t1, t2; +set @@optimizer_switch= @os_912513; +set @@join_cache_level= @jcl_912513; # End set join_cache_level=default; show variables like 'join_cache_level'; diff --git a/mysql-test/t/subselect_sj_jcl6.test b/mysql-test/t/subselect_sj_jcl6.test index 4eeaa465b11..6d563cab3d3 100644 --- a/mysql-test/t/subselect_sj_jcl6.test +++ b/mysql-test/t/subselect_sj_jcl6.test @@ -88,6 +88,32 @@ set join_cache_level=default; DROP TABLE t1,t2,t3; +--echo # +--echo # BUG#912513: Wrong result (missing rows) with join_cache_hashed+materialization+semijoin=on +--echo # +set @os_912513= @@optimizer_switch; +set @jcl_912513= @@join_cache_level; +SET optimizer_switch = 'semijoin=on,materialization=on,join_cache_hashed=on'; +SET join_cache_level = 3; + +CREATE TABLE t1 ( a INT, b INT, KEY(a) ); +INSERT INTO t1 VALUES + (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7); + +CREATE TABLE t2 ( c INT ); +INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6),(7); + +SELECT alias1.* FROM + t1 AS alias1 INNER JOIN t1 AS alias2 + ON alias2.a = alias1.b +WHERE alias1.b IN ( + SELECT a FROM t1, t2 + ); + +DROP table t1, t2; +set @@optimizer_switch= @os_912513; +set @@join_cache_level= @jcl_912513; + --echo # End set join_cache_level=default; diff --git a/sql/item.cc b/sql/item.cc index d0608e392b3..aaf9b0c2a12 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5023,7 +5023,8 @@ bool Item_field::set_no_const_sub(uchar *arg) Item *Item_field::replace_equal_field(uchar *arg) { - if (item_equal && item_equal == (Item_equal *) arg) + REPLACE_EQUAL_FIELD_ARG* param= (REPLACE_EQUAL_FIELD_ARG*)arg; + if (item_equal && item_equal == param->item_equal) { Item *const_item= item_equal->get_const(); if (const_item) @@ -5033,7 +5034,8 @@ Item *Item_field::replace_equal_field(uchar *arg) return this; return const_item; } - Item_field *subst= (Item_field *)(item_equal->get_first(this)); + Item_field *subst= + (Item_field *)(item_equal->get_first(param->context_tab, this)); if (subst) subst= (Item_field *) (subst->real_item()); if (subst && !field->eq(subst->field)) diff --git a/sql/item.h b/sql/item.h index d9aa6f3497e..9891d690798 100644 --- a/sql/item.h +++ b/sql/item.h @@ -440,6 +440,16 @@ typedef enum monotonicity_info class sp_rcontext; +class Item_equal; + +struct st_join_table* const NO_PARTICULAR_TAB= (struct st_join_table*)0x1; + +typedef struct replace_equal_field_arg +{ + Item_equal *item_equal; + struct st_join_table *context_tab; +} REPLACE_EQUAL_FIELD_ARG; + class Settable_routine_parameter { public: @@ -1153,6 +1163,7 @@ public: virtual Item *equal_fields_propagator(uchar * arg) { return this; } virtual bool set_no_const_sub(uchar *arg) { return FALSE; } + /* arg points to REPLACE_EQUAL_FIELD_ARG object */ virtual Item *replace_equal_field(uchar * arg) { return this; } /* Check if an expression value has allowed arguments, like DATE/DATETIME diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 5b2c862e9eb..8b8a85ca59b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -5716,7 +5716,7 @@ longlong Item_equal::val_int() void Item_equal::fix_length_and_dec() { - Item *item= get_first(NULL); + Item *item= get_first(NO_PARTICULAR_TAB, NULL); eval_item= cmp_item::get_comparator(item->cmp_type(), item, item->collation.collation); } @@ -5816,7 +5816,7 @@ CHARSET_INFO *Item_equal::compare_collation() @retval 0 if no field found. */ -Item* Item_equal::get_first(Item *field_item) +Item* Item_equal::get_first(JOIN_TAB *context, Item *field_item) { Item_equal_fields_iterator it(*this); Item *item; @@ -5844,7 +5844,11 @@ Item* Item_equal::get_first(Item *field_item) in presense of SJM nests. */ - TABLE_LIST *emb_nest= field->table->pos_in_table_list->embedding; + TABLE_LIST *emb_nest; + if (context != NO_PARTICULAR_TAB) + emb_nest= context->emb_sj_nest; + else + emb_nest= field->table->pos_in_table_list->embedding; if (emb_nest && emb_nest->sj_mat_info && emb_nest->sj_mat_info->is_used) { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 81a18bb594e..ad4f889f4df 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1712,7 +1712,7 @@ public: /** Add a non-constant item to the multiple equality */ void add(Item *f) { equal_items.push_back(f); } bool contains(Field *field); - Item* get_first(Item *field); + Item* get_first(struct st_join_table *context, Item *field); /** Get number of field items / references to field items in this object */ uint n_field_items() { return equal_items.elements-test(with_const); } void merge(Item_equal *item); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index dc13e1ddcab..4058e72c547 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -110,7 +110,8 @@ static COND *build_equal_items(THD *thd, COND *cond, COND_EQUAL *inherited, List *join_list, COND_EQUAL **cond_equal_ref); -static COND* substitute_for_best_equal_field(COND *cond, +static COND* substitute_for_best_equal_field(JOIN_TAB *context_tab, + COND *cond, COND_EQUAL *cond_equal, void *table_join_idx); static COND *simplify_joins(JOIN *join, List *join_list, @@ -1225,7 +1226,8 @@ JOIN::optimize() */ if (conds) { - conds= substitute_for_best_equal_field(conds, cond_equal, map2table); + conds= substitute_for_best_equal_field(NO_PARTICULAR_TAB, conds, + cond_equal, map2table); conds->update_used_tables(); DBUG_EXECUTE("where", print_where(conds, @@ -1242,7 +1244,8 @@ JOIN::optimize() { if (*tab->on_expr_ref) { - *tab->on_expr_ref= substitute_for_best_equal_field(*tab->on_expr_ref, + *tab->on_expr_ref= substitute_for_best_equal_field(NO_PARTICULAR_TAB, + *tab->on_expr_ref, tab->cond_equal, map2table); (*tab->on_expr_ref)->update_used_tables(); @@ -1265,7 +1268,7 @@ JOIN::optimize() continue; COND_EQUAL *equals= tab->first_inner ? tab->first_inner->cond_equal : cond_equal; - ref_item= substitute_for_best_equal_field(ref_item, equals, map2table); + ref_item= substitute_for_best_equal_field(tab, ref_item, equals, map2table); ref_item->update_used_tables(); if (*ref_item_ptr != ref_item) { @@ -11446,7 +11449,7 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, else { TABLE_LIST *emb_nest; - head= item_equal->get_first(NULL); + head= item_equal->get_first(NO_PARTICULAR_TAB, NULL); it++; if ((emb_nest= embedding_sjm(head))) { @@ -11555,6 +11558,7 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, return cond; } + /** Substitute every field reference in a condition by the best equal field and eliminate all multiple equality predicates. @@ -11569,6 +11573,9 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, After this the function retrieves all other conjuncted predicates substitute every field reference by the field reference to the first equal field or equal constant if there are any. + + @param context_tab Join tab that 'cond' will be attached to, or + NO_PARTICULAR_TAB. See notes above. @param cond condition to process @param cond_equal multiple equalities to take into consideration @param table_join_idx index to tables determining field preference @@ -11579,11 +11586,37 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, new fields in multiple equality item of lower levels. We want the order in them to comply with the order of upper levels. + context_tab may be used to specify which join tab `cond` will be + attached to. There are two possible cases: + + 1. context_tab != NO_PARTICULAR_TAB + We're doing substitution for an Item which will be evaluated in the + context of a particular item. For example, if the optimizer does a + ref access on "tbl1.key= expr" then + = equality substitution will be perfomed on 'expr' + = it is known in advance that 'expr' will be evaluated when + table t1 is accessed. + Note that in this kind of substution we never have to replace Item_equal + objects. For example, for + + t.key= func(col1=col2 AND col2=const) + + we will not build Item_equal or do equality substution (if we decide to, + this function will need to be fixed to handle it) + + 2. context_tab == NO_PARTICULAR_TAB + We're doing substitution in WHERE/ON condition, which is not yet + attached to any particular join_tab. We will use information about the + chosen join order to make "optimal" substitions, i.e. those that allow + to apply filtering as soon as possible. See eliminate_item_equal() and + Item_equal::get_first() for details. + @return The transformed condition */ -static COND* substitute_for_best_equal_field(COND *cond, +static COND* substitute_for_best_equal_field(JOIN_TAB *context_tab, + COND *cond, COND_EQUAL *cond_equal, void *table_join_idx) { @@ -11612,7 +11645,8 @@ static COND* substitute_for_best_equal_field(COND *cond, Item *item; while ((item= li++)) { - Item *new_item= substitute_for_best_equal_field(item, cond_equal, + Item *new_item= substitute_for_best_equal_field(context_tab, + item, cond_equal, table_join_idx); /* This works OK with PS/SP re-execution as changes are made to @@ -11659,7 +11693,8 @@ static COND* substitute_for_best_equal_field(COND *cond, List_iterator_fast it(cond_equal->current_level); while((item_equal= it++)) { - cond= cond->transform(&Item::replace_equal_field, (uchar *) item_equal); + REPLACE_EQUAL_FIELD_ARG arg= {item_equal, context_tab}; + cond= cond->transform(&Item::replace_equal_field, (uchar *) &arg); } cond_equal= cond_equal->upper_levels; } From bb4053afc3cb30c6016530884061d520350004f1 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 20 Jan 2012 23:54:43 -0800 Subject: [PATCH 40/83] Fixed LP bug #919427. The function subselect_uniquesubquery_engine::copy_ref_key has to take into account that when EXPLAIN is processed the array of store_key object created for any TABLE_REF may contain elements for constant items. These items should be ignored by thefunction. --- mysql-test/r/subselect.result | 49 +++++++++++++++++++++++++++++++++++ mysql-test/t/subselect.test | 46 ++++++++++++++++++++++++++++++++ sql/item_subselect.cc | 2 ++ sql/sql_select.h | 2 ++ 4 files changed, 99 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 101869e2843..4e12294da79 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5158,6 +5158,7 @@ DROP TABLE t1; # # BUG#12616253 - WRONG RESULT WITH EXISTS(SUBQUERY) (MISSING ROWS) # (duplicate of LP bug #888456) +# CREATE TABLE t1 (f1 varchar(1)); INSERT INTO t1 VALUES ('v'),('s'); CREATE TABLE t2 (f1_key varchar(1), KEY (f1_key)); @@ -5196,4 +5197,52 @@ s d v s s s DROP TABLE t1,t2; +# +# LP bug 919427: EXPLAIN for a query over a single-row table +# with IN subquery in WHERE condition +# +CREATE TABLE ot ( +col_int_nokey int(11), +col_varchar_nokey varchar(1) +) ; +INSERT INTO ot VALUES (1,'x'); +CREATE TABLE it1( +col_int_key int(11), +col_varchar_key varchar(1), +KEY idx_cvk_cik (col_varchar_key,col_int_key) +); +INSERT INTO it1 VALUES (NULL,'x'), (NULL,'f'); +CREATE TABLE it2 ( +col_int_key int(11), +col_varchar_key varchar(1), +col_varchar_key2 varchar(1), +KEY idx_cvk_cvk2_cik (col_varchar_key, col_varchar_key2, col_int_key), +KEY idx_cvk_cik (col_varchar_key, col_int_key) +); +INSERT INTO it2 VALUES (NULL,'x','x'), (NULL,'f','f'); +EXPLAIN +SELECT col_int_nokey FROM ot +WHERE col_varchar_nokey IN +(SELECT col_varchar_key FROM it1 WHERE col_int_key IS NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 DEPENDENT SUBQUERY it1 index_subquery idx_cvk_cik idx_cvk_cik 9 func,const 2 Using index; Using where +SELECT col_int_nokey FROM ot +WHERE col_varchar_nokey IN +(SELECT col_varchar_key FROM it1 WHERE col_int_key IS NULL); +col_int_nokey +1 +EXPLAIN +SELECT col_int_nokey FROM ot +WHERE (col_varchar_nokey, 'x') IN +(SELECT col_varchar_key, col_varchar_key2 FROM it2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 DEPENDENT SUBQUERY it2 index_subquery idx_cvk_cvk2_cik,idx_cvk_cik idx_cvk_cvk2_cik 8 func,const 1 Using index; Using where +SELECT col_int_nokey FROM ot +WHERE (col_varchar_nokey, 'x') IN +(SELECT col_varchar_key, col_varchar_key2 FROM it2); +col_int_nokey +1 +DROP TABLE ot,it1,it2; End of 5.2 tests diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 24aad3a145d..6bb9a9ae875 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4025,6 +4025,7 @@ DROP TABLE t1; --echo # --echo # BUG#12616253 - WRONG RESULT WITH EXISTS(SUBQUERY) (MISSING ROWS) --echo # (duplicate of LP bug #888456) +--echo # CREATE TABLE t1 (f1 varchar(1)); INSERT INTO t1 VALUES ('v'),('s'); @@ -4043,4 +4044,49 @@ SELECT table1.f1, table2.f1_key FROM t1 AS table1, t2 AS table2 DROP TABLE t1,t2; +--echo # +--echo # LP bug 919427: EXPLAIN for a query over a single-row table +--echo # with IN subquery in WHERE condition +--echo # + +CREATE TABLE ot ( + col_int_nokey int(11), + col_varchar_nokey varchar(1) +) ; +INSERT INTO ot VALUES (1,'x'); + +CREATE TABLE it1( + col_int_key int(11), + col_varchar_key varchar(1), + KEY idx_cvk_cik (col_varchar_key,col_int_key) +); +INSERT INTO it1 VALUES (NULL,'x'), (NULL,'f'); + +CREATE TABLE it2 ( + col_int_key int(11), + col_varchar_key varchar(1), + col_varchar_key2 varchar(1), + KEY idx_cvk_cvk2_cik (col_varchar_key, col_varchar_key2, col_int_key), + KEY idx_cvk_cik (col_varchar_key, col_int_key) +); +INSERT INTO it2 VALUES (NULL,'x','x'), (NULL,'f','f'); + +EXPLAIN +SELECT col_int_nokey FROM ot + WHERE col_varchar_nokey IN + (SELECT col_varchar_key FROM it1 WHERE col_int_key IS NULL); +SELECT col_int_nokey FROM ot + WHERE col_varchar_nokey IN + (SELECT col_varchar_key FROM it1 WHERE col_int_key IS NULL); + +EXPLAIN +SELECT col_int_nokey FROM ot + WHERE (col_varchar_nokey, 'x') IN + (SELECT col_varchar_key, col_varchar_key2 FROM it2); +SELECT col_int_nokey FROM ot + WHERE (col_varchar_nokey, 'x') IN + (SELECT col_varchar_key, col_varchar_key2 FROM it2); + +DROP TABLE ot,it1,it2; + --echo End of 5.2 tests diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 2828ae8c4ec..3aa8dcd56f0 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -2171,6 +2171,8 @@ bool subselect_uniquesubquery_engine::copy_ref_key() for (store_key **copy= tab->ref.key_copy ; *copy ; copy++) { + if ((*copy)->store_key_is_const()) + continue; tab->ref.key_err= (*copy)->copy(); /* diff --git a/sql/sql_select.h b/sql/sql_select.h index 1d1a023d9cf..79c07e80b25 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -670,6 +670,7 @@ public: } virtual ~store_key() {} /** Not actually needed */ virtual const char *name() const=0; + virtual bool store_key_is_const() { return false; } /** @brief sets ignore truncation warnings mode and calls the real copy method @@ -784,6 +785,7 @@ public: { } const char *name() const { return "const"; } + bool store_key_is_const() { return true; } protected: enum store_key_result copy_inner() From 80009f586245e6d1a6e4435288a9ae8c93d1c847 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sat, 21 Jan 2012 20:58:23 -0800 Subject: [PATCH 41/83] Back-ported test cases for bugs #53060, #53305, #50358, #49453 from subquery_sj of mysql-5.6 code line. The bugs could not be reproduced in the latest release of mariadb-5.3 as they were fixed either when the code of subquery optimization was back-ported from mysql-6.0 or later when some other bugs were fixed. --- mysql-test/r/join_cache.result | 97 +++++++++++++++++++++++++++ mysql-test/r/subselect_sj.result | 54 +++++++++++++++ mysql-test/r/subselect_sj_jcl6.result | 54 +++++++++++++++ mysql-test/t/join_cache.test | 82 ++++++++++++++++++++++ mysql-test/t/subselect_sj.test | 51 ++++++++++++++ 5 files changed, 338 insertions(+) diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index 362158cfdbe..db869ba434a 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5389,4 +5389,101 @@ x 5 5 4 SET join_cache_level = DEFAULT; SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3,t4; +# +# Bug#53305 Duplicate weedout + join buffer (join cache --level=7,8) +# +create table t1 (uid int, fid int, index(uid)); +insert into t1 values +(1,1), (1,2), (1,3), (1,4), +(2,5), (2,6), (2,7), (2,8), +(3,1), (3,2), (3,9); +create table t2 (uid int primary key, name varchar(128), index(name)); +insert into t2 values +(1, "A"), (2, "B"), (3, "C"), (4, "D"), (5, "E"), +(6, "F"), (7, "G"), (8, "H"), (9, "I"); +create table t3 (uid int, fid int, index(uid)); +insert into t3 values +(1,1), (1,2), (1,3),(1,4), +(2,5), (2,6), (2,7), (2,8), +(3,1), (3,2), (3,9); +set @tmp_optimizer_switch=@@optimizer_switch; +set @@optimizer_switch='semijoin=on'; +set optimizer_switch='materialization=off'; +set optimizer_switch='loosescan=off,firstmatch=off'; +set optimizer_switch='mrr_sort_keys=off'; +set join_cache_level=7; +create table t4 (uid int primary key, name varchar(128), index(name)); +insert into t4 values +(1, "A"), (2, "B"), (3, "C"), (4, "D"), (5, "E"), +(6, "F"), (7, "G"), (8, "H"), (9, "I"); +explain select name from t2, t1 +where t1.uid in (select t4.uid from t4, t3 where t3.uid=1 and t4.uid=t3.fid) +and t2.uid=t1.fid; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ref uid uid 5 const 4 Using where; Start temporary +1 PRIMARY t4 eq_ref PRIMARY PRIMARY 4 test.t3.fid 1 Using index +1 PRIMARY t1 ALL uid NULL NULL NULL 11 Using where; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t1.fid 1 Using join buffer (flat, BKAH join); Rowid-ordered scan +select name from t2, t1 +where t1.uid in (select t4.uid from t4, t3 where t3.uid=1 and t4.uid=t3.fid) +and t2.uid=t1.fid; +name +A +A +B +B +C +D +E +F +G +H +I +set join_cache_level = default; +set optimizer_switch=@tmp_optimizer_switch; +drop table t1,t2,t3,t4; +# +# Bug#50358 - semijoin execution of subquery with outerjoin +# emplying join buffer +# +CREATE TABLE t1 (i int); +CREATE TABLE t2 (i int); +CREATE TABLE t3 (i int); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (6); +INSERT INTO t3 VALUES (1), (2); +set @tmp_optimizer_switch=@@optimizer_switch; +set @@optimizer_switch='semijoin=on'; +set optimizer_switch='materialization=on'; +set join_cache_level=0; +EXPLAIN +SELECT * FROM t1 WHERE t1.i IN +(SELECT t3.i FROM t3 LEFT JOIN t2 ON t2.i=t3.i); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 1 Using where +SELECT * FROM t1 WHERE t1.i IN +(SELECT t3.i FROM t3 LEFT JOIN t2 ON t2.i=t3.i); +i +1 +2 +set join_cache_level=2; +EXPLAIN +SELECT * FROM t1 WHERE t1.i IN +(SELECT t3.i FROM t3 LEFT JOIN t2 ON t2.i=t3.i); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (flat, BNL join) +SELECT * FROM t1 WHERE t1.i IN +(SELECT t3.i FROM t3 LEFT JOIN t2 ON t2.i=t3.i); +i +1 +2 +set join_cache_level = default; +set optimizer_switch=@tmp_optimizer_switch; +DROP TABLE t1,t2,t3; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index f5c3f84bcd7..33468198422 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -1231,6 +1231,60 @@ IN (SELECT t3.pk, t3.pk FROM t2 LEFT JOIN t3 ON t3.varchar_key) AND pk = 9; datetime_key DROP TABLE t1, t2, t3; +# +# BUG#53060: LooseScan semijoin strategy does not return all rows +# +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=on,materialization=off'; +set optimizer_switch='firstmatch=off,loosescan=on'; +CREATE TABLE t1 (i INTEGER); +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +CREATE TABLE t2 (i INTEGER, j INTEGER, KEY k(i, j)); +INSERT INTO t2 VALUES (1, 0), (1, 1), (2, 0), (2, 1); +EXPLAIN +SELECT * FROM t1 WHERE (i) IN (SELECT i FROM t2 where j > 0); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index k k 10 NULL 4 Using where; Using index; LooseScan +1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join) +SELECT * FROM t1 WHERE (i) IN (SELECT i FROM t2 where j > 0); +i +1 +2 +DROP TABLE t1, t2; +set optimizer_switch=@save_optimizer_switch; +# +# BUG#49453: re-execution of prepared statement with view +# and semijoin crashes +# +CREATE TABLE t1 (city VARCHAR(50), country_id INT); +CREATE TABLE t2 (country_id INT, country VARCHAR(50)); +INSERT INTO t1 VALUES +('Batna',2),('Bchar',2),('Skikda',2),('Tafuna',3),('Algeria',2) ; +INSERT INTO t2 VALUES (2,'Algeria'),(2,'AlgeriaDup'),(3,'XAmerican Samoa'); +CREATE VIEW v1 AS +SELECT country_id as vf_country_id +FROM t2 +WHERE LEFT(country,1) = "A"; +PREPARE stmt FROM " +SELECT city, country_id +FROM t1 +WHERE country_id IN (SELECT vf_country_id FROM v1); +"; + +EXECUTE stmt; +city country_id +Batna 2 +Bchar 2 +Skikda 2 +Algeria 2 +EXECUTE stmt; +city country_id +Batna 2 +Bchar 2 +Skikda 2 +Algeria 2 +DROP TABLE t1,t2; +DROP VIEW v1; # # BUG#784723: Wrong result with semijoin + nested subqueries in maria-5.3 # diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index faa4140d375..c344271ceae 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -1244,6 +1244,60 @@ IN (SELECT t3.pk, t3.pk FROM t2 LEFT JOIN t3 ON t3.varchar_key) AND pk = 9; datetime_key DROP TABLE t1, t2, t3; +# +# BUG#53060: LooseScan semijoin strategy does not return all rows +# +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=on,materialization=off'; +set optimizer_switch='firstmatch=off,loosescan=on'; +CREATE TABLE t1 (i INTEGER); +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +CREATE TABLE t2 (i INTEGER, j INTEGER, KEY k(i, j)); +INSERT INTO t2 VALUES (1, 0), (1, 1), (2, 0), (2, 1); +EXPLAIN +SELECT * FROM t1 WHERE (i) IN (SELECT i FROM t2 where j > 0); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index k k 10 NULL 4 Using where; Using index; LooseScan +1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where; Using join buffer (flat, BNL join) +SELECT * FROM t1 WHERE (i) IN (SELECT i FROM t2 where j > 0); +i +1 +2 +DROP TABLE t1, t2; +set optimizer_switch=@save_optimizer_switch; +# +# BUG#49453: re-execution of prepared statement with view +# and semijoin crashes +# +CREATE TABLE t1 (city VARCHAR(50), country_id INT); +CREATE TABLE t2 (country_id INT, country VARCHAR(50)); +INSERT INTO t1 VALUES +('Batna',2),('Bchar',2),('Skikda',2),('Tafuna',3),('Algeria',2) ; +INSERT INTO t2 VALUES (2,'Algeria'),(2,'AlgeriaDup'),(3,'XAmerican Samoa'); +CREATE VIEW v1 AS +SELECT country_id as vf_country_id +FROM t2 +WHERE LEFT(country,1) = "A"; +PREPARE stmt FROM " +SELECT city, country_id +FROM t1 +WHERE country_id IN (SELECT vf_country_id FROM v1); +"; + +EXECUTE stmt; +city country_id +Batna 2 +Bchar 2 +Skikda 2 +Algeria 2 +EXECUTE stmt; +city country_id +Batna 2 +Bchar 2 +Skikda 2 +Algeria 2 +DROP TABLE t1,t2; +DROP VIEW v1; # # BUG#784723: Wrong result with semijoin + nested subqueries in maria-5.3 # diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index e39dcb72916..cc1941e16b9 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -3423,5 +3423,87 @@ SET optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3,t4; +--echo # +--echo # Bug#53305 Duplicate weedout + join buffer (join cache --level=7,8) +--echo # + +create table t1 (uid int, fid int, index(uid)); +insert into t1 values + (1,1), (1,2), (1,3), (1,4), + (2,5), (2,6), (2,7), (2,8), + (3,1), (3,2), (3,9); + +create table t2 (uid int primary key, name varchar(128), index(name)); +insert into t2 values + (1, "A"), (2, "B"), (3, "C"), (4, "D"), (5, "E"), + (6, "F"), (7, "G"), (8, "H"), (9, "I"); + +create table t3 (uid int, fid int, index(uid)); +insert into t3 values + (1,1), (1,2), (1,3),(1,4), + (2,5), (2,6), (2,7), (2,8), + (3,1), (3,2), (3,9); + +set @tmp_optimizer_switch=@@optimizer_switch; +set @@optimizer_switch='semijoin=on'; +set optimizer_switch='materialization=off'; +set optimizer_switch='loosescan=off,firstmatch=off'; +set optimizer_switch='mrr_sort_keys=off'; +set join_cache_level=7; + +create table t4 (uid int primary key, name varchar(128), index(name)); +insert into t4 values + (1, "A"), (2, "B"), (3, "C"), (4, "D"), (5, "E"), + (6, "F"), (7, "G"), (8, "H"), (9, "I"); + +explain select name from t2, t1 + where t1.uid in (select t4.uid from t4, t3 where t3.uid=1 and t4.uid=t3.fid) + and t2.uid=t1.fid; + +--sorted_result +select name from t2, t1 + where t1.uid in (select t4.uid from t4, t3 where t3.uid=1 and t4.uid=t3.fid) + and t2.uid=t1.fid; + +set join_cache_level = default; +set optimizer_switch=@tmp_optimizer_switch; + +drop table t1,t2,t3,t4; + +--echo # +--echo # Bug#50358 - semijoin execution of subquery with outerjoin +--echo # emplying join buffer +--echo # + +CREATE TABLE t1 (i int); +CREATE TABLE t2 (i int); +CREATE TABLE t3 (i int); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (6); +INSERT INTO t3 VALUES (1), (2); + +set @tmp_optimizer_switch=@@optimizer_switch; +set @@optimizer_switch='semijoin=on'; +set optimizer_switch='materialization=on'; + +set join_cache_level=0; +EXPLAIN +SELECT * FROM t1 WHERE t1.i IN + (SELECT t3.i FROM t3 LEFT JOIN t2 ON t2.i=t3.i); +SELECT * FROM t1 WHERE t1.i IN + (SELECT t3.i FROM t3 LEFT JOIN t2 ON t2.i=t3.i); + +set join_cache_level=2; +EXPLAIN +SELECT * FROM t1 WHERE t1.i IN + (SELECT t3.i FROM t3 LEFT JOIN t2 ON t2.i=t3.i); +SELECT * FROM t1 WHERE t1.i IN + (SELECT t3.i FROM t3 LEFT JOIN t2 ON t2.i=t3.i); + +set join_cache_level = default; +set optimizer_switch=@tmp_optimizer_switch; + +DROP TABLE t1,t2,t3; + # this must be the last command in the file set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/subselect_sj.test b/mysql-test/t/subselect_sj.test index f34cf5ba338..64e7bc3236e 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -1136,6 +1136,57 @@ WHERE (int_nokey, pk) DROP TABLE t1, t2, t3; +--echo # +--echo # BUG#53060: LooseScan semijoin strategy does not return all rows +--echo # + +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=on,materialization=off'; +set optimizer_switch='firstmatch=off,loosescan=on'; + +CREATE TABLE t1 (i INTEGER); +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +CREATE TABLE t2 (i INTEGER, j INTEGER, KEY k(i, j)); +INSERT INTO t2 VALUES (1, 0), (1, 1), (2, 0), (2, 1); + +EXPLAIN +SELECT * FROM t1 WHERE (i) IN (SELECT i FROM t2 where j > 0); +SELECT * FROM t1 WHERE (i) IN (SELECT i FROM t2 where j > 0); + +DROP TABLE t1, t2; + +set optimizer_switch=@save_optimizer_switch; + +--echo # +--echo # BUG#49453: re-execution of prepared statement with view +--echo # and semijoin crashes +--echo # + +CREATE TABLE t1 (city VARCHAR(50), country_id INT); +CREATE TABLE t2 (country_id INT, country VARCHAR(50)); + +INSERT INTO t1 VALUES + ('Batna',2),('Bchar',2),('Skikda',2),('Tafuna',3),('Algeria',2) ; +INSERT INTO t2 VALUES (2,'Algeria'),(2,'AlgeriaDup'),(3,'XAmerican Samoa'); + +CREATE VIEW v1 AS + SELECT country_id as vf_country_id + FROM t2 + WHERE LEFT(country,1) = "A"; + +PREPARE stmt FROM " +SELECT city, country_id +FROM t1 +WHERE country_id IN (SELECT vf_country_id FROM v1); +"; + +--echo +EXECUTE stmt; +EXECUTE stmt; + +DROP TABLE t1,t2; +DROP VIEW v1; + --echo # --echo # BUG#784723: Wrong result with semijoin + nested subqueries in maria-5.3 --echo # From 7bdbdb05cebaf722e44b415631717ed78933e906 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sun, 22 Jan 2012 12:54:30 -0800 Subject: [PATCH 42/83] Back-ported test cases for bugs #54437, #55955, #52329, #57623 from subquery_sj of mysql-5.6 code line. The bugs could not be reproduced in the latest release of mariadb-5.3 as they were fixed either when the code of subquery optimization was back-ported from mysql-6.0 or later when some other bugs were fixed. --- mysql-test/r/subselect_sj.result | 252 ++++++++++++++++++++++++++ mysql-test/r/subselect_sj_jcl6.result | 252 ++++++++++++++++++++++++++ mysql-test/t/subselect_sj.test | 166 +++++++++++++++++ 3 files changed, 670 insertions(+) diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index 33468198422..0c9c2eb3af5 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -1286,6 +1286,258 @@ Algeria 2 DROP TABLE t1,t2; DROP VIEW v1; # +# Bug#54437 Extra rows with LEFT JOIN + semijoin +# +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +insert into t1 values(1),(1); +insert into t2 values(1),(1),(1),(1); +insert into t3 values(2),(2); +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='materialization=off'; +set optimizer_switch='semijoin=off'; +explain +select * from t1 where t1.a in (select t2.a from t2 left join t3 on t2.a=t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 4 Using where +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where +select * from t1 where t1.a in (select t2.a from t2 left join t3 on t2.a=t3.a); +a +1 +1 +set optimizer_switch='semijoin=on'; +explain +select * from t1 where t1.a in (select t2.a from t2 left join t3 on t2.a=t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 +1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; Start temporary +1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where; End temporary +select * from t1 where t1.a in (select t2.a from t2 left join t3 on t2.a=t3.a); +a +1 +1 +set optimizer_switch=@save_optimizer_switch; +drop table t1,t2,t3; +# +# Bug#55955: crash in MEMORY engine with IN(LEFT JOIN (JOIN)) +# +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +CREATE TABLE t3 (a INT); +INSERT INTO t1 VALUES(1),(1); +INSERT INTO t2 VALUES(1),(1); +INSERT INTO t3 VALUES(2),(2); +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=off,materialization=off'; +EXPLAIN +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a +FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t2inner ALL NULL NULL NULL NULL 2 +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a +FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +a +1 +1 +set optimizer_switch='semijoin=off,materialization=on'; +EXPLAIN +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a +FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2inner ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 Using where +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a +FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +a +1 +1 +set optimizer_switch='semijoin=on,materialization=off'; +EXPLAIN +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a +FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Start temporary +1 PRIMARY t2inner ALL NULL NULL NULL NULL 2 +1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where; End temporary +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a +FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +a +1 +1 +set optimizer_switch=@save_optimizer_switch; +DROP TABLE t1,t2,t3; +# +# BUG#52329 - Wrong result: subquery materialization, IN, +# non-null field followed by nullable +# +CREATE TABLE t1 (a1 CHAR(8) NOT NULL, a2 char(8) NOT NULL); +CREATE TABLE t2a (b1 char(8), b2 char(8)); +CREATE TABLE t2b (b1 CHAR(8), b2 char(8) NOT NULL); +CREATE TABLE t2c (b1 CHAR(8) NOT NULL, b2 char(8)); +INSERT INTO t1 VALUES ('1 - 12', '2 - 22'); +INSERT INTO t2a VALUES ('1 - 11', '2 - 21'), +('1 - 11', '2 - 21'), +('1 - 12', '2 - 22'), +('1 - 12', '2 - 22'), +('1 - 13', '2 - 23'); +INSERT INTO t2b SELECT * FROM t2a; +INSERT INTO t2c SELECT * FROM t2a; +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=off,materialization=on'; +SELECT * FROM t1 +WHERE (a1, a2) IN ( +SELECT b1, b2 FROM t2c WHERE b1 > '0' GROUP BY b1, b2); +a1 a2 +1 - 12 2 - 22 +SELECT * FROM t1 +WHERE (a1, a2) IN ( +SELECT b1, b2 FROM t2a WHERE b1 > '0'); +a1 a2 +1 - 12 2 - 22 +SELECT * FROM t1 +WHERE (a1, a2) IN ( +SELECT b1, b2 FROM t2b WHERE b1 > '0'); +a1 a2 +1 - 12 2 - 22 +SELECT * FROM t1 +WHERE (a1, a2) IN ( +SELECT b1, b2 FROM t2c WHERE b1 > '0'); +a1 a2 +1 - 12 2 - 22 +set optimizer_switch=@save_optimizer_switch; +DROP TABLE t1,t2a,t2b,t2c; +# +# Bug#57623: subquery within before insert trigger causes crash (sj=on) +# +CREATE TABLE ot1(a INT); +CREATE TABLE ot2(a INT); +CREATE TABLE ot3(a INT); +CREATE TABLE it1(a INT); +INSERT INTO ot1 VALUES(0),(1),(2),(3),(4),(5),(6),(7); +INSERT INTO ot2 VALUES(0),(2),(4),(6); +INSERT INTO ot3 VALUES(0),(3),(6); +INSERT INTO it1 VALUES(0),(1),(2),(3),(4),(5),(6),(7); +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=on'; +set optimizer_switch='materialization=off'; +explain SELECT * +FROM ot1 +LEFT JOIN +(ot2 JOIN ot3 on ot2.a=ot3.a) +ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ot1 ALL NULL NULL NULL NULL 8 +1 PRIMARY ot3 ALL NULL NULL NULL NULL 3 Using where +1 PRIMARY ot2 ALL NULL NULL NULL NULL 4 Using where +2 DEPENDENT SUBQUERY it1 ALL NULL NULL NULL NULL 8 Using where +SELECT * +FROM ot1 +LEFT JOIN +(ot2 JOIN ot3 on ot2.a=ot3.a) +ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1); +a a a +0 0 0 +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +6 6 6 +7 NULL NULL +prepare s from 'SELECT * +FROM ot1 +LEFT JOIN +(ot2 JOIN ot3 on ot2.a=ot3.a) +ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1)'; +execute s; +a a a +0 0 0 +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +6 6 6 +7 NULL NULL +execute s; +a a a +0 0 0 +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +6 6 6 +7 NULL NULL +deallocate prepare s; +set optimizer_switch='materialization=on'; +explain SELECT * +FROM ot1 +LEFT JOIN +(ot2 JOIN ot3 on ot2.a=ot3.a) +ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ot1 ALL NULL NULL NULL NULL 8 +1 PRIMARY ot3 ALL NULL NULL NULL NULL 3 Using where +1 PRIMARY ot2 ALL NULL NULL NULL NULL 4 Using where +2 MATERIALIZED it1 ALL NULL NULL NULL NULL 8 +SELECT * +FROM ot1 +LEFT JOIN +(ot2 JOIN ot3 on ot2.a=ot3.a) +ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1); +a a a +0 0 0 +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +6 6 6 +7 NULL NULL +prepare s from 'SELECT * +FROM ot1 +LEFT JOIN +(ot2 JOIN ot3 on ot2.a=ot3.a) +ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1)'; +execute s; +a a a +0 0 0 +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +6 6 6 +7 NULL NULL +execute s; +a a a +0 0 0 +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +6 6 6 +7 NULL NULL +deallocate prepare s; +set optimizer_switch=@save_optimizer_switch; +DROP TABLE ot1, ot2, ot3, it1; +# # BUG#784723: Wrong result with semijoin + nested subqueries in maria-5.3 # CREATE TABLE t1 ( t1field integer, primary key (t1field)); diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index c344271ceae..a8bc0d120cd 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -1299,6 +1299,258 @@ Algeria 2 DROP TABLE t1,t2; DROP VIEW v1; # +# Bug#54437 Extra rows with LEFT JOIN + semijoin +# +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +insert into t1 values(1),(1); +insert into t2 values(1),(1),(1),(1); +insert into t3 values(2),(2); +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='materialization=off'; +set optimizer_switch='semijoin=off'; +explain +select * from t1 where t1.a in (select t2.a from t2 left join t3 on t2.a=t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 4 Using where +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) +select * from t1 where t1.a in (select t2.a from t2 left join t3 on t2.a=t3.a); +a +1 +1 +set optimizer_switch='semijoin=on'; +explain +select * from t1 where t1.a in (select t2.a from t2 left join t3 on t2.a=t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 +1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; Start temporary; Using join buffer (flat, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (incremental, BNL join) +select * from t1 where t1.a in (select t2.a from t2 left join t3 on t2.a=t3.a); +a +1 +1 +set optimizer_switch=@save_optimizer_switch; +drop table t1,t2,t3; +# +# Bug#55955: crash in MEMORY engine with IN(LEFT JOIN (JOIN)) +# +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +CREATE TABLE t3 (a INT); +INSERT INTO t1 VALUES(1),(1); +INSERT INTO t2 VALUES(1),(1); +INSERT INTO t3 VALUES(2),(2); +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=off,materialization=off'; +EXPLAIN +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a +FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t2inner ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join) +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (incremental, BNL join) +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a +FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +a +1 +1 +set optimizer_switch='semijoin=off,materialization=on'; +EXPLAIN +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a +FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 +2 MATERIALIZED t2inner ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join) +2 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (incremental, BNL join) +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a +FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +a +1 +1 +set optimizer_switch='semijoin=on,materialization=off'; +EXPLAIN +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a +FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Start temporary; Using join buffer (flat, BNL join) +1 PRIMARY t2inner ALL NULL NULL NULL NULL 2 Using join buffer (incremental, BNL join) +1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where; End temporary; Using join buffer (incremental, BNL join) +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a +FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +a +1 +1 +set optimizer_switch=@save_optimizer_switch; +DROP TABLE t1,t2,t3; +# +# BUG#52329 - Wrong result: subquery materialization, IN, +# non-null field followed by nullable +# +CREATE TABLE t1 (a1 CHAR(8) NOT NULL, a2 char(8) NOT NULL); +CREATE TABLE t2a (b1 char(8), b2 char(8)); +CREATE TABLE t2b (b1 CHAR(8), b2 char(8) NOT NULL); +CREATE TABLE t2c (b1 CHAR(8) NOT NULL, b2 char(8)); +INSERT INTO t1 VALUES ('1 - 12', '2 - 22'); +INSERT INTO t2a VALUES ('1 - 11', '2 - 21'), +('1 - 11', '2 - 21'), +('1 - 12', '2 - 22'), +('1 - 12', '2 - 22'), +('1 - 13', '2 - 23'); +INSERT INTO t2b SELECT * FROM t2a; +INSERT INTO t2c SELECT * FROM t2a; +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=off,materialization=on'; +SELECT * FROM t1 +WHERE (a1, a2) IN ( +SELECT b1, b2 FROM t2c WHERE b1 > '0' GROUP BY b1, b2); +a1 a2 +1 - 12 2 - 22 +SELECT * FROM t1 +WHERE (a1, a2) IN ( +SELECT b1, b2 FROM t2a WHERE b1 > '0'); +a1 a2 +1 - 12 2 - 22 +SELECT * FROM t1 +WHERE (a1, a2) IN ( +SELECT b1, b2 FROM t2b WHERE b1 > '0'); +a1 a2 +1 - 12 2 - 22 +SELECT * FROM t1 +WHERE (a1, a2) IN ( +SELECT b1, b2 FROM t2c WHERE b1 > '0'); +a1 a2 +1 - 12 2 - 22 +set optimizer_switch=@save_optimizer_switch; +DROP TABLE t1,t2a,t2b,t2c; +# +# Bug#57623: subquery within before insert trigger causes crash (sj=on) +# +CREATE TABLE ot1(a INT); +CREATE TABLE ot2(a INT); +CREATE TABLE ot3(a INT); +CREATE TABLE it1(a INT); +INSERT INTO ot1 VALUES(0),(1),(2),(3),(4),(5),(6),(7); +INSERT INTO ot2 VALUES(0),(2),(4),(6); +INSERT INTO ot3 VALUES(0),(3),(6); +INSERT INTO it1 VALUES(0),(1),(2),(3),(4),(5),(6),(7); +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=on'; +set optimizer_switch='materialization=off'; +explain SELECT * +FROM ot1 +LEFT JOIN +(ot2 JOIN ot3 on ot2.a=ot3.a) +ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ot1 ALL NULL NULL NULL NULL 8 +1 PRIMARY ot3 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) +1 PRIMARY ot2 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (incremental, BNL join) +2 DEPENDENT SUBQUERY it1 ALL NULL NULL NULL NULL 8 Using where +SELECT * +FROM ot1 +LEFT JOIN +(ot2 JOIN ot3 on ot2.a=ot3.a) +ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1); +a a a +0 0 0 +6 6 6 +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +7 NULL NULL +prepare s from 'SELECT * +FROM ot1 +LEFT JOIN +(ot2 JOIN ot3 on ot2.a=ot3.a) +ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1)'; +execute s; +a a a +0 0 0 +6 6 6 +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +7 NULL NULL +execute s; +a a a +0 0 0 +6 6 6 +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +7 NULL NULL +deallocate prepare s; +set optimizer_switch='materialization=on'; +explain SELECT * +FROM ot1 +LEFT JOIN +(ot2 JOIN ot3 on ot2.a=ot3.a) +ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ot1 ALL NULL NULL NULL NULL 8 +1 PRIMARY ot3 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) +1 PRIMARY ot2 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (incremental, BNL join) +2 MATERIALIZED it1 ALL NULL NULL NULL NULL 8 +SELECT * +FROM ot1 +LEFT JOIN +(ot2 JOIN ot3 on ot2.a=ot3.a) +ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1); +a a a +0 0 0 +6 6 6 +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +7 NULL NULL +prepare s from 'SELECT * +FROM ot1 +LEFT JOIN +(ot2 JOIN ot3 on ot2.a=ot3.a) +ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1)'; +execute s; +a a a +0 0 0 +6 6 6 +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +7 NULL NULL +execute s; +a a a +0 0 0 +6 6 6 +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +7 NULL NULL +deallocate prepare s; +set optimizer_switch=@save_optimizer_switch; +DROP TABLE ot1, ot2, ot3, it1; +# # BUG#784723: Wrong result with semijoin + nested subqueries in maria-5.3 # CREATE TABLE t1 ( t1field integer, primary key (t1field)); diff --git a/mysql-test/t/subselect_sj.test b/mysql-test/t/subselect_sj.test index 64e7bc3236e..62d2fd61721 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -1187,6 +1187,172 @@ EXECUTE stmt; DROP TABLE t1,t2; DROP VIEW v1; +--echo # +--echo # Bug#54437 Extra rows with LEFT JOIN + semijoin +--echo # + +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +insert into t1 values(1),(1); +insert into t2 values(1),(1),(1),(1); +insert into t3 values(2),(2); + +set @save_optimizer_switch=@@optimizer_switch; + +set optimizer_switch='materialization=off'; + +set optimizer_switch='semijoin=off'; +explain +select * from t1 where t1.a in (select t2.a from t2 left join t3 on t2.a=t3.a); +select * from t1 where t1.a in (select t2.a from t2 left join t3 on t2.a=t3.a); + +set optimizer_switch='semijoin=on'; +explain +select * from t1 where t1.a in (select t2.a from t2 left join t3 on t2.a=t3.a); +select * from t1 where t1.a in (select t2.a from t2 left join t3 on t2.a=t3.a); + +set optimizer_switch=@save_optimizer_switch; + +drop table t1,t2,t3; + +--echo # +--echo # Bug#55955: crash in MEMORY engine with IN(LEFT JOIN (JOIN)) +--echo # + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +CREATE TABLE t3 (a INT); +INSERT INTO t1 VALUES(1),(1); +INSERT INTO t2 VALUES(1),(1); +INSERT INTO t3 VALUES(2),(2); + +set @save_optimizer_switch=@@optimizer_switch; + +set optimizer_switch='semijoin=off,materialization=off'; +EXPLAIN +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a + FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a + FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); + +set optimizer_switch='semijoin=off,materialization=on'; +EXPLAIN +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a + FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a + FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); + +set optimizer_switch='semijoin=on,materialization=off'; +EXPLAIN +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a + FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); +SELECT * FROM t1 +WHERE t1.a IN (SELECT t2.a + FROM t2 LEFT JOIN (t2 AS t2inner, t3) ON t2.a=t3.a); + +set optimizer_switch=@save_optimizer_switch; + +DROP TABLE t1,t2,t3; + +--echo # +--echo # BUG#52329 - Wrong result: subquery materialization, IN, +--echo # non-null field followed by nullable +--echo # + +CREATE TABLE t1 (a1 CHAR(8) NOT NULL, a2 char(8) NOT NULL); + +CREATE TABLE t2a (b1 char(8), b2 char(8)); +CREATE TABLE t2b (b1 CHAR(8), b2 char(8) NOT NULL); +CREATE TABLE t2c (b1 CHAR(8) NOT NULL, b2 char(8)); + +INSERT INTO t1 VALUES ('1 - 12', '2 - 22'); + +INSERT INTO t2a VALUES ('1 - 11', '2 - 21'), + ('1 - 11', '2 - 21'), + ('1 - 12', '2 - 22'), + ('1 - 12', '2 - 22'), + ('1 - 13', '2 - 23'); + +INSERT INTO t2b SELECT * FROM t2a; +INSERT INTO t2c SELECT * FROM t2a; + +set @save_optimizer_switch=@@optimizer_switch; + +set optimizer_switch='semijoin=off,materialization=on'; + +SELECT * FROM t1 +WHERE (a1, a2) IN ( + SELECT b1, b2 FROM t2c WHERE b1 > '0' GROUP BY b1, b2); + +SELECT * FROM t1 +WHERE (a1, a2) IN ( + SELECT b1, b2 FROM t2a WHERE b1 > '0'); + + +SELECT * FROM t1 +WHERE (a1, a2) IN ( + SELECT b1, b2 FROM t2b WHERE b1 > '0'); + + +SELECT * FROM t1 +WHERE (a1, a2) IN ( + SELECT b1, b2 FROM t2c WHERE b1 > '0'); + +set optimizer_switch=@save_optimizer_switch; + +DROP TABLE t1,t2a,t2b,t2c; + +--echo # +--echo # Bug#57623: subquery within before insert trigger causes crash (sj=on) +--echo # + +CREATE TABLE ot1(a INT); +CREATE TABLE ot2(a INT); +CREATE TABLE ot3(a INT); +CREATE TABLE it1(a INT); + +INSERT INTO ot1 VALUES(0),(1),(2),(3),(4),(5),(6),(7); +INSERT INTO ot2 VALUES(0),(2),(4),(6); +INSERT INTO ot3 VALUES(0),(3),(6); +INSERT INTO it1 VALUES(0),(1),(2),(3),(4),(5),(6),(7); + +let $query= +SELECT * +FROM ot1 + LEFT JOIN + (ot2 JOIN ot3 on ot2.a=ot3.a) + ON ot1.a=ot2.a AND ot1.a IN (SELECT a from it1); + +set @save_optimizer_switch=@@optimizer_switch; + +set optimizer_switch='semijoin=on'; + +set optimizer_switch='materialization=off'; +eval explain $query; +eval $query; +eval prepare s from '$query'; +execute s; +execute s; +deallocate prepare s; + +set optimizer_switch='materialization=on'; +eval explain $query; +eval $query; +eval prepare s from '$query'; +execute s; +execute s; +deallocate prepare s; + +set optimizer_switch=@save_optimizer_switch; + +DROP TABLE ot1, ot2, ot3, it1; + --echo # --echo # BUG#784723: Wrong result with semijoin + nested subqueries in maria-5.3 --echo # From 81690cf326e09799ca77d9f7bc5601905b706548 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 23 Jan 2012 11:43:28 +0100 Subject: [PATCH 43/83] MDEV-106 my_gethwaddr() does not compile on Solaris 11 --- mysys/my_gethwaddr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mysys/my_gethwaddr.c b/mysys/my_gethwaddr.c index c96af3f1018..c4ab39dbcf1 100644 --- a/mysys/my_gethwaddr.c +++ b/mysys/my_gethwaddr.c @@ -101,14 +101,14 @@ my_bool my_gethwaddr(uchar *to) uint i; for (i= 0; res && i < ifc.ifc_len / sizeof(ifr[0]); i++) { -#ifdef SIOCGIFHWADDR +#ifdef __linux__ if (ioctl(fd, SIOCGIFHWADDR, &ifr[i]) >= 0) res= memcpy_and_test(to, (uchar *)&ifr[i].ifr_hwaddr.sa_data, ETHER_ADDR_LEN); #else /* - A bug in OpenSolaris prevents non-root from getting a mac address: - http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=4720634 + A bug in OpenSolaris used to prevent non-root from getting a mac address: + {no url. Oracle killed the old OpenSolaris bug database} Thus, we'll use an alternative method and extract the address from the arp table. From 5db8b5113b26e4c2c7960ab4d6240fd56ffa3432 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 23 Jan 2012 15:14:13 +0200 Subject: [PATCH 44/83] Fixed creating limit for exists subquery. --- sql/item_subselect.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index ed556f05466..d66dbd12436 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1259,7 +1259,8 @@ void Item_exists_subselect::fix_length_and_dec() We need only 1 row to determine existence (i.e. any EXISTS that is not an IN always requires LIMIT 1) */ - unit->global_parameters->select_limit= new Item_int((int32) 1); + thd->change_item_tree(&unit->global_parameters->select_limit, + new Item_int((int32) 1)); DBUG_PRINT("info", ("Set limit to 1")); DBUG_VOID_RETURN; } From 2ae3fca46536245fd2d7f33f317a9fb3a3097620 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 23 Jan 2012 23:35:52 +0400 Subject: [PATCH 45/83] Add MRR counters: Handler_mrr_init, Handler_mrr_extra_rowid_sorts, Handler_mrr_extra_key_sorts. --- mysql-test/r/myisam_mrr.result | 77 ++++++++++++++++++++++++++++++++++ mysql-test/t/myisam_mrr.test | 52 +++++++++++++++++++++++ sql/multi_range_read.cc | 23 +++++++++- sql/mysqld.cc | 3 ++ sql/sql_class.h | 2 + 5 files changed, 155 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/myisam_mrr.result b/mysql-test/r/myisam_mrr.result index 4e1e4f01c07..0eeb22d829a 100644 --- a/mysql-test/r/myisam_mrr.result +++ b/mysql-test/r/myisam_mrr.result @@ -557,4 +557,81 @@ COUNT(alias2.f2) set @@join_cache_level= @tmp_730133_jcl; set @@optimizer_switch= @tmp_730133_os; drop table t1; +# +# Test of MRR handler counters +# +flush status; +show status like 'Handler_mrr%'; +Variable_name Value +Handler_mrr_extra_key_sorts 0 +Handler_mrr_extra_rowid_sorts 0 +Handler_mrr_init 0 +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (a int, b int, filler char(200), key(a)); +insert into t1 +select A.a+10*B.a+100*C.a+1000*D.a, 123,'filler' from t0 A, t0 B, t0 C, t0 D; +explain select sum(b) from t1 where a < 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 8 Using index condition; Rowid-ordered scan +# This should show one MRR scan and no re-fills: +flush status; +select sum(b) from t1 where a < 10; +sum(b) +1230 +show status like 'handler_mrr%'; +Variable_name Value +Handler_mrr_extra_key_sorts 0 +Handler_mrr_extra_rowid_sorts 0 +Handler_mrr_init 1 +set @mrr_buffer_size_save= @@mrr_buffer_size; +set mrr_buffer_size=128; +explain select sum(b) from t1 where a < 1600; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1380 Using index condition; Rowid-ordered scan +# This should show one MRR scan and one extra rowid sort: +flush status; +select sum(b) from t1 where a < 1600; +sum(b) +196800 +show status like 'handler_mrr%'; +Variable_name Value +Handler_mrr_extra_key_sorts 0 +Handler_mrr_extra_rowid_sorts 1 +Handler_mrr_init 1 +set @@mrr_buffer_size= @mrr_buffer_size_save; +#Now, let's check BKA: +set @join_cache_level_save= @@join_cache_level; +set @join_buffer_size_save= @@join_buffer_size; +set join_cache_level=6; +explain select sum(t1.b) from t0,t1 where t0.a=t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where +1 SIMPLE t1 ref a a 5 test.t0.a 1 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +flush status; +select sum(t1.b) from t0,t1 where t0.a=t1.a; +sum(t1.b) +1230 +show status like 'handler_mrr%'; +Variable_name Value +Handler_mrr_extra_key_sorts 0 +Handler_mrr_extra_rowid_sorts 0 +Handler_mrr_init 1 +set join_buffer_size=10; +explain select sum(t1.b) from t0,t1 where t0.a=t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where +1 SIMPLE t1 ref a a 5 test.t0.a 1 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +flush status; +select sum(t1.b) from t0,t1 where t0.a=t1.a; +sum(t1.b) +1230 +show status like 'handler_mrr%'; +Variable_name Value +Handler_mrr_extra_key_sorts 1 +Handler_mrr_extra_rowid_sorts 1 +Handler_mrr_init 2 +set join_cache_level= @join_cache_level_save; +set join_buffer_size= @join_buffer_size_save; +drop table t0, t1; set optimizer_switch= @myisam_mrr_tmp; diff --git a/mysql-test/t/myisam_mrr.test b/mysql-test/t/myisam_mrr.test index 1e070ec9a34..0f916299ae7 100644 --- a/mysql-test/t/myisam_mrr.test +++ b/mysql-test/t/myisam_mrr.test @@ -268,5 +268,57 @@ set @@join_cache_level= @tmp_730133_jcl; set @@optimizer_switch= @tmp_730133_os; drop table t1; +--echo # +--echo # Test of MRR handler counters +--echo # +flush status; +show status like 'Handler_mrr%'; +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (a int, b int, filler char(200), key(a)); +insert into t1 +select A.a+10*B.a+100*C.a+1000*D.a, 123,'filler' from t0 A, t0 B, t0 C, t0 D; + +explain select sum(b) from t1 where a < 10; +--echo # This should show one MRR scan and no re-fills: +flush status; +select sum(b) from t1 where a < 10; +show status like 'handler_mrr%'; + +set @mrr_buffer_size_save= @@mrr_buffer_size; +--disable_warnings +set mrr_buffer_size=128; +--enable_warnings + +explain select sum(b) from t1 where a < 1600; +--echo # This should show one MRR scan and one extra rowid sort: +flush status; +select sum(b) from t1 where a < 1600; +show status like 'handler_mrr%'; +set @@mrr_buffer_size= @mrr_buffer_size_save; + +--echo #Now, let's check BKA: +set @join_cache_level_save= @@join_cache_level; +set @join_buffer_size_save= @@join_buffer_size; +set join_cache_level=6; + +explain select sum(t1.b) from t0,t1 where t0.a=t1.a; +flush status; +select sum(t1.b) from t0,t1 where t0.a=t1.a; +show status like 'handler_mrr%'; + +--disable_warnings +set join_buffer_size=10; +--enable_warnings +explain select sum(t1.b) from t0,t1 where t0.a=t1.a; +flush status; +select sum(t1.b) from t0,t1 where t0.a=t1.a; +show status like 'handler_mrr%'; + +set join_cache_level= @join_cache_level_save; +set join_buffer_size= @join_buffer_size_save; + +drop table t0, t1; + ## This must be last line in the file: set optimizer_switch= @myisam_mrr_tmp; diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index 055a9268417..6ecc64207de 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -466,6 +466,10 @@ void Mrr_ordered_index_reader::resume_read() /** Fill the buffer with (lookup_tuple, range_id) pairs and sort + + @return + 0 OK, the buffer is non-empty and sorted + HA_ERR_END_OF_FILE Source exhausted, the buffer is empty. */ int Mrr_ordered_index_reader::refill_buffer(bool initial) @@ -502,6 +506,13 @@ int Mrr_ordered_index_reader::refill_buffer(bool initial) if (source_exhausted && key_buffer->is_empty()) DBUG_RETURN(HA_ERR_END_OF_FILE); + if (!initial) + { + /* This is a non-initial buffer fill and we've got a non-empty buffer */ + THD *thd= current_thd; + status_var_increment(thd->status_var.ha_mrr_extra_key_sorts); + } + key_buffer->sort((key_buffer->type() == Lifo_buffer::FORWARD)? (qsort2_cmp)Mrr_ordered_index_reader::compare_keys_reverse : (qsort2_cmp)Mrr_ordered_index_reader::compare_keys, @@ -576,6 +587,7 @@ int Mrr_ordered_rndpos_reader::init(handler *h_arg, int Mrr_ordered_rndpos_reader::refill_buffer(bool initial) { int res; + bool first_call= initial; DBUG_ENTER("Mrr_ordered_rndpos_reader::refill_buffer"); if (index_reader_exhausted) @@ -593,6 +605,14 @@ int Mrr_ordered_rndpos_reader::refill_buffer(bool initial) initial= FALSE; index_reader_needs_refill= FALSE; } + + if (!first_call && !index_reader_exhausted) + { + /* Ok, this was a successful buffer refill operation */ + THD *thd= current_thd; + status_var_increment(thd->status_var.ha_mrr_extra_rowid_sorts); + } + DBUG_RETURN(res); } @@ -825,8 +845,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, strategy= disk_strategy= &reader_factory.ordered_rndpos_reader; } - if (is_mrr_assoc) - status_var_increment(thd->status_var.ha_multi_range_read_init_count); + status_var_increment(thd->status_var.ha_multi_range_read_init_count); full_buf= buf->buffer; full_buf_end= buf->buffer_end; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1312675f7b4..9ecf3466750 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8303,6 +8303,9 @@ SHOW_VAR status_vars[]= { {"Handler_write", (char*) offsetof(STATUS_VAR, ha_write_count), SHOW_LONG_STATUS}, {"Handler_tmp_update", (char*) offsetof(STATUS_VAR, ha_tmp_update_count), SHOW_LONG_STATUS}, {"Handler_tmp_write", (char*) offsetof(STATUS_VAR, ha_tmp_write_count), SHOW_LONG_STATUS}, + {"Handler_mrr_init", (char*) offsetof(STATUS_VAR, ha_multi_range_read_init_count), SHOW_LONG_STATUS}, + {"Handler_mrr_extra_rowid_sorts", (char*) offsetof(STATUS_VAR, ha_mrr_extra_rowid_sorts), SHOW_LONG_STATUS}, + {"Handler_mrr_extra_key_sorts", (char*) offsetof(STATUS_VAR, ha_mrr_extra_key_sorts), SHOW_LONG_STATUS}, {"Key", (char*) &show_default_keycache, SHOW_FUNC}, {"Last_query_cost", (char*) offsetof(STATUS_VAR, last_query_cost), SHOW_DOUBLE_STATUS}, {"Max_used_connections", (char*) &max_used_connections, SHOW_LONG}, diff --git a/sql/sql_class.h b/sql/sql_class.h index f7d44eeec52..58af7888385 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -578,6 +578,8 @@ typedef struct system_status_var BatchedKeyAccess. */ ulong ha_multi_range_read_init_count; + ulong ha_mrr_extra_key_sorts; + ulong ha_mrr_extra_rowid_sorts; ulong ha_rollback_count; ulong ha_update_count; From e10816118a35cdb67cd9e1e7b671c946741d3f7c Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 25 Jan 2012 18:27:34 +0400 Subject: [PATCH 46/83] Update handler status variables after the last commit. --- mysql-test/r/myisam_mrr.result | 6 +++--- mysql-test/r/status.result | 8 +++++++- mysql-test/r/status_user.result | 3 +++ mysql-test/t/myisam_mrr.test | 1 + 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/myisam_mrr.result b/mysql-test/r/myisam_mrr.result index 0eeb22d829a..4bb0e29a26e 100644 --- a/mysql-test/r/myisam_mrr.result +++ b/mysql-test/r/myisam_mrr.result @@ -628,9 +628,9 @@ sum(t1.b) 1230 show status like 'handler_mrr%'; Variable_name Value -Handler_mrr_extra_key_sorts 1 -Handler_mrr_extra_rowid_sorts 1 -Handler_mrr_init 2 +Handler_mrr_extra_key_sorts 1or2 +Handler_mrr_extra_rowid_sorts 1or2 +Handler_mrr_init 1or2 set join_cache_level= @join_cache_level_save; set join_buffer_size= @join_buffer_size_save; drop table t0, t1; diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index b0744726390..c9602ddb8f6 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -275,6 +275,9 @@ Variable_name Value Handler_commit 0 Handler_delete 0 Handler_discover 0 +Handler_mrr_extra_key_sorts 0 +Handler_mrr_extra_rowid_sorts 0 +Handler_mrr_init 0 Handler_prepare 0 Handler_read_first 0 Handler_read_key 4 @@ -297,7 +300,7 @@ Created_tmp_files 0 Created_tmp_tables 2 Handler_tmp_update 2 Handler_tmp_write 7 -Rows_tmp_read 35 +Rows_tmp_read 38 drop table t1; CREATE TABLE t1 (i int(11) DEFAULT NULL, KEY i (i) ) ENGINE=MyISAM; insert into t1 values (1),(2),(3),(4),(5); @@ -310,6 +313,9 @@ Variable_name Value Handler_commit 0 Handler_delete 0 Handler_discover 0 +Handler_mrr_extra_key_sorts 0 +Handler_mrr_extra_rowid_sorts 0 +Handler_mrr_init 0 Handler_prepare 0 Handler_read_first 0 Handler_read_key 2 diff --git a/mysql-test/r/status_user.result b/mysql-test/r/status_user.result index 17c44df1d3c..470c1625b55 100644 --- a/mysql-test/r/status_user.result +++ b/mysql-test/r/status_user.result @@ -100,6 +100,9 @@ Variable_name Value Handler_commit 19 Handler_delete 1 Handler_discover 0 +Handler_mrr_extra_key_sorts 0 +Handler_mrr_extra_rowid_sorts 0 +Handler_mrr_init 0 Handler_prepare 18 Handler_read_first 0 Handler_read_key 3 diff --git a/mysql-test/t/myisam_mrr.test b/mysql-test/t/myisam_mrr.test index 0f916299ae7..28385c61b0f 100644 --- a/mysql-test/t/myisam_mrr.test +++ b/mysql-test/t/myisam_mrr.test @@ -313,6 +313,7 @@ set join_buffer_size=10; explain select sum(t1.b) from t0,t1 where t0.a=t1.a; flush status; select sum(t1.b) from t0,t1 where t0.a=t1.a; +--replace_result 1 1or2 2 1or2 show status like 'handler_mrr%'; set join_cache_level= @join_cache_level_save; From 73cc529b51dd4262e81df86491e3f2803946339c Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 25 Jan 2012 18:33:57 +0400 Subject: [PATCH 47/83] BUG#920255: Wrong result (extra rows) with loosescan and IN subquery The problem was that LooseScan execution code assumed that tab->key holds the index used for looseScan. This is only true when range or full index scan are used. In case of ref access, the index is in tab->ref.key (and tab->index==0 which explains how LooseScan passed tests with ref access: they used one index) Fixed by setting/using loosescan_key, which always the correct index#. --- mysql-test/r/subselect_sj.result | 34 +++++++++++++++++++++++++++ mysql-test/r/subselect_sj_jcl6.result | 34 +++++++++++++++++++++++++++ mysql-test/t/subselect_sj.test | 19 +++++++++++++++ sql/opt_subselect.cc | 1 + sql/sql_select.cc | 4 ++-- sql/sql_select.h | 6 +++++ 6 files changed, 96 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index f5c3f84bcd7..9e81a0fa1b5 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -2169,4 +2169,38 @@ WHERE c = b AND b = a a COUNT(*) NULL 0 DROP TABLE t1, t2, t3; +# +# BUG#920255: Wrong result (extra rows) with loosescan and IN subquery +# +CREATE TABLE t1 ( a INT PRIMARY KEY, b INT, KEY(b) ); +INSERT INTO t1 VALUES +(1,2),(2,1),(3,3),(4,2),(5,5), +(6,3),(7,1),(8,4),(9,3),(10,2); +CREATE TABLE t2 ( c INT, d INT, UNIQUE KEY(c) ); +INSERT INTO t2 VALUES +(1,2),(2,1),(3,3),(4,2),(5,5),(6,3),(7,1); +SELECT a, b, d FROM t1, t2 +WHERE ( b, d ) IN +( SELECT b, d FROM t1, t2 WHERE b = c ); +a b d +2 1 2 +7 1 2 +2 1 2 +7 1 2 +1 2 1 +4 2 1 +10 2 1 +1 2 1 +4 2 1 +10 2 1 +3 3 3 +6 3 3 +9 3 3 +3 3 3 +6 3 3 +9 3 3 +8 4 2 +8 4 2 +5 5 5 +DROP TABLE t1, t2; set optimizer_switch=@subselect_sj_tmp; diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index faa4140d375..f632d3bc89d 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -2183,6 +2183,40 @@ WHERE c = b AND b = a a COUNT(*) NULL 0 DROP TABLE t1, t2, t3; +# +# BUG#920255: Wrong result (extra rows) with loosescan and IN subquery +# +CREATE TABLE t1 ( a INT PRIMARY KEY, b INT, KEY(b) ); +INSERT INTO t1 VALUES +(1,2),(2,1),(3,3),(4,2),(5,5), +(6,3),(7,1),(8,4),(9,3),(10,2); +CREATE TABLE t2 ( c INT, d INT, UNIQUE KEY(c) ); +INSERT INTO t2 VALUES +(1,2),(2,1),(3,3),(4,2),(5,5),(6,3),(7,1); +SELECT a, b, d FROM t1, t2 +WHERE ( b, d ) IN +( SELECT b, d FROM t1, t2 WHERE b = c ); +a b d +1 2 1 +1 2 1 +2 1 2 +2 1 2 +3 3 3 +3 3 3 +4 2 1 +4 2 1 +5 5 5 +6 3 3 +6 3 3 +7 1 2 +7 1 2 +8 4 2 +8 4 2 +9 3 3 +9 3 3 +10 2 1 +10 2 1 +DROP TABLE t1, t2; set optimizer_switch=@subselect_sj_tmp; # # BUG#49129: Wrong result with IN-subquery with join_cache_level=6 and firstmatch=off diff --git a/mysql-test/t/subselect_sj.test b/mysql-test/t/subselect_sj.test index f34cf5ba338..afa471d5889 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -2017,5 +2017,24 @@ SELECT a, COUNT(*) FROM t1 DROP TABLE t1, t2, t3; +--echo # +--echo # BUG#920255: Wrong result (extra rows) with loosescan and IN subquery +--echo # +CREATE TABLE t1 ( a INT PRIMARY KEY, b INT, KEY(b) ); +INSERT INTO t1 VALUES + (1,2),(2,1),(3,3),(4,2),(5,5), + (6,3),(7,1),(8,4),(9,3),(10,2); + +CREATE TABLE t2 ( c INT, d INT, UNIQUE KEY(c) ); +INSERT INTO t2 VALUES + (1,2),(2,1),(3,3),(4,2),(5,5),(6,3),(7,1); + +SELECT a, b, d FROM t1, t2 +WHERE ( b, d ) IN + ( SELECT b, d FROM t1, t2 WHERE b = c ); + +DROP TABLE t1, t2; + + # The following command must be the last one the file set optimizer_switch=@subselect_sj_tmp; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 8e043b17bcf..63a90891720 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -4107,6 +4107,7 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, for (uint kp=0; kp < pos->loosescan_picker.loosescan_parts; kp++) keylen += tab->table->key_info[keyno].key_part[kp].store_length; + tab->loosescan_key= keyno; tab->loosescan_key_len= keylen; if (pos->n_sj_tables > 1) tab[pos->n_sj_tables - 1].do_firstmatch= tab; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4058e72c547..3991fff6960 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15372,7 +15372,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) if (join_tab->loosescan_match_tab && join_tab->loosescan_match_tab->found_match) { - KEY *key= join_tab->table->key_info + join_tab->index; + KEY *key= join_tab->table->key_info + join_tab->loosescan_key; key_copy(join_tab->loosescan_buf, join_tab->table->record[0], key, join_tab->loosescan_key_len); skip_over= TRUE; @@ -15382,7 +15382,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) if (skip_over && !error) { - if(!key_cmp(join_tab->table->key_info[join_tab->index].key_part, + if(!key_cmp(join_tab->table->key_info[join_tab->loosescan_key].key_part, join_tab->loosescan_buf, join_tab->loosescan_key_len)) { /* diff --git a/sql/sql_select.h b/sql/sql_select.h index 8b448130eaf..185bf90ea17 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -379,6 +379,12 @@ typedef struct st_join_table { /* Buffer to save index tuple to be able to skip duplicates */ uchar *loosescan_buf; + /* + Index used by LooseScan (we store it here separately because ref access + stores it in tab->ref.key, while range scan stores it in tab->index, etc) + */ + uint loosescan_key; + /* Length of key tuple (depends on #keyparts used) to store in the above */ uint loosescan_key_len; From 424f56b3bae1e45c2956bfcd8d92f43569471415 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Wed, 25 Jan 2012 22:05:20 +0400 Subject: [PATCH 48/83] BUG#920713: Wrong result (missing rows) with firstmatch+BNL, IN subquery, ... - Disable use of join cache when we're using FirstMatch strategy, and the join order is such that subquery's inner tables are interleaved with outer. Join buffering code is incapable of handling such join orders. - The testcase requires use of @@debug_optimizer_prefer_join_prefix to hit the bug, but I'm pushing it anyway (including the mention of the variable in .test file), so that it can be found and enabled when/if we get something comparable in the main tree. --- mysql-test/r/subselect_sj.result | 27 +++++++++++++++++++++++++++ mysql-test/r/subselect_sj_jcl6.result | 27 +++++++++++++++++++++++++++ mysql-test/t/subselect_sj.test | 17 +++++++++++++++++ sql/opt_subselect.cc | 19 +++++++++++++++---- sql/sql_select.cc | 7 ++++++- sql/sql_select.h | 7 +++++++ 6 files changed, 99 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index 9c335be4c89..0784b429052 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -2509,4 +2509,31 @@ a b d 8 4 2 5 5 5 DROP TABLE t1, t2; +# +# BUG#920713: Wrong result (missing rows) with firstmatch+BNL, IN subquery, ... +# +CREATE TABLE t1 ( a VARCHAR(1) ) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('e'),('w'),('a'),('h'),('x'),('k'),('g'); +CREATE TABLE t2 ( b INT, c VARCHAR(1) ); +INSERT INTO t2 VALUES (0,'j'),(8,'v'); +SELECT * FROM t1 alias1, t2 alias2 +WHERE alias2.c IN ( +SELECT alias4.c FROM t1 alias3, t2 alias4 +); +a b c +e 0 j +e 8 v +w 0 j +w 8 v +a 0 j +a 8 v +h 0 j +h 8 v +x 0 j +x 8 v +k 0 j +k 8 v +g 0 j +g 8 v +DROP TABLE t1, t2; set optimizer_switch=@subselect_sj_tmp; diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index af7c3484b1f..b970a01c94e 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -2523,6 +2523,33 @@ a b d 10 2 1 10 2 1 DROP TABLE t1, t2; +# +# BUG#920713: Wrong result (missing rows) with firstmatch+BNL, IN subquery, ... +# +CREATE TABLE t1 ( a VARCHAR(1) ) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('e'),('w'),('a'),('h'),('x'),('k'),('g'); +CREATE TABLE t2 ( b INT, c VARCHAR(1) ); +INSERT INTO t2 VALUES (0,'j'),(8,'v'); +SELECT * FROM t1 alias1, t2 alias2 +WHERE alias2.c IN ( +SELECT alias4.c FROM t1 alias3, t2 alias4 +); +a b c +e 0 j +e 8 v +w 0 j +w 8 v +a 0 j +a 8 v +h 0 j +h 8 v +x 0 j +x 8 v +k 0 j +k 8 v +g 0 j +g 8 v +DROP TABLE t1, t2; set optimizer_switch=@subselect_sj_tmp; # # BUG#49129: Wrong result with IN-subquery with join_cache_level=6 and firstmatch=off diff --git a/mysql-test/t/subselect_sj.test b/mysql-test/t/subselect_sj.test index 65d74419dbe..b8275f72604 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -2252,6 +2252,23 @@ WHERE ( b, d ) IN DROP TABLE t1, t2; +--echo # +--echo # BUG#920713: Wrong result (missing rows) with firstmatch+BNL, IN subquery, ... +--echo # +# t1 should be MyISAM or InnoDB +CREATE TABLE t1 ( a VARCHAR(1) ) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('e'),('w'),('a'),('h'),('x'),('k'),('g'); +CREATE TABLE t2 ( b INT, c VARCHAR(1) ); +INSERT INTO t2 VALUES (0,'j'),(8,'v'); + +#SET debug_optimizer_prefer_join_prefix= 'alias2,alias4,alias1,alias3'; + +SELECT * FROM t1 alias1, t2 alias2 +WHERE alias2.c IN ( + SELECT alias4.c FROM t1 alias3, t2 alias4 +); + +DROP TABLE t1, t2; # The following command must be the last one the file set optimizer_switch=@subselect_sj_tmp; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 63a90891720..75490482d93 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -4079,7 +4079,8 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, { uint i; DBUG_ENTER("setup_semijoin_dups_elimination"); - + + join->complex_firstmatch_tables= table_map(0); POSITION *pos= join->best_positions + join->const_tables; for (i= join->const_tables ; i < join->top_join_tab_count; ) @@ -4165,8 +4166,13 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, { JOIN_TAB *j; JOIN_TAB *jump_to= tab-1; + + bool complex_range= FALSE; + table_map tables_in_range= table_map(0); + for (j= tab; j != tab + pos->n_sj_tables; j++) { + tables_in_range |= j->table->map; if (!j->emb_sj_nest) { /* @@ -4176,11 +4182,12 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, SELECT * FROM ot1, nt1 WHERE ot1.col IN (SELECT expr FROM it1, it2) with a join order of - - ot1 it1 nt1 nt2 + +----- FirstMatch range ----+ + | | + ot1 it1 nt1 nt2 it2 it3 ... | ^ - | +-------- 'j' point here + | +-------- 'j' points here +------------- SJ_OPT_FIRST_MATCH was set for this table as it's the first one that produces duplicates @@ -4195,6 +4202,7 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, j[-1].do_firstmatch= jump_to; jump_to= j; /* Jump back to us */ + complex_range= TRUE; } else { @@ -4205,6 +4213,9 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, j[-1].do_firstmatch= jump_to; i+= pos->n_sj_tables; pos+= pos->n_sj_tables; + + if (complex_range) + join->complex_firstmatch_tables|= tables_in_range; break; } case SJ_OPT_NONE: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3991fff6960..9d03cdd55a2 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9153,6 +9153,9 @@ uint check_join_cache_usage(JOIN_TAB *tab, if (tab->use_quick == 2) goto no_join_cache; + + if (tab->table->map & join->complex_firstmatch_tables) + goto no_join_cache; /* Don't use join cache if we're inside a join tab range covered by LooseScan @@ -9363,7 +9366,7 @@ void check_join_cache_usage_for_tables(JOIN *join, ulonglong options, { tab->used_join_cache_level= join->max_allowed_join_cache_level; } - + uint idx= join->const_tables; for (tab= first_linear_tab(join, WITHOUT_CONST_TABLES); tab; @@ -9448,6 +9451,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) bool statistics= test(!(join->select_options & SELECT_DESCRIBE)); bool sorted= 1; + join->complex_firstmatch_tables= table_map(0); + if (!join->select_lex->sj_nests.is_empty() && setup_semijoin_dups_elimination(join, options, no_jbuf_after)) DBUG_RETURN(TRUE); /* purecov: inspected */ diff --git a/sql/sql_select.h b/sql/sql_select.h index 185bf90ea17..002c5a2df5a 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -995,6 +995,13 @@ public: /* We also maintain a stack of join optimization states in * join->positions[] */ /******* Join optimization state members end *******/ + + /* + Tables within complex firstmatch ranges (i.e. those where inner tables are + interleaved with outer tables). Join buffering cannot be used for these. + */ + table_map complex_firstmatch_tables; + /* The cost of best complete join plan found so far during optimization, after optimization phase - cost of picked join order (not taking into From a0c1ada91caca56bab6093fb0a4de05cd1bf936e Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 26 Jan 2012 12:22:02 +0400 Subject: [PATCH 49/83] Sort counters by name (will this make them show in the same order on all platforms?) --- sql/mysqld.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9ecf3466750..16254ead03f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8288,6 +8288,9 @@ SHOW_VAR status_vars[]= { {"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS}, {"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS}, {"Handler_discover", (char*) offsetof(STATUS_VAR, ha_discover_count), SHOW_LONG_STATUS}, + {"Handler_mrr_init", (char*) offsetof(STATUS_VAR, ha_multi_range_read_init_count), SHOW_LONG_STATUS}, + {"Handler_mrr_extra_rowid_sorts", (char*) offsetof(STATUS_VAR, ha_mrr_extra_rowid_sorts), SHOW_LONG_STATUS}, + {"Handler_mrr_extra_key_sorts", (char*) offsetof(STATUS_VAR, ha_mrr_extra_key_sorts), SHOW_LONG_STATUS}, {"Handler_prepare", (char*) offsetof(STATUS_VAR, ha_prepare_count), SHOW_LONG_STATUS}, {"Handler_read_first", (char*) offsetof(STATUS_VAR, ha_read_first_count), SHOW_LONG_STATUS}, {"Handler_read_key", (char*) offsetof(STATUS_VAR, ha_read_key_count), SHOW_LONG_STATUS}, @@ -8299,13 +8302,10 @@ SHOW_VAR status_vars[]= { {"Handler_rollback", (char*) offsetof(STATUS_VAR, ha_rollback_count), SHOW_LONG_STATUS}, {"Handler_savepoint", (char*) offsetof(STATUS_VAR, ha_savepoint_count), SHOW_LONG_STATUS}, {"Handler_savepoint_rollback",(char*) offsetof(STATUS_VAR, ha_savepoint_rollback_count), SHOW_LONG_STATUS}, - {"Handler_update", (char*) offsetof(STATUS_VAR, ha_update_count), SHOW_LONG_STATUS}, - {"Handler_write", (char*) offsetof(STATUS_VAR, ha_write_count), SHOW_LONG_STATUS}, {"Handler_tmp_update", (char*) offsetof(STATUS_VAR, ha_tmp_update_count), SHOW_LONG_STATUS}, {"Handler_tmp_write", (char*) offsetof(STATUS_VAR, ha_tmp_write_count), SHOW_LONG_STATUS}, - {"Handler_mrr_init", (char*) offsetof(STATUS_VAR, ha_multi_range_read_init_count), SHOW_LONG_STATUS}, - {"Handler_mrr_extra_rowid_sorts", (char*) offsetof(STATUS_VAR, ha_mrr_extra_rowid_sorts), SHOW_LONG_STATUS}, - {"Handler_mrr_extra_key_sorts", (char*) offsetof(STATUS_VAR, ha_mrr_extra_key_sorts), SHOW_LONG_STATUS}, + {"Handler_update", (char*) offsetof(STATUS_VAR, ha_update_count), SHOW_LONG_STATUS}, + {"Handler_write", (char*) offsetof(STATUS_VAR, ha_write_count), SHOW_LONG_STATUS}, {"Key", (char*) &show_default_keycache, SHOW_FUNC}, {"Last_query_cost", (char*) offsetof(STATUS_VAR, last_query_cost), SHOW_DOUBLE_STATUS}, {"Max_used_connections", (char*) &max_used_connections, SHOW_LONG}, From 8a8e5a50c9fd54f97e01099ff8b1e657932e80cd Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 26 Jan 2012 14:20:34 +0400 Subject: [PATCH 50/83] Fix compile failure when built without query cache: define QUERY_CACHE_DB_LENGTH_SIZE 0, just like it is done with QUERY_CACHE_FLAGS_SIZE. --- sql/mysql_priv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index fbd0d8549f7..253acff3405 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1068,6 +1068,7 @@ struct Query_cache_query_flags (((L)->sql_command == SQLCOM_SELECT) && (L)->safe_to_cache_query) #else #define QUERY_CACHE_FLAGS_SIZE 0 +#define QUERY_CACHE_DB_LENGTH_SIZE 0 #define query_cache_store_query(A, B) do { } while(0) #define query_cache_destroy() do { } while(0) #define query_cache_result_size_limit(A) do { } while(0) From 53fde5bb6f98896c0ccd9b60a9576e5c5fef8a91 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 27 Jan 2012 17:35:26 +0400 Subject: [PATCH 51/83] BUG#922254: Assertion `0' failed at item_cmpfunc.cc:5899: Item* Item_equal::get_first(JOIN_TAB*, Item*) Fixed Item* Item_equal::get_first(JOIN_TAB *context, Item *field_item) to work correctly in the case where: - context!= NO_PARTICULAR_TAB, it points to a table within SJ-Materialization nest - field_item points to an item_equal that has a constant Item_field but does not have any fields from tables that are within semi-join nests. --- mysql-test/r/subselect_mat.result | 20 ++++++++++++++++++++ mysql-test/r/subselect_sj_mat.result | 18 ++++++++++++++++++ mysql-test/t/subselect_sj_mat.test | 19 +++++++++++++++++++ sql/item_cmpfunc.cc | 10 ++++++---- 4 files changed, 63 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 7225cf7c825..bb30bfaf7f1 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -1811,6 +1811,26 @@ a b c 4 4 2 4 4 4 DROP TABLE t1,t2; +# +# BUG#922254: Assertion `0' failed at item_cmpfunc.cc:5899: Item* Item_equal::get_first(JOIN_TAB*, Item*) +# +CREATE TABLE t1 ( a VARCHAR(3) ); +CREATE TABLE t2 ( b VARCHAR(3), c VARCHAR(8), KEY(c) ); +INSERT INTO t2 VALUES ('USA','Abilene'),('USA','Akron'); +EXPLAIN +SELECT * FROM +( SELECT * FROM t1 ) AS alias1, +t2 AS alias2 +WHERE b = a AND a IN ( +SELECT alias3.c +FROM t2 AS alias3, t2 AS alias4 +WHERE alias4.c = alias3.b +); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +3 MATERIALIZED alias3 ALL NULL NULL NULL NULL 2 +3 MATERIALIZED alias4 index c c 11 NULL 2 Using where; Using index; Using join buffer (flat, BNL join) +DROP TABLE t1,t2; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; set join_cache_level=@save_join_cache_level; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 82f012bcbf1..44fb9c61f24 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -1849,6 +1849,24 @@ a b c 4 4 2 4 4 4 DROP TABLE t1,t2; +# +# BUG#922254: Assertion `0' failed at item_cmpfunc.cc:5899: Item* Item_equal::get_first(JOIN_TAB*, Item*) +# +CREATE TABLE t1 ( a VARCHAR(3) ); +CREATE TABLE t2 ( b VARCHAR(3), c VARCHAR(8), KEY(c) ); +INSERT INTO t2 VALUES ('USA','Abilene'),('USA','Akron'); +EXPLAIN +SELECT * FROM +( SELECT * FROM t1 ) AS alias1, +t2 AS alias2 +WHERE b = a AND a IN ( +SELECT alias3.c +FROM t2 AS alias3, t2 AS alias4 +WHERE alias4.c = alias3.b +); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +DROP TABLE t1,t2; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; set join_cache_level=@save_join_cache_level; diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index 2a5b0f56877..80ba42e7bab 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -1510,6 +1510,25 @@ SELECT * FROM t1 LEFT JOIN t2 ON ( a = b ) DROP TABLE t1,t2; +--echo # +--echo # BUG#922254: Assertion `0' failed at item_cmpfunc.cc:5899: Item* Item_equal::get_first(JOIN_TAB*, Item*) +--echo # +CREATE TABLE t1 ( a VARCHAR(3) ); +CREATE TABLE t2 ( b VARCHAR(3), c VARCHAR(8), KEY(c) ); +INSERT INTO t2 VALUES ('USA','Abilene'),('USA','Akron'); + +EXPLAIN +SELECT * FROM + ( SELECT * FROM t1 ) AS alias1, + t2 AS alias2 +WHERE b = a AND a IN ( + SELECT alias3.c + FROM t2 AS alias3, t2 AS alias4 + WHERE alias4.c = alias3.b +); + +DROP TABLE t1,t2; + --echo # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; set join_cache_level=@save_join_cache_level; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 8b8a85ca59b..ddb80a3ed81 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -5853,13 +5853,15 @@ Item* Item_equal::get_first(JOIN_TAB *context, Item *field_item) if (emb_nest && emb_nest->sj_mat_info && emb_nest->sj_mat_info->is_used) { /* - It's a field from an materialized semi-join. We can substitute it only - for a field from the same semi-join. Find the first of such items. + It's a field from an materialized semi-join. We can substitute it for + - a constant item + - a field from the same semi-join + Find the first of such items: */ - while ((item= it++)) { - if (it.get_curr_field()->table->pos_in_table_list->embedding == emb_nest) + if (item->const_item() || + it.get_curr_field()->table->pos_in_table_list->embedding == emb_nest) { /* If we found given field then return NULL to avoid unnecessary From 4f4047a259015479c6ec85ae3d64a8c59714a3d6 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 27 Jan 2012 17:51:40 +0400 Subject: [PATCH 52/83] Make testcase stable by adding --sorted_result for SHOW STATUS commands. --- mysql-test/t/myisam_mrr.test | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mysql-test/t/myisam_mrr.test b/mysql-test/t/myisam_mrr.test index 28385c61b0f..3629a9cebed 100644 --- a/mysql-test/t/myisam_mrr.test +++ b/mysql-test/t/myisam_mrr.test @@ -272,6 +272,7 @@ drop table t1; --echo # Test of MRR handler counters --echo # flush status; +--sorted_result show status like 'Handler_mrr%'; create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); @@ -283,6 +284,7 @@ explain select sum(b) from t1 where a < 10; --echo # This should show one MRR scan and no re-fills: flush status; select sum(b) from t1 where a < 10; +--sorted_result show status like 'handler_mrr%'; set @mrr_buffer_size_save= @@mrr_buffer_size; @@ -294,6 +296,7 @@ explain select sum(b) from t1 where a < 1600; --echo # This should show one MRR scan and one extra rowid sort: flush status; select sum(b) from t1 where a < 1600; +--sorted_result show status like 'handler_mrr%'; set @@mrr_buffer_size= @mrr_buffer_size_save; @@ -305,6 +308,7 @@ set join_cache_level=6; explain select sum(t1.b) from t0,t1 where t0.a=t1.a; flush status; select sum(t1.b) from t0,t1 where t0.a=t1.a; +--sorted_result show status like 'handler_mrr%'; --disable_warnings @@ -313,6 +317,7 @@ set join_buffer_size=10; explain select sum(t1.b) from t0,t1 where t0.a=t1.a; flush status; select sum(t1.b) from t0,t1 where t0.a=t1.a; +--sorted_result --replace_result 1 1or2 2 1or2 show status like 'handler_mrr%'; From 4e2b6d45e02bdfa5fbf998a86d5cc020b64be5d9 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 27 Jan 2012 19:01:26 -0800 Subject: [PATCH 53/83] Back-ported test cases for bug #59919 of mysql-5.6 code line. The bug could not be reproduced in the latest release of mariadb-5.3 as it was was fixed by Sergey Petrunia when working on the problems concerning outer joins within in subqueries converted to semi-joins. --- mysql-test/r/subselect_sj.result | 52 +++++++++++++++++++++++++++ mysql-test/r/subselect_sj_jcl6.result | 52 +++++++++++++++++++++++++++ mysql-test/t/subselect_sj.test | 39 ++++++++++++++++++++ 3 files changed, 143 insertions(+) diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index 0c9c2eb3af5..a6f10b21bd2 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -1538,6 +1538,58 @@ deallocate prepare s; set optimizer_switch=@save_optimizer_switch; DROP TABLE ot1, ot2, ot3, it1; # +# Bug#59919/11766739: Crash in tmp_table_param::init() with semijoin=on +# +CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM; +CREATE TABLE t2 (f1 INTEGER, f2 INTEGER) ENGINE=MyISAM; +CREATE TABLE t3 (f1 INTEGER, f2 INTEGER) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1,1), (2,1); +INSERT INTO t3 VALUES +(1,1), (2,1), (5,4), (7,3), (8,2), (8,1), (7,3), +(9,5), (4,3), (7,2), (7,7), (3,1), (5,8), (9,7); +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=off,materialization=on'; +EXPLAIN +SELECT * FROM t3 +WHERE f2 IN (SELECT t1.f1 +FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 14 Using where +2 MATERIALIZED t1 system NULL NULL NULL NULL 1 +2 MATERIALIZED b1 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED b2 ALL NULL NULL NULL NULL 2 +SELECT * FROM t3 +WHERE f2 IN (SELECT t1.f1 +FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE); +f1 f2 +1 1 +2 1 +8 1 +3 1 +set optimizer_switch='semijoin=on,materialization=on'; +EXPLAIN +SELECT * FROM t3 +WHERE f2 IN (SELECT t1.f1 +FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 +1 PRIMARY ALL distinct_key NULL NULL NULL 1 +1 PRIMARY t3 ALL NULL NULL NULL NULL 14 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED b1 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED b2 ALL NULL NULL NULL NULL 2 +SELECT * FROM t3 +WHERE f2 IN (SELECT t1.f1 +FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE); +f1 f2 +1 1 +2 1 +8 1 +3 1 +set optimizer_switch=@save_optimizer_switch; +DROP TABLE t1, t2, t3 ; +# +# # BUG#784723: Wrong result with semijoin + nested subqueries in maria-5.3 # CREATE TABLE t1 ( t1field integer, primary key (t1field)); diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index a8bc0d120cd..2f53a4855a3 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -1551,6 +1551,58 @@ deallocate prepare s; set optimizer_switch=@save_optimizer_switch; DROP TABLE ot1, ot2, ot3, it1; # +# Bug#59919/11766739: Crash in tmp_table_param::init() with semijoin=on +# +CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM; +CREATE TABLE t2 (f1 INTEGER, f2 INTEGER) ENGINE=MyISAM; +CREATE TABLE t3 (f1 INTEGER, f2 INTEGER) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1,1), (2,1); +INSERT INTO t3 VALUES +(1,1), (2,1), (5,4), (7,3), (8,2), (8,1), (7,3), +(9,5), (4,3), (7,2), (7,7), (3,1), (5,8), (9,7); +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=off,materialization=on'; +EXPLAIN +SELECT * FROM t3 +WHERE f2 IN (SELECT t1.f1 +FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 14 Using where +2 MATERIALIZED t1 system NULL NULL NULL NULL 1 +2 MATERIALIZED b1 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED b2 ALL NULL NULL NULL NULL 2 +SELECT * FROM t3 +WHERE f2 IN (SELECT t1.f1 +FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE); +f1 f2 +1 1 +2 1 +8 1 +3 1 +set optimizer_switch='semijoin=on,materialization=on'; +EXPLAIN +SELECT * FROM t3 +WHERE f2 IN (SELECT t1.f1 +FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 1 +1 PRIMARY ALL distinct_key NULL NULL NULL 1 +1 PRIMARY t3 ALL NULL NULL NULL NULL 14 Using where; Using join buffer (flat, BNL join) +2 MATERIALIZED b1 ALL NULL NULL NULL NULL 2 Using where +2 MATERIALIZED b2 ALL NULL NULL NULL NULL 2 +SELECT * FROM t3 +WHERE f2 IN (SELECT t1.f1 +FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE); +f1 f2 +1 1 +2 1 +8 1 +3 1 +set optimizer_switch=@save_optimizer_switch; +DROP TABLE t1, t2, t3 ; +# +# # BUG#784723: Wrong result with semijoin + nested subqueries in maria-5.3 # CREATE TABLE t1 ( t1field integer, primary key (t1field)); diff --git a/mysql-test/t/subselect_sj.test b/mysql-test/t/subselect_sj.test index 62d2fd61721..f906482a3b1 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -1353,6 +1353,45 @@ set optimizer_switch=@save_optimizer_switch; DROP TABLE ot1, ot2, ot3, it1; +--echo # +--echo # Bug#59919/11766739: Crash in tmp_table_param::init() with semijoin=on +--echo # + +CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM; +CREATE TABLE t2 (f1 INTEGER, f2 INTEGER) ENGINE=MyISAM; +CREATE TABLE t3 (f1 INTEGER, f2 INTEGER) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1,1), (2,1); +INSERT INTO t3 VALUES + (1,1), (2,1), (5,4), (7,3), (8,2), (8,1), (7,3), + (9,5), (4,3), (7,2), (7,7), (3,1), (5,8), (9,7); + +set @save_optimizer_switch=@@optimizer_switch; + +set optimizer_switch='semijoin=off,materialization=on'; +EXPLAIN +SELECT * FROM t3 +WHERE f2 IN (SELECT t1.f1 + FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE); +SELECT * FROM t3 +WHERE f2 IN (SELECT t1.f1 + FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE); + +set optimizer_switch='semijoin=on,materialization=on'; +EXPLAIN +SELECT * FROM t3 +WHERE f2 IN (SELECT t1.f1 + FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE); +SELECT * FROM t3 +WHERE f2 IN (SELECT t1.f1 + FROM t1 LEFT OUTER JOIN (t2 AS b1 JOIN t2 AS b2 ON TRUE) ON TRUE); + +set optimizer_switch=@save_optimizer_switch; + +DROP TABLE t1, t2, t3 ; + +--echo # --echo # --echo # BUG#784723: Wrong result with semijoin + nested subqueries in maria-5.3 --echo # From 5ca1dd8f0b22d6b5aea06c9ad32481498cb99d6e Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sat, 28 Jan 2012 01:12:45 -0800 Subject: [PATCH 54/83] Fixed LP bug #922971. Applied the fix for bug #12546542 from the mysql-5.6 code line: JOIN_CACHE::join_records forgot to reset JOIN_TAB::first_unmatched in some cases. --- mysql-test/r/join_cache.result | 48 ++++++++++++++++++++++++++++++++++ mysql-test/t/join_cache.test | 42 +++++++++++++++++++++++++++++ sql/sql_join_cache.cc | 20 +++++++------- 3 files changed, 100 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index db869ba434a..11114a032f9 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5486,4 +5486,52 @@ i set join_cache_level = default; set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +# +# Bug #12546542: missing row with semijoin=off + join cache +# (LP bug #922971) +# +CREATE TABLE t1 (a varchar(1024)); +INSERT INTO t1 VALUES ('v'), ('we'); +CREATE TABLE t2 ( +a varchar(1024) CHARACTER SET utf8 DEFAULT NULL, b int, c int +); +INSERT INTO t2 VALUES ('we',4,NULL), ('v',1305673728,6); +CREATE TABLE t3 (b int, c int); +INSERT INTO t3 VALUES (4,4); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=off'; +set optimizer_switch='materialization=off'; +set join_cache_level=0; +EXPLAIN +SELECT * FROM t1 +WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b +WHERE t2.c < 10 OR t3.c > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 1 Using where +SELECT * FROM t1 +WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b +WHERE t2.c < 10 OR t3.c > 1); +a +v +we +set join_cache_level=2; +EXPLAIN +SELECT * FROM t1 +WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b +WHERE t2.c < 10 OR t3.c > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (flat, BNL join) +SELECT * FROM t1 +WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b +WHERE t2.c < 10 OR t3.c > 1); +a +v +we +set join_cache_level = default; +set optimizer_switch=@tmp_optimizer_switch; +DROP TABLE t1,t2,t3; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index cc1941e16b9..8a61c00b7d4 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -3505,5 +3505,47 @@ set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +--echo # +--echo # Bug #12546542: missing row with semijoin=off + join cache +--echo # (LP bug #922971) +--echo # + +CREATE TABLE t1 (a varchar(1024)); +INSERT INTO t1 VALUES ('v'), ('we'); +CREATE TABLE t2 ( + a varchar(1024) CHARACTER SET utf8 DEFAULT NULL, b int, c int +); +INSERT INTO t2 VALUES ('we',4,NULL), ('v',1305673728,6); +CREATE TABLE t3 (b int, c int); +INSERT INTO t3 VALUES (4,4); + +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=off'; +set optimizer_switch='materialization=off'; + +set join_cache_level=0; +EXPLAIN +SELECT * FROM t1 + WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b + WHERE t2.c < 10 OR t3.c > 1); + +SELECT * FROM t1 + WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b + WHERE t2.c < 10 OR t3.c > 1); + +set join_cache_level=2; +EXPLAIN +SELECT * FROM t1 + WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b + WHERE t2.c < 10 OR t3.c > 1); +SELECT * FROM t1 + WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b + WHERE t2.c < 10 OR t3.c > 1); + +set join_cache_level = default; +set optimizer_switch=@tmp_optimizer_switch; + +DROP TABLE t1,t2,t3; + # this must be the last command in the file set @@optimizer_switch=@save_optimizer_switch; diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index af4b157ba90..2a8db8b4fd1 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -2109,16 +2109,6 @@ enum_nested_loop_state JOIN_CACHE::join_records(bool skip_last) if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS) goto finish; } - if (outer_join_first_inner) - { - /* - All null complemented rows have been already generated for all - outer records from join buffer. Restore the state of the - first_unmatched values to 0 to avoid another null complementing. - */ - for (tab= join_tab->first_inner; tab <= join_tab->last_inner; tab++) - tab->first_unmatched= 0; - } if (skip_last) { @@ -2131,6 +2121,16 @@ enum_nested_loop_state JOIN_CACHE::join_records(bool skip_last) } finish: + if (outer_join_first_inner) + { + /* + All null complemented rows have been already generated for all + outer records from join buffer. Restore the state of the + first_unmatched values to 0 to avoid another null complementing. + */ + for (tab= join_tab->first_inner; tab <= join_tab->last_inner; tab++) + tab->first_unmatched= 0; + } restore_last_record(); reset(TRUE); DBUG_PRINT("exit", ("rc: %d", rc)); From 12bd3dfe29164a4a74a97da5c09d9401491ea27d Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 30 Jan 2012 20:34:47 +0400 Subject: [PATCH 55/83] BUG#923246: Loosescan reports different result than other semijoin methods - If LooseScan is used with quick select, require that quick select produces data in key order (this disables use of MRR, which can return data in arbitrary order). --- mysql-test/r/subselect3_jcl6.result | 2 +- mysql-test/r/subselect_sj.result | 40 +++++++++++++++++++++++++++ mysql-test/r/subselect_sj_jcl6.result | 40 +++++++++++++++++++++++++++ mysql-test/t/subselect_sj.test | 22 +++++++++++++++ sql/opt_subselect.cc | 5 ++++ 5 files changed, 108 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect3_jcl6.result b/mysql-test/r/subselect3_jcl6.result index 38284345fc2..77b8b5faebc 100644 --- a/mysql-test/r/subselect3_jcl6.result +++ b/mysql-test/r/subselect3_jcl6.result @@ -1156,7 +1156,7 @@ insert into t4 select a from t3; explain select * from t3 where a in (select t1.kp1 from t1,t4 where kp1<20 and t4.pk=t1.c); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 range kp1 kp1 5 NULL 48 Using index condition; Using where; Rowid-ordered scan; LooseScan +1 PRIMARY t1 range kp1 kp1 5 NULL 48 Using index condition; Using where; LooseScan 1 PRIMARY t4 eq_ref PRIMARY PRIMARY 4 test.t1.c 1 Using index; FirstMatch(t1) 1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join) drop table t1, t3, t4; diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index 260cd512863..f92b33ff651 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -2588,4 +2588,44 @@ k 8 v g 0 j g 8 v DROP TABLE t1, t2; +# +# BUG#923246: Loosescan reports different result than other semijoin methods +# +set @tmp_923246= @@optimizer_switch; +set optimizer_switch='mrr=on,materialization=off'; +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (kp1 int, kp2 int, c int, filler char(100), key(kp1, kp2)); +insert into t1 select A.a+10*(B.a+10*C.a), 0, 0, 'filler' from t0 A, t0 B, t0 C; +insert into t1 select * from t1 where kp1 < 20; +create table t3 (a int); +insert into t3 select A.a + 10*B.a from t0 A, t0 B; +select * from t3 where a in (select kp1 from t1 where kp1<20); +a +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +explain select * from t3 where a in (select kp1 from t1 where kp1<20); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 range kp1 kp1 5 NULL 48 Using where; Using index; LooseScan +1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join) +drop table t0,t1,t3; +set optimizer_switch= @tmp_923246; set optimizer_switch=@subselect_sj_tmp; diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index a27b6b7b55d..dd358ced14a 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -2602,6 +2602,46 @@ k 8 v g 0 j g 8 v DROP TABLE t1, t2; +# +# BUG#923246: Loosescan reports different result than other semijoin methods +# +set @tmp_923246= @@optimizer_switch; +set optimizer_switch='mrr=on,materialization=off'; +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (kp1 int, kp2 int, c int, filler char(100), key(kp1, kp2)); +insert into t1 select A.a+10*(B.a+10*C.a), 0, 0, 'filler' from t0 A, t0 B, t0 C; +insert into t1 select * from t1 where kp1 < 20; +create table t3 (a int); +insert into t3 select A.a + 10*B.a from t0 A, t0 B; +select * from t3 where a in (select kp1 from t1 where kp1<20); +a +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +explain select * from t3 where a in (select kp1 from t1 where kp1<20); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 range kp1 kp1 5 NULL 48 Using where; Using index; LooseScan +1 PRIMARY t3 ALL NULL NULL NULL NULL 100 Using where; Using join buffer (flat, BNL join) +drop table t0,t1,t3; +set optimizer_switch= @tmp_923246; set optimizer_switch=@subselect_sj_tmp; # # BUG#49129: Wrong result with IN-subquery with join_cache_level=6 and firstmatch=off diff --git a/mysql-test/t/subselect_sj.test b/mysql-test/t/subselect_sj.test index eabdbf33ecd..6b8a757b9e8 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -2309,5 +2309,27 @@ WHERE alias2.c IN ( DROP TABLE t1, t2; +--echo # +--echo # BUG#923246: Loosescan reports different result than other semijoin methods +--echo # +set @tmp_923246= @@optimizer_switch; +set optimizer_switch='mrr=on,materialization=off'; + +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t1 (kp1 int, kp2 int, c int, filler char(100), key(kp1, kp2)); +insert into t1 select A.a+10*(B.a+10*C.a), 0, 0, 'filler' from t0 A, t0 B, t0 C; +insert into t1 select * from t1 where kp1 < 20; + +create table t3 (a int); +insert into t3 select A.a + 10*B.a from t0 A, t0 B; + +select * from t3 where a in (select kp1 from t1 where kp1<20); +explain select * from t3 where a in (select kp1 from t1 where kp1<20); + +drop table t0,t1,t3; +set optimizer_switch= @tmp_923246; + # The following command must be the last one the file set optimizer_switch=@subselect_sj_tmp; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 75490482d93..d01ef381806 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -4099,6 +4099,11 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, { /* We jump from the last table to the first one */ tab->loosescan_match_tab= tab + pos->n_sj_tables - 1; + + /* LooseScan requires records to be produced in order */ + if (tab->select && tab->select->quick) + tab->select->quick->need_sorted_output(); + for (uint j= i; j < i + pos->n_sj_tables; j++) join->join_tab[j].inside_loosescan_range= TRUE; From 7ed15e6e50aec65560d8988fc5713f1f489b6616 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 31 Jan 2012 21:12:26 +0100 Subject: [PATCH 56/83] sort status variables alphabetically in mysqld.cc --- mysql-test/t/myisam_mrr.test | 5 ----- sql/mysqld.cc | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/mysql-test/t/myisam_mrr.test b/mysql-test/t/myisam_mrr.test index 3629a9cebed..28385c61b0f 100644 --- a/mysql-test/t/myisam_mrr.test +++ b/mysql-test/t/myisam_mrr.test @@ -272,7 +272,6 @@ drop table t1; --echo # Test of MRR handler counters --echo # flush status; ---sorted_result show status like 'Handler_mrr%'; create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); @@ -284,7 +283,6 @@ explain select sum(b) from t1 where a < 10; --echo # This should show one MRR scan and no re-fills: flush status; select sum(b) from t1 where a < 10; ---sorted_result show status like 'handler_mrr%'; set @mrr_buffer_size_save= @@mrr_buffer_size; @@ -296,7 +294,6 @@ explain select sum(b) from t1 where a < 1600; --echo # This should show one MRR scan and one extra rowid sort: flush status; select sum(b) from t1 where a < 1600; ---sorted_result show status like 'handler_mrr%'; set @@mrr_buffer_size= @mrr_buffer_size_save; @@ -308,7 +305,6 @@ set join_cache_level=6; explain select sum(t1.b) from t0,t1 where t0.a=t1.a; flush status; select sum(t1.b) from t0,t1 where t0.a=t1.a; ---sorted_result show status like 'handler_mrr%'; --disable_warnings @@ -317,7 +313,6 @@ set join_buffer_size=10; explain select sum(t1.b) from t0,t1 where t0.a=t1.a; flush status; select sum(t1.b) from t0,t1 where t0.a=t1.a; ---sorted_result --replace_result 1 1or2 2 1or2 show status like 'handler_mrr%'; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 16254ead03f..a090448ebae 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8288,9 +8288,9 @@ SHOW_VAR status_vars[]= { {"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS}, {"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS}, {"Handler_discover", (char*) offsetof(STATUS_VAR, ha_discover_count), SHOW_LONG_STATUS}, - {"Handler_mrr_init", (char*) offsetof(STATUS_VAR, ha_multi_range_read_init_count), SHOW_LONG_STATUS}, - {"Handler_mrr_extra_rowid_sorts", (char*) offsetof(STATUS_VAR, ha_mrr_extra_rowid_sorts), SHOW_LONG_STATUS}, {"Handler_mrr_extra_key_sorts", (char*) offsetof(STATUS_VAR, ha_mrr_extra_key_sorts), SHOW_LONG_STATUS}, + {"Handler_mrr_extra_rowid_sorts", (char*) offsetof(STATUS_VAR, ha_mrr_extra_rowid_sorts), SHOW_LONG_STATUS}, + {"Handler_mrr_init", (char*) offsetof(STATUS_VAR, ha_multi_range_read_init_count), SHOW_LONG_STATUS}, {"Handler_prepare", (char*) offsetof(STATUS_VAR, ha_prepare_count), SHOW_LONG_STATUS}, {"Handler_read_first", (char*) offsetof(STATUS_VAR, ha_read_first_count), SHOW_LONG_STATUS}, {"Handler_read_key", (char*) offsetof(STATUS_VAR, ha_read_key_count), SHOW_LONG_STATUS}, From b4643d75fe065d92403817a1dd8785b198b6fdec Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Feb 2012 17:09:49 +0200 Subject: [PATCH 57/83] fix for LP BUG#921878. Problem was in try to check/use Item_direct_ref of derived view when we have to use real Item_field under it. --- mysql-test/r/derived_view.result | 25 ++++++++++++++++++++++++- mysql-test/t/derived_view.test | 30 ++++++++++++++++++++++++++---- sql/item.cc | 10 +++++----- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index e853f5ac526..eceae5cc3d9 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -1800,6 +1800,7 @@ INSERT INTO t2 VALUES (7), (4); CREATE TABLE t1 (b int NOT NULL); INSERT INTO t1 VALUES (5), (7); CREATE ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1; +SET @save_optimizer_switch=@@optimizer_switch; SET SESSION optimizer_switch='derived_merge=off'; PREPARE st1 FROM 'SELECT * FROM (SELECT * FROM t2 LEFT JOIN v1 ON t2.a = v1.b) AS t'; @@ -1812,9 +1813,9 @@ a b 7 7 4 NULL DEALLOCATE PREPARE st1; +set SESSION optimizer_switch= @save_optimizer_switch; DROP VIEW v1; DROP TABLE t1,t2; -SET SESSION optimizer_switch='derived_merge=on'; # # LP bug #879939: assertion in ha_maria::enable_indexes # with derived_with_keys=on @@ -1832,6 +1833,7 @@ INSERT INTO t1 VALUES ('USA','Mesquite'), ('USA','Metairie'), ('USA','Miami'); CREATE TABLE t3 (a varchar(35)); INSERT INTO t3 VALUES ('Miami'); +SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch = 'derived_with_keys=on'; SET @@tmp_table_size=1024*4; explain SELECT * FROM (SELECT t1.* FROM t1, t2) AS t JOIN t3 ON t3.a = t.b; @@ -1855,6 +1857,7 @@ USA Miami Miami USA Miami Miami USA Miami Miami SET @@tmp_table_size=default; +set SESSION optimizer_switch= @save_optimizer_switch; drop table t1,t2,t3; # # BUG#882994: Crash in QUICK_RANGE_SELECT::reset with derived_with_keys @@ -1906,5 +1909,25 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 3 2 DERIVED t1 ALL NULL NULL NULL NULL 8 DROP TABLE t1; +# +# LP BUG#921878 incorrect check of items during columns union types +# aggregation for merged derived tables +# +SET @save_optimizer_switch=@@optimizer_switch; +SET SESSION optimizer_switch='derived_merge=on'; +CREATE TABLE t1 ( a ENUM( 'x', 'y' ) ); +insert into t1 values ('x'); +CREATE TABLE t2 LIKE t1; +insert into t1 values ('y'); +CREATE TABLE t3 LIKE t1; +INSERT INTO t3 +SELECT * FROM ( SELECT * FROM t1 ) AS A +UNION SELECT * FROM t2; +select * from t3; +a +x +y +drop table t1,t2,t3; +set SESSION optimizer_switch= @save_optimizer_switch; set optimizer_switch=@exit_optimizer_switch; set join_cache_level=@exit_join_cache_level; diff --git a/mysql-test/t/derived_view.test b/mysql-test/t/derived_view.test index f8ba1f347f3..95412426aa0 100644 --- a/mysql-test/t/derived_view.test +++ b/mysql-test/t/derived_view.test @@ -1192,7 +1192,7 @@ INSERT INTO t2 VALUES (7), (4); CREATE TABLE t1 (b int NOT NULL); INSERT INTO t1 VALUES (5), (7); CREATE ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1; - +SET @save_optimizer_switch=@@optimizer_switch; SET SESSION optimizer_switch='derived_merge=off'; PREPARE st1 FROM @@ -1201,10 +1201,12 @@ EXECUTE st1; EXECUTE st1; DEALLOCATE PREPARE st1; +set SESSION optimizer_switch= @save_optimizer_switch; + DROP VIEW v1; DROP TABLE t1,t2; -SET SESSION optimizer_switch='derived_merge=on'; + --echo # --echo # LP bug #879939: assertion in ha_maria::enable_indexes @@ -1226,7 +1228,7 @@ INSERT INTO t1 VALUES CREATE TABLE t3 (a varchar(35)); INSERT INTO t3 VALUES ('Miami'); - +SET @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch = 'derived_with_keys=on'; SET @@tmp_table_size=1024*4; explain SELECT * FROM (SELECT t1.* FROM t1, t2) AS t JOIN t3 ON t3.a = t.b; @@ -1234,7 +1236,7 @@ SELECT * FROM (SELECT t1.* FROM t1, t2) AS t JOIN t3 ON t3.a = t.b; SET @@tmp_table_size=1024*1024*16; SELECT * FROM (SELECT t1.* FROM t1, t2) AS t JOIN t3 ON t3.a = t.b; SET @@tmp_table_size=default; - +set SESSION optimizer_switch= @save_optimizer_switch; drop table t1,t2,t3; --echo # @@ -1291,6 +1293,26 @@ SELECT * FROM (SELECT * FROM t1 LIMIT 3) t; DROP TABLE t1; +--echo # +--echo # LP BUG#921878 incorrect check of items during columns union types +--echo # aggregation for merged derived tables +--echo # +SET @save_optimizer_switch=@@optimizer_switch; +SET SESSION optimizer_switch='derived_merge=on'; +CREATE TABLE t1 ( a ENUM( 'x', 'y' ) ); +insert into t1 values ('x'); +CREATE TABLE t2 LIKE t1; +insert into t1 values ('y'); +CREATE TABLE t3 LIKE t1; +INSERT INTO t3 + SELECT * FROM ( SELECT * FROM t1 ) AS A + UNION SELECT * FROM t2; +select * from t3; + +drop table t1,t2,t3; + +set SESSION optimizer_switch= @save_optimizer_switch; + # The following command must be the last one the file set optimizer_switch=@exit_optimizer_switch; set join_cache_level=@exit_join_cache_level; diff --git a/sql/item.cc b/sql/item.cc index aaf9b0c2a12..b738d1f00da 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9052,13 +9052,13 @@ void Item_type_holder::get_full_info(Item *item) DBUG_ASSERT((enum_set_typelib && get_real_type(item) == MYSQL_TYPE_NULL) || (!enum_set_typelib && - item->type() == Item::FIELD_ITEM && - (get_real_type(item) == MYSQL_TYPE_ENUM || - get_real_type(item) == MYSQL_TYPE_SET) && - ((Field_enum*)((Item_field *) item)->field)->typelib)); + item->real_item()->type() == Item::FIELD_ITEM && + (get_real_type(item->real_item()) == MYSQL_TYPE_ENUM || + get_real_type(item->real_item()) == MYSQL_TYPE_SET) && + ((Field_enum*)((Item_field *) item->real_item())->field)->typelib)); if (!enum_set_typelib) { - enum_set_typelib= ((Field_enum*)((Item_field *) item)->field)->typelib; + enum_set_typelib= ((Field_enum*)((Item_field *) item->real_item())->field)->typelib; } } } From 94c316069e7d1be80d81d55c3218d3f29d38f230 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 2 Feb 2012 22:22:27 -0800 Subject: [PATCH 58/83] Applied the patch from mysql-5.6 code line that fixed a significant performance drop for high concurrency bechmarks (bug #11765850 - 58854). Here's the comment of the patch commit: The bug is that the InnoDB pre-fetch cache was not being used in row_search_for_mysql(). Secondly the changeset that planted the bug also introduced some inefficient code. It would read an extra row, convert it to MySQL row format (for ICP==off), copy the row to the pre-fetch cache row buffer, then check for cache overflow and dequeue the row that was pushed if there was a possibility of a cache overflow. --- storage/xtradb/row/row0sel.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/storage/xtradb/row/row0sel.c b/storage/xtradb/row/row0sel.c index 226b19359bb..f52e782599f 100644 --- a/storage/xtradb/row/row0sel.c +++ b/storage/xtradb/row/row0sel.c @@ -3259,16 +3259,15 @@ row_sel_pop_cached_row_for_mysql( } /********************************************************************//** -Pushes a row for MySQL to the fetch cache. -@return TRUE on success, FALSE if the record contains incomplete BLOBs */ -UNIV_INLINE __attribute__((warn_unused_result)) -ibool +Pushes a row for MySQL to the fetch cache. */ +UNIV_INLINE +void row_sel_push_cache_row_for_mysql( /*=============================*/ byte* mysql_rec, /*!< in/out: MySQL record */ row_prebuilt_t* prebuilt) /*!< in/out: prebuilt struct */ { - ut_ad(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE); + ut_a(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE); ut_a(!prebuilt->templ_contains_blob); if (UNIV_UNLIKELY(prebuilt->fetch_cache[0] == NULL)) { @@ -3300,12 +3299,7 @@ row_sel_push_cache_row_for_mysql( memcpy(prebuilt->fetch_cache[prebuilt->n_fetch_cached], mysql_rec, prebuilt->mysql_row_len); - if (++prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE) { - return(FALSE); - } - - row_sel_pop_cached_row_for_mysql(mysql_rec, prebuilt); - return(TRUE); + ++prebuilt->n_fetch_cached; } /*********************************************************************//** @@ -4669,6 +4663,11 @@ requires_clust_rec: not cache rows because there the cursor is a scrollable cursor. */ + ut_a(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE); + + /* We only convert from InnoDB row format to MySQL row + format when ICP is disabled. */ + if (!prebuilt->idx_cond && !row_sel_store_mysql_rec(buf, prebuilt, result_rec, result_rec != rec, offsets)) { @@ -4680,8 +4679,12 @@ requires_clust_rec: transaction. Rollback happens at a lower level, not here. */ goto next_rec; - } else if (row_sel_push_cache_row_for_mysql(buf, prebuilt)) { - goto next_rec; + } + + row_sel_push_cache_row_for_mysql(buf, prebuilt); + + if (prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE) { + goto next_rec; } } else { if (UNIV_UNLIKELY From d6e1377ac206718abd039426ab72690a9ee0b48e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Feb 2012 10:28:23 +0200 Subject: [PATCH 59/83] Fix check of view updatability in case of underlying view changes its updatability. For single table update/insert added deep check of single tables (single_table_updatable()). For multi-table view insert added additional check of target table (check_view_single_update). Multi-update was correct. Test suite for all cases added. --- mysql-test/r/view.result | 27 ++++++++++++++++++++++++++- mysql-test/t/view.test | 22 +++++++++++++++++++++- sql/sql_insert.cc | 17 +++++++++++++---- sql/sql_update.cc | 3 ++- sql/table.cc | 22 ++++++++++++++++++++++ sql/table.h | 3 +++ 6 files changed, 87 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 22fd4eb1722..65d6574ac8b 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -3930,10 +3930,35 @@ drop table t1,t2; # Bug #794005: crash in st_table::mark_virtual_columns_for_write # CREATE TABLE t1 (a int); +insert into t1 values (1); CREATE TABLE t2 (a int); +insert into t2 values (1); CREATE VIEW v2 AS SELECT * FROM t2; CREATE VIEW v1 AS SELECT * FROM v2; +CREATE VIEW v3 AS SELECT t2.a,v1.a as b FROM t2,v1 where t2.a=v1.a; CREATE OR REPLACE ALGORITHM = TEMPTABLE VIEW v2 AS SELECT * FROM t1; UPDATE v1 SET a = 10; -DROP VIEW v1,v2; +ERROR HY000: The target table v1 of the UPDATE is not updatable +REPLACE v1 SET a = 10; +ERROR HY000: The target table v1 of the INSERT is not insertable-into +INSERT into v1 values (20); +ERROR HY000: The target table v1 of the INSERT is not insertable-into +UPDATE v3 SET b= 10; +ERROR HY000: The target table v2 of the UPDATE is not updatable +REPLACE v3 SET b= 10; +ERROR HY000: The target table v3 of the INSERT is not insertable-into +INSERT into v3(b) values (20); +ERROR HY000: The target table v3 of the INSERT is not insertable-into +UPDATE v3 SET a = 10; +REPLACE v3 SET a = 11; +INSERT INTO v3(a) values (20); +select * from t1; +a +1 +select * from t2; +a +10 +11 +20 +DROP VIEW v1,v2,v3; DROP TABLE t1,t2; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 462118af4ea..4be8aa89358 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -3982,13 +3982,33 @@ drop table t1,t2; --echo # CREATE TABLE t1 (a int); +insert into t1 values (1); CREATE TABLE t2 (a int); +insert into t2 values (1); CREATE VIEW v2 AS SELECT * FROM t2; CREATE VIEW v1 AS SELECT * FROM v2; +CREATE VIEW v3 AS SELECT t2.a,v1.a as b FROM t2,v1 where t2.a=v1.a; CREATE OR REPLACE ALGORITHM = TEMPTABLE VIEW v2 AS SELECT * FROM t1; +--error ER_NON_UPDATABLE_TABLE UPDATE v1 SET a = 10; +--error ER_NON_INSERTABLE_TABLE +REPLACE v1 SET a = 10; +--error ER_NON_INSERTABLE_TABLE +INSERT into v1 values (20); +--error ER_NON_UPDATABLE_TABLE +UPDATE v3 SET b= 10; +--error ER_NON_INSERTABLE_TABLE +REPLACE v3 SET b= 10; +--error ER_NON_INSERTABLE_TABLE +INSERT into v3(b) values (20); +UPDATE v3 SET a = 10; +REPLACE v3 SET a = 11; +INSERT INTO v3(a) values (20); -DROP VIEW v1,v2; +select * from t1; +select * from t2; + +DROP VIEW v1,v2,v3; DROP TABLE t1,t2; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 99bebe827a4..c350d2deeee 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -103,7 +103,8 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view); */ bool check_view_single_update(List &fields, List *values, - TABLE_LIST *view, table_map *map) + TABLE_LIST *view, table_map *map, + bool insert) { /* it is join view => we need to find the table for update */ List_iterator_fast it(fields); @@ -135,6 +136,14 @@ bool check_view_single_update(List &fields, List *values, goto error; view->table= tbl->table; + if (!tbl->single_table_updatable()) + { + if (insert) + my_error(ER_NON_INSERTABLE_TABLE, MYF(0), view->alias, "INSERT"); + else + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), view->alias, "UPDATE"); + return TRUE; + } *map= tables; return FALSE; @@ -179,7 +188,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, { TABLE *table= table_list->table; - if (!table_list->updatable) + if (!table_list->single_table_updatable()) { my_error(ER_NON_INSERTABLE_TABLE, MYF(0), table_list->alias, "INSERT"); return -1; @@ -251,7 +260,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, if (check_view_single_update(fields, fields_and_values_from_different_maps ? (List*) 0 : &values, - table_list, map)) + table_list, map, true)) return -1; table= table_list->table; } @@ -337,7 +346,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE && check_view_single_update(update_fields, &update_values, - insert_table_list, map)) + insert_table_list, map, false)) return -1; if (table->timestamp_field) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c6f413e754e..b3c001849b5 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -277,7 +277,8 @@ int mysql_update(THD *thd, { DBUG_RETURN(1); } - if (!table_list->updatable || check_key_in_view(thd, table_list)) + if (!table_list->single_table_updatable() || + check_key_in_view(thd, table_list)) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE"); DBUG_RETURN(1); diff --git a/sql/table.cc b/sql/table.cc index a3df9023805..e576e5ae25f 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3722,6 +3722,28 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds, DBUG_RETURN(FALSE); } +/** + Check that table/view is updatable and if it has single + underlying tables/views it is also updatable + + @return Result of the check. +*/ + +bool TABLE_LIST::single_table_updatable() +{ + if (!updatable) + return false; + if (view_tables && view_tables->elements == 1) + { + /* + We need to check deeply only single table views. Multi-table views + will be turned to multi-table updates and then checked by leaf tables + */ + return view_tables->head()->single_table_updatable(); + } + return true; +} + /* Merge ON expressions for a view diff --git a/sql/table.h b/sql/table.h index 1b7713022ce..fed30722d71 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1606,6 +1606,9 @@ struct TABLE_LIST */ char *get_table_name() { return view != NULL ? view_name.str : table_name; } + + bool single_table_updatable(); + private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); From b9616d815d9c318bb2c1028041a210a807d941bc Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Feb 2012 10:31:30 +0200 Subject: [PATCH 60/83] Added 5.2 test result delimiter --- mysql-test/r/view.result | 3 +++ mysql-test/t/view.test | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 65d6574ac8b..8d1237501f3 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -3962,3 +3962,6 @@ a 20 DROP VIEW v1,v2,v3; DROP TABLE t1,t2; +# ----------------------------------------------------------------- +# -- End of 5.2 tests. +# ----------------------------------------------------------------- diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 4be8aa89358..f691a0c528b 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -4012,3 +4012,7 @@ select * from t2; DROP VIEW v1,v2,v3; DROP TABLE t1,t2; + +--echo # ----------------------------------------------------------------- +--echo # -- End of 5.2 tests. +--echo # ----------------------------------------------------------------- From 046988661d330e48e19af9fd7d9d2ad4f6cbcd1e Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 3 Feb 2012 00:46:34 -0800 Subject: [PATCH 61/83] Back-ported the fix for bug #12831587 from mysql-5.6 code line. The comment for the fix commit says: Due to the changes required by ICP we first copy a row from the InnoDB format to the MySQL row buffer and then copy it to the pre-fetch queue. This was done for the non-ICP code path too. This change removes the double copy for the latter. --- storage/xtradb/row/row0sel.c | 40 +++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/storage/xtradb/row/row0sel.c b/storage/xtradb/row/row0sel.c index f52e782599f..fca3c90109f 100644 --- a/storage/xtradb/row/row0sel.c +++ b/storage/xtradb/row/row0sel.c @@ -3259,12 +3259,12 @@ row_sel_pop_cached_row_for_mysql( } /********************************************************************//** -Pushes a row for MySQL to the fetch cache. */ -UNIV_INLINE -void -row_sel_push_cache_row_for_mysql( -/*=============================*/ - byte* mysql_rec, /*!< in/out: MySQL record */ +Get the last fetch cache buffer from the queue. +@return pointer to buffer. */ +UNIV_INLINE +byte* +row_sel_fetch_last_buf( +/*===================*/ row_prebuilt_t* prebuilt) /*!< in/out: prebuilt struct */ { ut_a(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE); @@ -3296,8 +3296,26 @@ row_sel_push_cache_row_for_mysql( UNIV_MEM_INVALID(prebuilt->fetch_cache[prebuilt->n_fetch_cached], prebuilt->mysql_row_len); - memcpy(prebuilt->fetch_cache[prebuilt->n_fetch_cached], - mysql_rec, prebuilt->mysql_row_len); + return(prebuilt->fetch_cache[prebuilt->n_fetch_cached]); +} + +/********************************************************************//** +Pushes a row for MySQL to the fetch cache. */ +UNIV_INLINE +void +row_sel_push_cache_row_for_mysql( +/*=============================*/ + byte* mysql_rec, /*!< in/out: MySQL record */ + row_prebuilt_t* prebuilt) /*!< in/out: prebuilt struct */ +{ + /* For non ICP code path the row should already exist in the + next fetch cache slot. */ + + if (prebuilt->idx_cond != NULL) { + byte* dest = row_sel_fetch_last_buf(prebuilt); + + ut_memcpy(dest, mysql_rec, prebuilt->mysql_row_len); + } ++prebuilt->n_fetch_cached; } @@ -4669,8 +4687,10 @@ requires_clust_rec: format when ICP is disabled. */ if (!prebuilt->idx_cond - && !row_sel_store_mysql_rec(buf, prebuilt, result_rec, - result_rec != rec, offsets)) { + && !row_sel_store_mysql_rec( + row_sel_fetch_last_buf(prebuilt), + prebuilt, result_rec, + result_rec != rec, offsets)) { /* Only fresh inserts may contain incomplete externally stored columns. Pretend that such records do not exist. Such records may only be From 52d4103ccc02c55e05faef188d73d2b07c00084b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Feb 2012 12:24:55 +0200 Subject: [PATCH 62/83] Fixed DELETE issues of view over view over table. --- mysql-test/r/view.result | 18 ++++++++++++++++++ mysql-test/t/view.test | 14 ++++++++++++++ sql/sql_delete.cc | 5 +++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 8d1237501f3..0ff06ac09d7 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -3943,12 +3943,20 @@ REPLACE v1 SET a = 10; ERROR HY000: The target table v1 of the INSERT is not insertable-into INSERT into v1 values (20); ERROR HY000: The target table v1 of the INSERT is not insertable-into +DELETE from v1; +ERROR HY000: The target table v1 of the DELETE is not updatable UPDATE v3 SET b= 10; ERROR HY000: The target table v2 of the UPDATE is not updatable REPLACE v3 SET b= 10; ERROR HY000: The target table v3 of the INSERT is not insertable-into INSERT into v3(b) values (20); ERROR HY000: The target table v3 of the INSERT is not insertable-into +DELETE from v3 where b=20; +ERROR HY000: Can not delete from join view 'test.v3' +DELETE from v3 where a=20; +ERROR HY000: Can not delete from join view 'test.v3' +DELETE v1 from v1,t1 where v1.a=t1.a; +ERROR HY000: The target table v1 of the DELETE is not updatable UPDATE v3 SET a = 10; REPLACE v3 SET a = 11; INSERT INTO v3(a) values (20); @@ -3960,6 +3968,16 @@ a 10 11 20 +CREATE OR REPLACE ALGORITHM = MERGE VIEW v2 AS SELECT * FROM t2; +DELETE from v1 where a=11; +DELETE v1 from v1,t1 where v1.a=t1.a; +select * from t1; +a +1 +select * from t2; +a +10 +20 DROP VIEW v1,v2,v3; DROP TABLE t1,t2; # ----------------------------------------------------------------- diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index f691a0c528b..762c3121615 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -3998,11 +3998,19 @@ REPLACE v1 SET a = 10; --error ER_NON_INSERTABLE_TABLE INSERT into v1 values (20); --error ER_NON_UPDATABLE_TABLE +DELETE from v1; +--error ER_NON_UPDATABLE_TABLE UPDATE v3 SET b= 10; --error ER_NON_INSERTABLE_TABLE REPLACE v3 SET b= 10; --error ER_NON_INSERTABLE_TABLE INSERT into v3(b) values (20); +--error ER_VIEW_DELETE_MERGE_VIEW +DELETE from v3 where b=20; +--error ER_VIEW_DELETE_MERGE_VIEW +DELETE from v3 where a=20; +--error ER_NON_UPDATABLE_TABLE +DELETE v1 from v1,t1 where v1.a=t1.a; UPDATE v3 SET a = 10; REPLACE v3 SET a = 11; INSERT INTO v3(a) values (20); @@ -4010,6 +4018,12 @@ INSERT INTO v3(a) values (20); select * from t1; select * from t2; +CREATE OR REPLACE ALGORITHM = MERGE VIEW v2 AS SELECT * FROM t2; +DELETE from v1 where a=11; +DELETE v1 from v1,t1 where v1.a=t1.a; +select * from t1; +select * from t2; + DROP VIEW v1,v2,v3; DROP TABLE t1,t2; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 29cd3262a72..72a5b9703b3 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -508,7 +508,8 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) setup_conds(thd, table_list, select_lex->leaf_tables, conds) || setup_ftfuncs(select_lex)) DBUG_RETURN(TRUE); - if (!table_list->updatable || check_key_in_view(thd, table_list)) + if (!table_list->single_table_updatable() || + check_key_in_view(thd, table_list)) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE"); DBUG_RETURN(TRUE); @@ -598,7 +599,7 @@ int mysql_multi_delete_prepare(THD *thd) DBUG_RETURN(TRUE); } - if (!target_tbl->correspondent_table->updatable || + if (!target_tbl->correspondent_table->single_table_updatable() || check_key_in_view(thd, target_tbl->correspondent_table)) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), From 79a04a2c9c2cb04bc635b609504e2b9fb57fd23d Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Feb 2012 13:01:05 +0200 Subject: [PATCH 63/83] Moving LP BUG#794005 to 5.3 + fixing INSERT of multi-table view. --- mysql-test/r/view.result | 60 ++++++++++++++++++++++++++++++++++++++++ mysql-test/t/view.test | 58 ++++++++++++++++++++++++++++++++++++++ sql/item.cc | 16 +++++++---- sql/sql_base.cc | 5 ++-- sql/sql_delete.cc | 7 +++-- sql/sql_derived.cc | 2 +- sql/sql_insert.cc | 19 +++++++++---- sql/sql_load.cc | 2 +- sql/sql_prepare.cc | 4 +-- sql/sql_update.cc | 4 +-- sql/table.cc | 25 +++++++++++++++++ sql/table.h | 3 ++ 12 files changed, 183 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index d302df2f029..15ef0c088b1 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -3930,6 +3930,63 @@ drop table t1,t2; # -- End of 5.1 tests. # ----------------------------------------------------------------- # +# Bug #794005: crash in st_table::mark_virtual_columns_for_write +# +CREATE TABLE t1 (a int); +insert into t1 values (1); +CREATE TABLE t2 (a int); +insert into t2 values (1); +CREATE VIEW v2 AS SELECT * FROM t2; +CREATE VIEW v1 AS SELECT * FROM v2; +CREATE VIEW v3 AS SELECT t2.a,v1.a as b FROM t2,v1 where t2.a=v1.a; +CREATE OR REPLACE ALGORITHM = TEMPTABLE VIEW v2 AS SELECT * FROM t1; +UPDATE v1 SET a = 10; +ERROR HY000: The target table v1 of the UPDATE is not updatable +REPLACE v1 SET a = 10; +ERROR HY000: The target table v1 of the INSERT is not insertable-into +INSERT into v1 values (20); +ERROR HY000: The target table v1 of the INSERT is not insertable-into +DELETE from v1; +ERROR HY000: The target table v1 of the DELETE is not updatable +UPDATE v3 SET b= 10; +ERROR HY000: The target table v2 of the UPDATE is not updatable +REPLACE v3 SET b= 10; +ERROR HY000: The target table v3 of the INSERT is not insertable-into +INSERT into v3(b) values (20); +ERROR HY000: The target table v3 of the INSERT is not insertable-into +DELETE from v3 where b=20; +ERROR HY000: Can not delete from join view 'test.v3' +DELETE from v3 where a=20; +ERROR HY000: Can not delete from join view 'test.v3' +DELETE v1 from v1,t1 where v1.a=t1.a; +ERROR HY000: The target table v1 of the DELETE is not updatable +UPDATE v3 SET a = 10; +REPLACE v3 SET a = 11; +INSERT INTO v3(a) values (20); +select * from t1; +a +1 +select * from t2; +a +10 +11 +20 +CREATE OR REPLACE ALGORITHM = MERGE VIEW v2 AS SELECT * FROM t2; +DELETE from v1 where a=11; +DELETE v1 from v1,t1 where v1.a=t1.a; +select * from t1; +a +1 +select * from t2; +a +10 +20 +DROP VIEW v1,v2,v3; +DROP TABLE t1,t2; +# ----------------------------------------------------------------- +# -- End of 5.2 tests. +# ----------------------------------------------------------------- +# # Bug #59696 Optimizer does not use equalities for conditions over view # CREATE TABLE t1 (a int NOT NULL); @@ -4376,4 +4433,7 @@ NULL NULL 1 0 NULL NULL 1 0 DROP VIEW v2; DROP TABLE t1, t2, t3; +# ----------------------------------------------------------------- +# -- End of 5.3 tests. +# ----------------------------------------------------------------- SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index d4d5f2acc0b..2a9bfd89f3b 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -3980,6 +3980,60 @@ drop table t1,t2; --echo # ----------------------------------------------------------------- --echo # -- End of 5.1 tests. --echo # ----------------------------------------------------------------- +--echo # +--echo # Bug #794005: crash in st_table::mark_virtual_columns_for_write +--echo # + +CREATE TABLE t1 (a int); +insert into t1 values (1); +CREATE TABLE t2 (a int); +insert into t2 values (1); + +CREATE VIEW v2 AS SELECT * FROM t2; +CREATE VIEW v1 AS SELECT * FROM v2; +CREATE VIEW v3 AS SELECT t2.a,v1.a as b FROM t2,v1 where t2.a=v1.a; +CREATE OR REPLACE ALGORITHM = TEMPTABLE VIEW v2 AS SELECT * FROM t1; + +--error ER_NON_UPDATABLE_TABLE +UPDATE v1 SET a = 10; +--error ER_NON_INSERTABLE_TABLE +REPLACE v1 SET a = 10; +--error ER_NON_INSERTABLE_TABLE +INSERT into v1 values (20); +--error ER_NON_UPDATABLE_TABLE +DELETE from v1; +--error ER_NON_UPDATABLE_TABLE +UPDATE v3 SET b= 10; +--error ER_NON_INSERTABLE_TABLE +REPLACE v3 SET b= 10; +--error ER_NON_INSERTABLE_TABLE +INSERT into v3(b) values (20); +--error ER_VIEW_DELETE_MERGE_VIEW +DELETE from v3 where b=20; +--error ER_VIEW_DELETE_MERGE_VIEW +DELETE from v3 where a=20; +--error ER_NON_UPDATABLE_TABLE +DELETE v1 from v1,t1 where v1.a=t1.a; +UPDATE v3 SET a = 10; +REPLACE v3 SET a = 11; +INSERT INTO v3(a) values (20); + +select * from t1; +select * from t2; + +CREATE OR REPLACE ALGORITHM = MERGE VIEW v2 AS SELECT * FROM t2; +DELETE from v1 where a=11; +DELETE v1 from v1,t1 where v1.a=t1.a; +select * from t1; +select * from t2; + +DROP VIEW v1,v2,v3; +DROP TABLE t1,t2; + +--echo # ----------------------------------------------------------------- +--echo # -- End of 5.2 tests. +--echo # ----------------------------------------------------------------- + --echo # --echo # Bug #59696 Optimizer does not use equalities for conditions over view --echo # @@ -4311,4 +4365,8 @@ SELECT * FROM t1 RIGHT JOIN v2 ON ( v2.a = t1.a ) WHERE v2.b IN ( SELECT b FROM DROP VIEW v2; DROP TABLE t1, t2, t3; +--echo # ----------------------------------------------------------------- +--echo # -- End of 5.3 tests. +--echo # ----------------------------------------------------------------- + SET optimizer_switch=@save_optimizer_switch; diff --git a/sql/item.cc b/sql/item.cc index 8bd5b6fe1a4..f9bbc4aeead 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9143,18 +9143,22 @@ void Item_ref::update_used_tables() } -table_map Item_direct_view_ref::used_tables() const +table_map Item_direct_view_ref::used_tables() const { - return get_depended_from() ? + return get_depended_from() ? OUTER_REF_TABLE_BIT : - (view->merged ? (*ref)->used_tables() : view->table->map); + ((view->merged || !view->table) ? + (*ref)->used_tables() : + view->table->map); } -table_map Item_direct_view_ref::not_null_tables() const +table_map Item_direct_view_ref::not_null_tables() const { - return get_depended_from() ? + return get_depended_from() ? 0 : - (view->merged ? (*ref)->not_null_tables() : view->table->map); + ((view->merged || !view->table) ? + (*ref)->not_null_tables() : + view->table->map); } /* diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6dd329f8c77..9c5d251c728 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7927,7 +7927,8 @@ bool setup_tables(THD *thd, Name_resolution_context *context, while ((table_list= ti++)) { TABLE *table= table_list->table; - table->pos_in_table_list= table_list; + if (table) + table->pos_in_table_list= table_list; if (first_select_table && table_list->top_table() == first_select_table) { @@ -7940,7 +7941,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, { table_list->jtbm_table_no= tablenr; } - else + else if (table) { table->pos_in_table_list= table_list; setup_table_map(table, table_list, tablenr); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 3ce375190a7..84e88196f20 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -68,7 +68,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (mysql_handle_list_of_derived(thd->lex, table_list, DT_PREPARE)) DBUG_RETURN(TRUE); - if (!table_list->updatable) + if (!table_list->single_table_updatable()) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE"); DBUG_RETURN(TRUE); @@ -526,7 +526,8 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) setup_conds(thd, table_list, select_lex->leaf_tables, conds) || setup_ftfuncs(select_lex)) DBUG_RETURN(TRUE); - if (!table_list->updatable || check_key_in_view(thd, table_list)) + if (!table_list->single_table_updatable() || + check_key_in_view(thd, table_list)) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE"); DBUG_RETURN(TRUE); @@ -622,7 +623,7 @@ int mysql_multi_delete_prepare(THD *thd) DBUG_RETURN(TRUE); } - if (!target_tbl->correspondent_table->updatable || + if (!target_tbl->correspondent_table->single_table_updatable() || check_key_in_view(thd, target_tbl->correspondent_table)) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 0955f9c0982..02a26254336 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -483,7 +483,7 @@ bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived) return mysql_derived_prepare(thd, lex, derived); if (!derived->is_multitable()) { - if (!derived->updatable) + if (!derived->single_table_updatable()) return derived->create_field_translation(thd); if (derived->merge_underlying_list) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index d01a594708e..a4943d5e13a 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -103,7 +103,8 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view); */ bool check_view_single_update(List &fields, List *values, - TABLE_LIST *view, table_map *map) + TABLE_LIST *view, table_map *map, + bool insert) { /* it is join view => we need to find the table for update */ List_iterator_fast it(fields); @@ -140,6 +141,14 @@ bool check_view_single_update(List &fields, List *values, */ tbl->table->insert_values= view->table->insert_values; view->table= tbl->table; + if (!tbl->single_table_updatable()) + { + if (insert) + my_error(ER_NON_INSERTABLE_TABLE, MYF(0), view->alias, "INSERT"); + else + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), view->alias, "UPDATE"); + return TRUE; + } *map= tables; return FALSE; @@ -184,7 +193,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, { TABLE *table= table_list->table; - if (!table_list->updatable) + if (!table_list->single_table_updatable()) { my_error(ER_NON_INSERTABLE_TABLE, MYF(0), table_list->alias, "INSERT"); return -1; @@ -260,7 +269,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, if (check_view_single_update(fields, fields_and_values_from_different_maps ? (List*) 0 : &values, - table_list, map)) + table_list, map, true)) return -1; table= table_list->table; } @@ -347,7 +356,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, if (insert_table_list->is_view() && insert_table_list->is_merged_derived() && check_view_single_update(update_fields, &update_values, - insert_table_list, map)) + insert_table_list, map, false)) return -1; if (table->timestamp_field) @@ -1159,7 +1168,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, bool insert_into_view= (table_list->view != 0); DBUG_ENTER("mysql_prepare_insert_check_table"); - if (!table_list->updatable) + if (!table_list->single_table_updatable()) { my_error(ER_NON_INSERTABLE_TABLE, MYF(0), table_list->alias, "INSERT"); DBUG_RETURN(TRUE); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 42a8f001c6f..7fcb52a7b9c 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -187,7 +187,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, INSERT_ACL | UPDATE_ACL, FALSE)) DBUG_RETURN(-1); if (!table_list->table || // do not suport join view - !table_list->updatable || // and derived tables + !table_list->single_table_updatable() || // and derived tables check_key_in_view(thd, table_list)) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "LOAD"); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 611c8ddf944..32ce8dc6fc4 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1274,7 +1274,7 @@ static int mysql_test_update(Prepared_statement *stmt, if (table_list->handle_derived(thd->lex, DT_PREPARE)) goto error; - if (!table_list->updatable) + if (!table_list->single_table_updatable()) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE"); goto error; @@ -1348,7 +1348,7 @@ static bool mysql_test_delete(Prepared_statement *stmt, if (mysql_handle_derived(thd->lex, DT_PREPARE)) goto error; - if (!table_list->updatable) + if (!table_list->single_table_updatable()) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE"); goto error; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 80eb823c346..a921a87884e 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -257,7 +257,7 @@ int mysql_update(THD *thd, thd_proc_info(thd, "init"); table= table_list->table; - if (!table_list->updatable) + if (!table_list->single_table_updatable()) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE"); DBUG_RETURN(1); @@ -1090,7 +1090,7 @@ reopen_tables: /* if table will be updated then check that it is unique */ if (table->map & tables_for_update) { - if (!tl->updatable || check_key_in_view(thd, tl)) + if (!tl->single_table_updatable() || check_key_in_view(thd, tl)) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), tl->alias, "UPDATE"); DBUG_RETURN(TRUE); diff --git a/sql/table.cc b/sql/table.cc index 5fe2d8afc42..f1ff353a8c4 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3712,6 +3712,28 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds, DBUG_RETURN(FALSE); } +/** + Check that table/view is updatable and if it has single + underlying tables/views it is also updatable + + @return Result of the check. +*/ + +bool TABLE_LIST::single_table_updatable() +{ + if (!updatable) + return false; + if (view_tables && view_tables->elements == 1) + { + /* + We need to check deeply only single table views. Multi-table views + will be turned to multi-table updates and then checked by leaf tables + */ + return view_tables->head()->single_table_updatable(); + } + return true; +} + /* Merge ON expressions for a view @@ -5185,6 +5207,9 @@ void st_table::mark_virtual_columns_for_write(bool insert_fl) Field **vfield_ptr, *tmp_vfield; bool bitmap_updated= FALSE; + if (!vfield) + return; + if (!vfield) return; diff --git a/sql/table.h b/sql/table.h index 376aa9824dc..09230e40f7a 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1797,6 +1797,9 @@ struct TABLE_LIST int fetch_number_of_rows(); bool change_refs_to_fields(); + + bool single_table_updatable(); + private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); From 74b61f845b26257e7f44a5bb602529b4cb7638a9 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Feb 2012 16:56:12 +0200 Subject: [PATCH 64/83] Fixed typos in Query Cache. --- sql/sql_cache.cc | 8 ++++---- sql/sql_cache.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 16b6d78576a..c45234f2cdf 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1452,10 +1452,10 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", In case the wait time can't be determined there is an upper limit which causes try_lock() to abort with a time out. - The 'TRUE' parameter indicate that the lock is allowed to timeout + The 'TIMEOUT' parameter indicate that the lock is allowed to timeout */ - if (try_lock(thd, Query_cache::WAIT)) + if (try_lock(thd, Query_cache::TIMEOUT)) DBUG_VOID_RETURN; if (query_cache_size == 0) { @@ -1781,9 +1781,9 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length) disabled or if a full cache flush is in progress, the attempt to get the lock is aborted. - The WAIT parameter indicate that the lock is allowed to timeout. + The TIMEOUT parameter indicate that the lock is allowed to timeout. */ - if (try_lock(thd, Query_cache::WAIT)) + if (try_lock(thd, Query_cache::TIMEOUT)) goto err; if (query_cache_size == 0) diff --git a/sql/sql_cache.h b/sql/sql_cache.h index eeaac8f6b62..b2e88a3c619 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -429,8 +429,8 @@ protected: uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE, uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE); - bool is_disabled(void) { return m_cache_status != OK; } - bool is_disable_in_progress(void) + inline bool is_disabled(void) { return m_cache_status != OK; } + inline bool is_disable_in_progress(void) { return m_cache_status == DISABLE_REQUEST; } /* initialize cache (mutex) */ From 3efc8d016f1e1fbc854a4698e1d06aba5fa2ec15 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 3 Feb 2012 12:49:17 -0800 Subject: [PATCH 65/83] Made mrr related counters temporarily invisible until we agree upon their names. --- mysql-test/r/myisam_mrr.result | 15 --------------- mysql-test/r/status.result | 8 +------- mysql-test/r/status_user.result | 3 --- sql/mysqld.cc | 3 +++ 4 files changed, 4 insertions(+), 25 deletions(-) diff --git a/mysql-test/r/myisam_mrr.result b/mysql-test/r/myisam_mrr.result index 4bb0e29a26e..c2f382eb9e6 100644 --- a/mysql-test/r/myisam_mrr.result +++ b/mysql-test/r/myisam_mrr.result @@ -563,9 +563,6 @@ drop table t1; flush status; show status like 'Handler_mrr%'; Variable_name Value -Handler_mrr_extra_key_sorts 0 -Handler_mrr_extra_rowid_sorts 0 -Handler_mrr_init 0 create table t0 (a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); create table t1 (a int, b int, filler char(200), key(a)); @@ -581,9 +578,6 @@ sum(b) 1230 show status like 'handler_mrr%'; Variable_name Value -Handler_mrr_extra_key_sorts 0 -Handler_mrr_extra_rowid_sorts 0 -Handler_mrr_init 1 set @mrr_buffer_size_save= @@mrr_buffer_size; set mrr_buffer_size=128; explain select sum(b) from t1 where a < 1600; @@ -596,9 +590,6 @@ sum(b) 196800 show status like 'handler_mrr%'; Variable_name Value -Handler_mrr_extra_key_sorts 0 -Handler_mrr_extra_rowid_sorts 1 -Handler_mrr_init 1 set @@mrr_buffer_size= @mrr_buffer_size_save; #Now, let's check BKA: set @join_cache_level_save= @@join_cache_level; @@ -614,9 +605,6 @@ sum(t1.b) 1230 show status like 'handler_mrr%'; Variable_name Value -Handler_mrr_extra_key_sorts 0 -Handler_mrr_extra_rowid_sorts 0 -Handler_mrr_init 1 set join_buffer_size=10; explain select sum(t1.b) from t0,t1 where t0.a=t1.a; id select_type table type possible_keys key key_len ref rows Extra @@ -628,9 +616,6 @@ sum(t1.b) 1230 show status like 'handler_mrr%'; Variable_name Value -Handler_mrr_extra_key_sorts 1or2 -Handler_mrr_extra_rowid_sorts 1or2 -Handler_mrr_init 1or2 set join_cache_level= @join_cache_level_save; set join_buffer_size= @join_buffer_size_save; drop table t0, t1; diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index c9602ddb8f6..b0744726390 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -275,9 +275,6 @@ Variable_name Value Handler_commit 0 Handler_delete 0 Handler_discover 0 -Handler_mrr_extra_key_sorts 0 -Handler_mrr_extra_rowid_sorts 0 -Handler_mrr_init 0 Handler_prepare 0 Handler_read_first 0 Handler_read_key 4 @@ -300,7 +297,7 @@ Created_tmp_files 0 Created_tmp_tables 2 Handler_tmp_update 2 Handler_tmp_write 7 -Rows_tmp_read 38 +Rows_tmp_read 35 drop table t1; CREATE TABLE t1 (i int(11) DEFAULT NULL, KEY i (i) ) ENGINE=MyISAM; insert into t1 values (1),(2),(3),(4),(5); @@ -313,9 +310,6 @@ Variable_name Value Handler_commit 0 Handler_delete 0 Handler_discover 0 -Handler_mrr_extra_key_sorts 0 -Handler_mrr_extra_rowid_sorts 0 -Handler_mrr_init 0 Handler_prepare 0 Handler_read_first 0 Handler_read_key 2 diff --git a/mysql-test/r/status_user.result b/mysql-test/r/status_user.result index 470c1625b55..17c44df1d3c 100644 --- a/mysql-test/r/status_user.result +++ b/mysql-test/r/status_user.result @@ -100,9 +100,6 @@ Variable_name Value Handler_commit 19 Handler_delete 1 Handler_discover 0 -Handler_mrr_extra_key_sorts 0 -Handler_mrr_extra_rowid_sorts 0 -Handler_mrr_init 0 Handler_prepare 18 Handler_read_first 0 Handler_read_key 3 diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7a701217bb0..109d0220a4a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8284,9 +8284,12 @@ SHOW_VAR status_vars[]= { {"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS}, {"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS}, {"Handler_discover", (char*) offsetof(STATUS_VAR, ha_discover_count), SHOW_LONG_STATUS}, +#if 0 + /* Made 3 counters below temporarily invisible until we agree upon their names */ {"Handler_mrr_extra_key_sorts", (char*) offsetof(STATUS_VAR, ha_mrr_extra_key_sorts), SHOW_LONG_STATUS}, {"Handler_mrr_extra_rowid_sorts", (char*) offsetof(STATUS_VAR, ha_mrr_extra_rowid_sorts), SHOW_LONG_STATUS}, {"Handler_mrr_init", (char*) offsetof(STATUS_VAR, ha_multi_range_read_init_count), SHOW_LONG_STATUS}, +#endif {"Handler_prepare", (char*) offsetof(STATUS_VAR, ha_prepare_count), SHOW_LONG_STATUS}, {"Handler_read_first", (char*) offsetof(STATUS_VAR, ha_read_first_count), SHOW_LONG_STATUS}, {"Handler_read_key", (char*) offsetof(STATUS_VAR, ha_read_key_count), SHOW_LONG_STATUS}, From a03d8465769974e0254e4e4acb8aa59617453f9f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Feb 2012 21:55:40 +0100 Subject: [PATCH 66/83] Fix memory leak when one +O debug on top of another. --- dbug/dbug.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dbug/dbug.c b/dbug/dbug.c index 8b3927d2427..cac544b6cd3 100644 --- a/dbug/dbug.c +++ b/dbug/dbug.c @@ -1863,6 +1863,8 @@ static void DBUGOpenFile(CODE_STATE *cs, name=cs->stack->name; if (strcmp(name, "-") == 0) { + if (!is_shared(cs->stack, out_file)) + DBUGCloseFile(cs, cs->stack->out_file); cs->stack->out_file= stdout; cs->stack->flags |= FLUSH_ON_WRITE; cs->stack->name[0]=0; @@ -1885,6 +1887,8 @@ static void DBUGOpenFile(CODE_STATE *cs, } else { + if (!is_shared(cs->stack, out_file)) + DBUGCloseFile(cs, cs->stack->out_file); cs->stack->out_file= fp; } } From 6e9b06d90bd8a833d7daf3dbc9927a36ba2137e5 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2012 13:10:47 +0100 Subject: [PATCH 67/83] Fix a number of problems in the test suite (no code bugs): - mysql-test-run.pl --valgrind complains when all tests succeed. - perfschema.all_instances fail on non-linux, where ENABLE_TEMP_POOL is not set and therefore BITMAP mutex is not used. - MDEV-132: main.mysqldump fails because it depends on exact size of stdio buffers. - MDEV-99: rpl.rpl_cant_read_event_incident fails due to a race where the slave manages to connect while the test case is in the middle of setting up the master, causing the slave to replicate extra/wrong events. - MDEV-133: rpl.rpl_rotate_purge_deadlock fails because it issues a DEBUG_SYNC SIGNAL immediately followed by RESET; this means that sometimes the intended receipient has no time to see the signal before it is cleared by the RESET, causing wait to timeout. --- mysql-test/mysql-test-run.pl | 4 +- mysql-test/r/mysqldump.result | 68 ------------------- .../suite/perfschema/r/all_instances.result | 6 +- .../suite/perfschema/t/all_instances.test | 5 +- .../rpl/r/rpl_cant_read_event_incident.result | 2 +- .../rpl/r/rpl_rotate_purge_deadlock.result | 4 ++ .../rpl/t/rpl_cant_read_event_incident.test | 9 ++- .../rpl/t/rpl_rotate_purge_deadlock.test | 4 ++ mysql-test/t/mysqldump.test | 6 +- sql/log.cc | 1 + 10 files changed, 33 insertions(+), 76 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index aa7da22d20c..76ea349cd83 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -584,6 +584,7 @@ sub main { } mtr_report_test($tinfo); push @$completed, $tinfo; + ++$num_tests } mtr_print_line(); @@ -599,7 +600,8 @@ sub main { if ( @$completed != $num_tests) { - mtr_error("Not all tests completed"); + mtr_error("Not all tests completed (only ". scalar(@$completed) . + " of $num_tests)"); } remove_vardir_subs() if $opt_clean_vardir; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 022523d4749..3db422657e3 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -4770,79 +4770,11 @@ INSERT INTO b12809202_db.t2 VALUES (1), (2), (3); -- Retrieving table structure for table t1... -- Sending SELECT query... -- Retrieving rows... --- --- Host: localhost Database: b12809202_db --- ------------------------------------------------------ - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; -/*!40103 SET TIME_ZONE='+00:00' */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - --- --- Table structure for table `t1` --- - -DROP TABLE IF EXISTS `t1`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `t1` ( - `c1` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `t1` --- - -LOCK TABLES `t1` WRITE; -/*!40000 ALTER TABLE `t1` DISABLE KEYS */; -INSERT INTO `t1` VALUES (1),(2),(3); -- Retrieving table structure for table t2... -- Sending SELECT query... -- Retrieving rows... -/*!40000 ALTER TABLE `t1` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `t2` --- - -DROP TABLE IF EXISTS `t2`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `t2` ( - `c1` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `t2` --- - -LOCK TABLES `t2` WRITE; -/*!40000 ALTER TABLE `t2` DISABLE KEYS */; -INSERT INTO `t2` VALUES (1),(2),(3); -/*!40000 ALTER TABLE `t2` ENABLE KEYS */; -UNLOCK TABLES; -- Disconnecting from localhost... -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - --- Dump completed #### Dump ends here #### DROP TABLE b12809202_db.t1; DROP TABLE b12809202_db.t2; diff --git a/mysql-test/suite/perfschema/r/all_instances.result b/mysql-test/suite/perfschema/r/all_instances.result index 7eb2bc73d8e..dedaf9612a9 100644 --- a/mysql-test/suite/perfschema/r/all_instances.result +++ b/mysql-test/suite/perfschema/r/all_instances.result @@ -1,5 +1,8 @@ use performance_schema; -select name from mutex_instances where name not rlike '/(DEBUG_SYNC::mutex)$' group by name; +select name from mutex_instances +where name not rlike '/(DEBUG_SYNC::mutex)$' + and name != 'wait/synch/mutex/mysys/BITMAP::mutex' + group by name; name wait/synch/mutex/archive/archive_mutex wait/synch/mutex/aria/LOCK_trn_list @@ -16,7 +19,6 @@ wait/synch/mutex/blackhole/blackhole wait/synch/mutex/csv/tina wait/synch/mutex/memory/HP_SHARE::intern_lock wait/synch/mutex/myisam/MYISAM_SHARE::intern_lock -wait/synch/mutex/mysys/BITMAP::mutex wait/synch/mutex/mysys/KEY_CACHE::cache_lock wait/synch/mutex/mysys/LOCK_alarm wait/synch/mutex/mysys/LOCK_uuid_generator diff --git a/mysql-test/suite/perfschema/t/all_instances.test b/mysql-test/suite/perfschema/t/all_instances.test index 46b2c06c327..1119f523829 100644 --- a/mysql-test/suite/perfschema/t/all_instances.test +++ b/mysql-test/suite/perfschema/t/all_instances.test @@ -17,7 +17,10 @@ use performance_schema; # "where" filters out instances that can be conditionally compiled out # -select name from mutex_instances where name not rlike '/(DEBUG_SYNC::mutex)$' group by name; +select name from mutex_instances + where name not rlike '/(DEBUG_SYNC::mutex)$' + and name != 'wait/synch/mutex/mysys/BITMAP::mutex' + group by name; # CRYPTO_dynlock_value::lock exists only when building with OpenSSL (not YaSSL). select name from rwlock_instances where name not in ("wait/synch/rwlock/sql/CRYPTO_dynlock_value::lock") diff --git a/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result b/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result index 1bee6f2ec1a..8a4de852617 100644 --- a/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result +++ b/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result @@ -1,12 +1,12 @@ include/master-slave.inc [connection master] +include/stop_slave.inc call mtr.add_suppression("Error in Log_event::read_log_event()"); include/rpl_stop_server.inc [server_number=1] include/rpl_start_server.inc [server_number=1] show binlog events; ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Wrong offset or I/O error call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log"); -stop slave; reset slave; start slave; include/wait_for_slave_param.inc [Last_IO_Errno] diff --git a/mysql-test/suite/rpl/r/rpl_rotate_purge_deadlock.result b/mysql-test/suite/rpl/r/rpl_rotate_purge_deadlock.result index 34024f89617..1bda3bd3ee1 100644 --- a/mysql-test/suite/rpl/r/rpl_rotate_purge_deadlock.result +++ b/mysql-test/suite/rpl/r/rpl_rotate_purge_deadlock.result @@ -5,6 +5,7 @@ Log_name File_size master-bin.000001 # create table t1 (f text) engine=innodb; SET DEBUG_SYNC = 'at_purge_logs_before_date WAIT_FOR rotated'; +SET DEBUG_SYNC = 'after_purge_logs_before_date SIGNAL continued'; insert into t1 set f=repeat('a', 4096); *** there must be two logs in the list *** show binary logs; @@ -19,11 +20,14 @@ master-bin.000001 # master-bin.000002 # master-bin.000003 # SET DEBUG_SYNC = 'now SIGNAL rotated'; +SET DEBUG_SYNC = 'now WAIT_FOR continued'; SET DEBUG_SYNC = 'RESET'; SET DEBUG_SYNC = 'RESET'; SET DEBUG_SYNC = 'at_purge_logs_before_date WAIT_FOR rotated'; +SET DEBUG_SYNC = 'after_purge_logs_before_date SIGNAL continued'; insert into t1 set f=repeat('b', 4096); SET DEBUG_SYNC = 'now SIGNAL rotated'; +SET DEBUG_SYNC = 'now WAIT_FOR continued'; SET DEBUG_SYNC = 'RESET'; SET DEBUG_SYNC = 'RESET'; drop table t1; diff --git a/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test b/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test index 5e88b163d99..9789079bde6 100644 --- a/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test +++ b/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test @@ -20,9 +20,15 @@ # --source include/not_windows.inc -call mtr.add_suppression("Error in Log_event::read_log_event()"); +--connection slave +# Make sure the slave is stopped while we are messing with master. +# Otherwise we get occasional failures as the slave manages to re-connect +# to the newly started master and we get extra events applied, causing +# conflicts. +--source include/stop_slave.inc --connection master +call mtr.add_suppression("Error in Log_event::read_log_event()"); --let $datadir= `SELECT @@datadir` --let $rpl_server_number= 1 @@ -42,7 +48,6 @@ show binlog events; --connection slave call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log"); -stop slave; reset slave; start slave; diff --git a/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock.test b/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock.test index 429612c405f..a63844b451c 100644 --- a/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock.test +++ b/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock.test @@ -20,6 +20,7 @@ connection master; source include/show_binary_logs.inc; create table t1 (f text) engine=innodb; SET DEBUG_SYNC = 'at_purge_logs_before_date WAIT_FOR rotated'; +SET DEBUG_SYNC = 'after_purge_logs_before_date SIGNAL continued'; send insert into t1 set f=repeat('a', 4096); connection master1; @@ -38,6 +39,7 @@ insert into t1 set f=repeat('b', 4096); source include/show_binary_logs.inc; SET DEBUG_SYNC = 'now SIGNAL rotated'; +SET DEBUG_SYNC = 'now WAIT_FOR continued'; SET DEBUG_SYNC = 'RESET'; # the first connection finally completes its INSERT @@ -54,6 +56,7 @@ sync_slave_with_master; connection master; SET DEBUG_SYNC = 'at_purge_logs_before_date WAIT_FOR rotated'; +SET DEBUG_SYNC = 'after_purge_logs_before_date SIGNAL continued'; send insert into t1 set f=repeat('b', 4096); connection master1; @@ -80,6 +83,7 @@ let $wait_condition= --source include/wait_condition.inc SET DEBUG_SYNC = 'now SIGNAL rotated'; +SET DEBUG_SYNC = 'now WAIT_FOR continued'; SET DEBUG_SYNC = 'RESET'; connection master; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 302d79b6b13..424dd35a819 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -2249,8 +2249,12 @@ INSERT INTO b12809202_db.t2 VALUES (1), (2), (3); --echo # commit starting 5.5. --echo --echo #### Dump starts here #### +# We only need to check the --verbose output to verify that "start transaction" +# happens after "logs flushed". We redirect normal output, as otherwise the +# mixing of normal (stdout) and --verbose (stderr) output will happen in random +# order depending on stdio internal buffer size. --replace_regex /-- Server version.*// /-- MySQL dump .*// /-- Dump completed on .*/-- Dump completed/ ---exec $MYSQL_DUMP --verbose --single-transaction --flush-log b12809202_db 2>&1 +--exec $MYSQL_DUMP --verbose --single-transaction --flush-log b12809202_db 2>&1 > $MYSQLTEST_VARDIR/tmp/bug61854.sql --echo --echo #### Dump ends here #### diff --git a/sql/log.cc b/sql/log.cc index af400c19f4a..9e9716dde67 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -5372,6 +5372,7 @@ void MYSQL_BIN_LOG::purge() { purge_logs_before_date(purge_time); } + DEBUG_SYNC(current_thd, "after_purge_logs_before_date"); } #endif } From f6cdddf51f385fd7dd9afe286f3bdce0b7e59f60 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Feb 2012 23:35:26 +0200 Subject: [PATCH 68/83] Test case for bug lp:905353 The bug itself is fixed by the patch for bug lp:908269. --- mysql-test/r/subselect.result | 9 +++++++++ mysql-test/r/subselect_no_mat.result | 9 +++++++++ mysql-test/r/subselect_no_opts.result | 9 +++++++++ mysql-test/r/subselect_no_scache.result | 9 +++++++++ mysql-test/r/subselect_no_semijoin.result | 9 +++++++++ mysql-test/t/subselect.test | 11 +++++++++++ 6 files changed, 56 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 47dcafc663b..bca4eb677de 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5994,5 +5994,14 @@ SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1; 1 NULL drop table t1,t2,t3; +# +# LP BUG#905353 Wrong non-empty result with a constant table, +# aggregate function in subquery, MyISAM or Aria +# +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); +SELECT a FROM t1 WHERE ( SELECT MIN(a) = 100 ); +a +drop table t1; # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index ea832b7f7ce..bcd08b70517 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -5993,6 +5993,15 @@ SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1; 1 NULL drop table t1,t2,t3; +# +# LP BUG#905353 Wrong non-empty result with a constant table, +# aggregate function in subquery, MyISAM or Aria +# +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); +SELECT a FROM t1 WHERE ( SELECT MIN(a) = 100 ); +a +drop table t1; # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; set optimizer_switch=default; diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index f86955eadcd..a493722fabe 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -5989,6 +5989,15 @@ SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1; 1 NULL drop table t1,t2,t3; +# +# LP BUG#905353 Wrong non-empty result with a constant table, +# aggregate function in subquery, MyISAM or Aria +# +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); +SELECT a FROM t1 WHERE ( SELECT MIN(a) = 100 ); +a +drop table t1; # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; set @optimizer_switch_for_subselect_test=null; diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index fa8342da223..e170debd6d2 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -6000,6 +6000,15 @@ SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1; 1 NULL drop table t1,t2,t3; +# +# LP BUG#905353 Wrong non-empty result with a constant table, +# aggregate function in subquery, MyISAM or Aria +# +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); +SELECT a FROM t1 WHERE ( SELECT MIN(a) = 100 ); +a +drop table t1; # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; set optimizer_switch=default; diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 985f840f7c2..782aba08d26 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -5989,6 +5989,15 @@ SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1; 1 NULL drop table t1,t2,t3; +# +# LP BUG#905353 Wrong non-empty result with a constant table, +# aggregate function in subquery, MyISAM or Aria +# +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); +SELECT a FROM t1 WHERE ( SELECT MIN(a) = 100 ); +a +drop table t1; # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; set @optimizer_switch_for_subselect_test=null; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index b4e79416c40..e9735dae79f 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -5078,6 +5078,17 @@ SELECT ( SELECT b FROM t2 WHERE b = a OR rand() * 0) FROM t1; drop table t1,t2,t3; +--echo # +--echo # LP BUG#905353 Wrong non-empty result with a constant table, +--echo # aggregate function in subquery, MyISAM or Aria +--echo # + +CREATE TABLE t1 ( a INT ) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); + +SELECT a FROM t1 WHERE ( SELECT MIN(a) = 100 ); + +drop table t1; --echo # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; From 804c69ab835eb13f892fbaf1766f923e19ce7d6e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Feb 2012 16:23:18 +0200 Subject: [PATCH 69/83] Fix set_limit to be uniform with all calls. Fix of set_limit in case of an error (actually impossible case but better it will be right) --- sql/sql_derived.cc | 4 ++-- sql/sql_lex.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 13985becff7..63c5bb30474 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -750,7 +750,7 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived) if (!derived->is_merged_derived()) { JOIN *join= first_select->join; - unit->set_limit(first_select); + unit->set_limit(unit->global_parameters); unit->optimized= TRUE; if ((res= join->optimize())) goto err; @@ -865,7 +865,7 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) } else { - unit->set_limit(first_select); + unit->set_limit(unit->global_parameters); if (unit->select_limit_cnt == HA_POS_ERROR) first_select->options&= ~OPTION_FOUND_ROWS; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 04de1325480..9b5c1c0de37 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2847,7 +2847,7 @@ void st_select_lex_unit::set_limit(st_select_lex *sl) DBUG_ASSERT(fix_fields_successful); } - val= fix_fields_successful ? item->val_uint() : HA_POS_ERROR; + val= fix_fields_successful ? item->val_uint() : 0; } else val= ULL(0); From 3d61c1399dc74e651030418730da429ee0b4e38a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Feb 2012 21:19:12 +0100 Subject: [PATCH 70/83] lp:910817: Race condition in kill_threads_for_user() The code was accessing a pointer in a mem_root that might be freed by another concurrent thread. Fix by moving the access to be done while the LOCK_thd_data is held, preventing the memory from being freed too early. --- sql/sql_parse.cc | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1676d4a09f4..ef0f784e945 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7363,13 +7363,23 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user, if (!threads_to_kill.is_empty()) { List_iterator_fast it(threads_to_kill); - THD *ptr; - while ((ptr= it++)) + THD *next_ptr; + THD *ptr= it++; + do { ptr->awake(kill_signal); + /* + Careful here: The list nodes are allocated on the memroots of the + THDs to be awakened. + But those THDs may be terminated and deleted as soon as we release + LOCK_thd_data, which will make the list nodes invalid. + Since the operation "it++" dereferences the "next" pointer of the + previous list node, we need to do this while holding LOCK_thd_data. + */ + next_ptr= it++; pthread_mutex_unlock(&ptr->LOCK_thd_data); (*rows)++; - } + } while ((ptr= next_ptr)); } DBUG_RETURN(0); } From ea45d770af35e95becc83872bcc7c86b2698550f Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 10 Feb 2012 22:53:46 +0200 Subject: [PATCH 71/83] Fixed that prepared statements are properly igored (if possible) by query cache. --- sql/sql_cache.cc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index c45234f2cdf..fbe42c85711 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1659,6 +1659,17 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length) if (is_disabled() || thd->locked_tables || thd->variables.query_cache_type == 0) goto err; + + /* + The following can only happen for prepared statements that was found + during parsing or later that the query was not cacheable. + */ + if (!thd->lex->safe_to_cache_query) + { + DBUG_PRINT("qcache", ("SELECT is non-cacheable")); + goto err; + } + DBUG_ASSERT(query_cache_size != 0); // otherwise cache would be disabled thd->query_cache_is_applicable= 1; @@ -1950,6 +1961,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", faster. */ thd->query_cache_is_applicable= 0; // Query can't be cached + thd->lex->safe_to_cache_query= 0; // For prepared statements BLOCK_UNLOCK_RD(query_block); DBUG_RETURN(-1); } @@ -1966,6 +1978,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", table_list.db, table_list.alias)); unlock(); thd->query_cache_is_applicable= 0; // Query can't be cached + thd->lex->safe_to_cache_query= 0; // For prepared statements BLOCK_UNLOCK_RD(query_block); DBUG_RETURN(-1); // Privilege error } @@ -1975,6 +1988,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", table_list.db, table_list.alias)); BLOCK_UNLOCK_RD(query_block); thd->query_cache_is_applicable= 0; // Query can't be cached + thd->lex->safe_to_cache_query= 0; // For prepared statements goto err_unlock; // Parse query } #endif /*!NO_EMBEDDED_ACCESS_CHECKS*/ @@ -1998,7 +2012,13 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", table->key_length()); } else + { + /* + As this can change from call to call, don't reset set + thd->lex->safe_to_cache_query + */ thd->query_cache_is_applicable= 0; // Query can't be cached + } goto err_unlock; // Parse query } else @@ -3886,6 +3906,7 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used, DBUG_PRINT("qcache", ("Don't cache statement as it refers to " "tables with column privileges.")); thd->query_cache_is_applicable= 0; // Query can't be cached + thd->lex->safe_to_cache_query= 0; // For prepared statements DBUG_RETURN(0); } #endif @@ -4022,6 +4043,10 @@ my_bool Query_cache::ask_handler_allowance(THD *thd, { DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s", tables_used->db, tables_used->alias)); + /* + As this can change from call to call, don't reset set + thd->lex->safe_to_cache_query + */ thd->query_cache_is_applicable= 0; // Query can't be cached DBUG_RETURN(1); } From b3e15f838955217125476130766551731f1eaa4c Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sat, 11 Feb 2012 03:25:49 +0100 Subject: [PATCH 72/83] A recent change in the server protocol code broke SSL connection for some client libraries. Protocol documentation (http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol) says that initial packet sent by client if client wants SSL, consists of client capability flags only (4 bytes or 2 bytes edependent on protocol versionl). Some clients happen to send more in the initial SSL packet (C client, Python connector), while others (Java, .NET) follow the docs and send only client capability flags. A change that broke Java client was a newly introduced check that frst client packet has 32 or more bytes. This is generally wrong, if client capability flags contains CLIENT_SSL. Also, fixed the code such that read max client packet size and charset in the first packet prior to SSL handshake. With SSL, clients do not have to send this info, they can only send client flags. This is now fixed such that max packet size and charset are not read prior to SSL handshake, in case of SSL they are read from the "complete" client authentication packet after SSL initialization. --- sql/sql_connect.cc | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 7dd15ea731f..13e3a823103 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -810,25 +810,12 @@ static int check_connection(THD *thd) thd->client_capabilities= uint2korr(net->read_pos); if (thd->client_capabilities & CLIENT_PROTOCOL_41) { - if (pkt_len < 32) + if (pkt_len < 4) goto error; thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16; - thd->max_client_packet_length= uint4korr(net->read_pos+4); - DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); - if (thd_init_client_charset(thd, (uint) net->read_pos[8])) - return 1; - thd->update_charset(); - end= (char*) net->read_pos+32; } - else - { - if (pkt_len < 5) - goto error; - thd->max_client_packet_length= uint3korr(net->read_pos+2); - end= (char*) net->read_pos+5; - } /* Disable those bits which are not supported by the server. This is a precautionary measure, if the client lies. See Bug#27944. @@ -861,6 +848,26 @@ static int check_connection(THD *thd) } } #endif /* HAVE_OPENSSL */ + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + if (pkt_len < 32) + goto error; + + thd->max_client_packet_length= uint4korr(net->read_pos+4); + DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); + if (thd_init_client_charset(thd, (uint) net->read_pos[8])) + return 1; + thd->update_charset(); + end= (char*) net->read_pos+32; + } + else + { + if (pkt_len < 5) + goto error; + + thd->max_client_packet_length= uint3korr(net->read_pos+2); + end= (char*) net->read_pos+5; + } if (end >= (char*) net->read_pos+ pkt_len +2) goto error; From bc2c40e71bf3f97fb5013256ff05551b6c3daee5 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 11 Feb 2012 13:32:36 +0100 Subject: [PATCH 73/83] Fix _another_ race in test case rpl_cant_read_event_incident (seen in 5.5 Buildbot). --- .../suite/rpl/r/rpl_cant_read_event_incident.result | 2 +- mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result b/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result index 8a4de852617..bcae1c2c62b 100644 --- a/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result +++ b/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result @@ -15,5 +15,5 @@ Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary reset master; stop slave; reset slave; -drop table t; +drop table if exists t; End of the tests diff --git a/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test b/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test index 9789079bde6..7d05ce251f2 100644 --- a/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test +++ b/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test @@ -69,6 +69,12 @@ reset master; --connection slave stop slave; reset slave; -drop table t; # table was created from binlog. it does not exist on master. +# The table t may have been created on the slave from binlog. It does not exist +# on the master. +# "May", as it depends on whether the SQL thread had time do do the CREATE +# TABLE before we stopped. +--disable_warnings +drop table if exists t; +--enable_warnings --echo End of the tests From 0c265a5eb8962fba6f0be90946ec8af11b44af45 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sun, 12 Feb 2012 23:02:56 +0100 Subject: [PATCH 74/83] Use newly released HeidiSQL 7.0 in the MSI installer --- win/packaging/heidisql.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/packaging/heidisql.cmake b/win/packaging/heidisql.cmake index 94a287cba08..f826c9a6633 100644 --- a/win/packaging/heidisql.cmake +++ b/win/packaging/heidisql.cmake @@ -1,4 +1,4 @@ -SET(HEIDISQL_BASE_NAME "HeidiSQL_6.0_Portable") +SET(HEIDISQL_BASE_NAME "HeidiSQL_7.0_Portable") SET(HEIDISQL_ZIP "${HEIDISQL_BASE_NAME}.zip") SET(HEIDISQL_URL "http://heidisql.googlecode.com/files/${HEIDISQL_ZIP}") SET(HEIDISQL_DOWNLOAD_DIR ${THIRD_PARTY_DOWNLOAD_LOCATION}/${HEIDISQL_BASE_NAME}) From 27dfa45e7026f6b632863a37b7dece8ecd480b47 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 13 Feb 2012 17:14:10 +0100 Subject: [PATCH 75/83] When we fail during slave thread initialisation, keep mi->run_lock locked until we have finished clean up. Previously, the code released the lock without marking that the thread was running. This allowed a new slave thread to start while the old one was still in the middle of cleaning up, causing assertions and probably general mayhem. --- sql/slave.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sql/slave.cc b/sql/slave.cc index 363c1eb9a17..7935754e25c 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2683,9 +2683,8 @@ pthread_handler_t handle_slave_io(void *arg) if (init_slave_thread(thd, SLAVE_THD_IO)) { pthread_cond_broadcast(&mi->start_cond); - pthread_mutex_unlock(&mi->run_lock); sql_print_error("Failed during slave I/O thread initialization"); - goto err; + goto err_during_init; } pthread_mutex_lock(&LOCK_thread_count); threads.append(thd); @@ -2953,6 +2952,7 @@ err: thd_proc_info(thd, "Waiting for slave mutex on exit"); pthread_mutex_lock(&mi->run_lock); +err_during_init: /* Forget the relay log's format */ delete mi->rli.relay_log.description_event_for_queue; mi->rli.relay_log.description_event_for_queue= 0; @@ -3076,10 +3076,9 @@ pthread_handler_t handle_slave_sql(void *arg) will be stuck if we fail here */ pthread_cond_broadcast(&rli->start_cond); - pthread_mutex_unlock(&rli->run_lock); rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, "Failed during slave thread initialization"); - goto err; + goto err_during_init; } thd->init_for_queries(); thd->temporary_tables = rli->save_temporary_tables; // restore temp tables @@ -3332,6 +3331,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ thd->reset_db(NULL, 0); thd_proc_info(thd, "Waiting for slave mutex on exit"); pthread_mutex_lock(&rli->run_lock); +err_during_init: /* We need data_lock, at least to wake up any waiting master_pos_wait() */ pthread_mutex_lock(&rli->data_lock); DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun From c8bbe06ac7fd536b3e756afc0e2e8c8dc0724119 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Mon, 13 Feb 2012 23:46:57 -0800 Subject: [PATCH 76/83] Fixed LP bug #925985. If the flag 'optimize_join_buffer_size' is set to 'off' and the value of the system variable 'join_buffer_size' is greater than the value of the system variable 'join_buffer_space_limit' than no join cache can be employed to join tables of the executed query. A bug in the function JOIN_CACHE::alloc_buffer allowed to use join buffer even in this case while another bug in the function revise_cache_usage could cause a crash of the server in this case if the chosen execution plan for the query contained outer join or semi-join operation. --- mysql-test/r/join_cache.result | 35 ++++++++++++++++++++++++++++++++++ mysql-test/t/join_cache.test | 35 ++++++++++++++++++++++++++++++++++ sql/sql_join_cache.cc | 2 ++ sql/sql_select.cc | 4 ++-- 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index 11114a032f9..dda0f4c8f66 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5534,4 +5534,39 @@ we set join_cache_level = default; set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +# +# Bug #925985: LEFT JOIN with optimize_join_buffer_size=off + +# join_buffer_size > join_buffer_space_limit +# +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (5), (3); +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES +(3,30), (1,10), (7,70), (2,20), +(3,31), (1,11), (7,71), (2,21), +(3,32), (1,12), (7,72), (2,22); +CREATE TABLE t3 (b int, c int); +INSERT INTO t3 VALUES (32, 302), (42,400), (30,300); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='optimize_join_buffer_size=off'; +set join_buffer_space_limit=4096; +set join_buffer_size=4096*2; +set join_cache_level=2; +set optimizer_switch='outer_join_with_cache=on'; +EXPLAIN +SELECT * FROM t1, t2 LEFT JOIN t3 ON t2.b=t3.b WHERE t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +1 SIMPLE t2 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t3 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (incremental, BNL join) +SELECT * FROM t1, t2 LEFT JOIN t3 ON t2.b=t3.b WHERE t1.a=t2.a; +a a b b c +3 3 30 30 300 +3 3 31 NULL NULL +3 3 32 32 302 +set join_buffer_space_limit=default; +set join_buffer_size=default; +set join_cache_level=default; +set optimizer_switch=@tmp_optimizer_switch; +DROP TABLE t1,t2,t3; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index 8a61c00b7d4..9d7b07f6b9e 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -3547,5 +3547,40 @@ set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +--echo # +--echo # Bug #925985: LEFT JOIN with optimize_join_buffer_size=off + +--echo # join_buffer_size > join_buffer_space_limit +--echo # + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (5), (3); + +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES + (3,30), (1,10), (7,70), (2,20), + (3,31), (1,11), (7,71), (2,21), + (3,32), (1,12), (7,72), (2,22); + +CREATE TABLE t3 (b int, c int); +INSERT INTO t3 VALUES (32, 302), (42,400), (30,300); + +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='optimize_join_buffer_size=off'; +set join_buffer_space_limit=4096; +set join_buffer_size=4096*2; +set join_cache_level=2; +set optimizer_switch='outer_join_with_cache=on'; + +EXPLAIN +SELECT * FROM t1, t2 LEFT JOIN t3 ON t2.b=t3.b WHERE t1.a=t2.a; +SELECT * FROM t1, t2 LEFT JOIN t3 ON t2.b=t3.b WHERE t1.a=t2.a; + +set join_buffer_space_limit=default; +set join_buffer_size=default; +set join_cache_level=default; +set optimizer_switch=@tmp_optimizer_switch; + +DROP TABLE t1,t2,t3; + # this must be the last command in the file set @@optimizer_switch=@save_optimizer_switch; diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index 2a8db8b4fd1..78f95a7ac7e 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -898,6 +898,8 @@ int JOIN_CACHE::alloc_buffer() curr_buff_space_sz+= cache->get_join_buffer_size(); } } + curr_min_buff_space_sz+= min_buff_size; + curr_buff_space_sz+= buff_size; if (curr_min_buff_space_sz > join_buff_space_limit || (curr_buff_space_sz > join_buff_space_limit && diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 05fba45792b..aa1090fb03b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8903,7 +8903,7 @@ void revise_cache_usage(JOIN_TAB *join_tab) first_inner; first_inner= first_inner->first_upper) { - for (tab= end_tab-1; tab >= first_inner; tab--) + for (tab= end_tab; tab >= first_inner; tab--) set_join_cache_denial(tab); end_tab= first_inner; } @@ -8911,7 +8911,7 @@ void revise_cache_usage(JOIN_TAB *join_tab) else if (join_tab->first_sj_inner_tab) { first_inner= join_tab->first_sj_inner_tab; - for (tab= join_tab-1; tab >= first_inner; tab--) + for (tab= join_tab; tab >= first_inner; tab--) { set_join_cache_denial(tab); } From c9355dc279ac30cc41ff076d20414fd59c36091d Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 14 Feb 2012 13:58:57 +0400 Subject: [PATCH 77/83] BUG#928048: Query containing IN subquery with OR in the where clause returns a wrong result - Make equality propagation work correctly when done inside the OR branches --- mysql-test/r/subselect_mat.result | 17 +++++++++++++++++ mysql-test/r/subselect_sj_mat.result | 18 ++++++++++++++++++ mysql-test/t/subselect_sj_mat.test | 17 +++++++++++++++++ sql/sql_select.cc | 7 ++++--- 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 009510276b5..6f90cc868a6 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -1831,6 +1831,23 @@ id select_type table type possible_keys key key_len ref rows Extra 3 MATERIALIZED alias3 ALL NULL NULL NULL NULL 2 3 MATERIALIZED alias4 index c c 11 NULL 2 Using where; Using index; Using join buffer (flat, BNL join) DROP TABLE t1,t2; +# +# BUG#928048: Query containing IN subquery with OR in the where clause returns a wrong result +# +create table t1 (a int, b int); +insert into t1 values (7,5), (3,3), (5,4), (9,3); +create table t2 (a int, b int, index i_a(a)); +insert into t2 values +(4,2), (7,9), (7,4), (3,1), (5,3), (3,1), (9,4), (8,1); +explain select * from t1 where t1.a in (select a from t2 where t2.a=7 or t2.b<=1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where +2 MATERIALIZED t2 ALL i_a NULL NULL NULL 8 Using where +select * from t1 where t1.a in (select a from t2 where t2.a=7 or t2.b<=1); +a b +7 5 +3 3 +drop table t1,t2; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; set join_cache_level=@save_join_cache_level; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 44fb9c61f24..964df6735f8 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -1867,6 +1867,24 @@ WHERE alias4.c = alias3.b id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables DROP TABLE t1,t2; +# +# BUG#928048: Query containing IN subquery with OR in the where clause returns a wrong result +# +create table t1 (a int, b int); +insert into t1 values (7,5), (3,3), (5,4), (9,3); +create table t2 (a int, b int, index i_a(a)); +insert into t2 values +(4,2), (7,9), (7,4), (3,1), (5,3), (3,1), (9,4), (8,1); +explain select * from t1 where t1.a in (select a from t2 where t2.a=7 or t2.b<=1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 +1 PRIMARY eq_ref distinct_key distinct_key 5 func 1 +2 MATERIALIZED t2 ALL i_a NULL NULL NULL 8 Using where +select * from t1 where t1.a in (select a from t2 where t2.a=7 or t2.b<=1); +a b +7 5 +3 3 +drop table t1,t2; # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; set join_cache_level=@save_join_cache_level; diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index 80ba42e7bab..0840029c5e0 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -1529,6 +1529,23 @@ WHERE b = a AND a IN ( DROP TABLE t1,t2; +--echo # +--echo # BUG#928048: Query containing IN subquery with OR in the where clause returns a wrong result +--echo # +create table t1 (a int, b int); +insert into t1 values (7,5), (3,3), (5,4), (9,3); + +create table t2 (a int, b int, index i_a(a)); + +insert into t2 values + (4,2), (7,9), (7,4), (3,1), (5,3), (3,1), (9,4), (8,1); + +explain select * from t1 where t1.a in (select a from t2 where t2.a=7 or t2.b<=1); +select * from t1 where t1.a in (select a from t2 where t2.a=7 or t2.b<=1); + +drop table t1,t2; + + --echo # This must be at the end: set optimizer_switch=@subselect_sj_mat_tmp; set join_cache_level=@save_join_cache_level; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 05fba45792b..292ed9439e4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11490,7 +11490,7 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, } /* - Check if "item_field=head" equality is already guaranteed to be true + Check if "field_item=head" equality is already guaranteed to be true on upper AND-levels. */ if (upper) @@ -11502,7 +11502,8 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, Item_equal_fields_iterator li(*item_equal); while ((item= li++) != field_item) { - if (item->find_item_equal(upper_levels) == upper) + if (embedding_sjm(item) == field_sjm && + item->find_item_equal(upper_levels) == upper) break; } } @@ -11646,7 +11647,7 @@ static COND* substitute_for_best_equal_field(JOIN_TAB *context_tab, if (and_level) { cond_equal= &((Item_cond_and *) cond)->cond_equal; - cond_list->disjoin((List *) &cond_equal->current_level); + cond_list->disjoin((List *) &cond_equal->current_level);/* remove Item_equal objects from the AND. */ List_iterator_fast it(cond_equal->current_level); while ((item_equal= it++)) From 7ab53e80627e54c6dece486bf0b059436b7e5777 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 14 Feb 2012 16:04:06 +0400 Subject: [PATCH 78/83] MDEV-59 Review and push crashsafe GIS keys. tests for RTree keys recovery. --- .../suite/maria/r/maria-gis-recovery.result | 64 +++++++++++++++++++ .../maria/t/maria-gis-recovery-master.opt | 1 + .../suite/maria/t/maria-gis-recovery.test | 64 +++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 mysql-test/suite/maria/r/maria-gis-recovery.result create mode 100644 mysql-test/suite/maria/t/maria-gis-recovery-master.opt create mode 100644 mysql-test/suite/maria/t/maria-gis-recovery.test diff --git a/mysql-test/suite/maria/r/maria-gis-recovery.result b/mysql-test/suite/maria/r/maria-gis-recovery.result new file mode 100644 index 00000000000..ca406fc46e5 --- /dev/null +++ b/mysql-test/suite/maria/r/maria-gis-recovery.result @@ -0,0 +1,64 @@ +set global aria_log_file_size=4294967295; +drop database if exists mysqltest; +create database mysqltest; +use mysqltest; +* shut down mysqld, removed logs, restarted it +CREATE TABLE t1 ( +i int, +shape GEOMETRY NOT NULL, +SPATIAL (shape) +) ENGINE=ARIA; +insert into t1 values(1,POINT(1, 1)); +* copied t1 for feeding_recovery +insert into t1 values(2,POINT(2, 2)), (3,POINT(3, 3)), (4,POINT(4, 4)); +flush table t1; +* copied t1 for comparison +SET SESSION debug="+d,maria_flush_whole_log,maria_crash"; +* crashing mysqld intentionally +set global aria_checkpoint_interval=1; +ERROR HY000: Lost connection to MySQL server during query +* copied t1 back for feeding_recovery +* recovery happens +check table t1 extended; +Table Op Msg_type Msg_text +mysqltest.t1 check status OK +* testing that checksum after recovery is as expected +Checksum-check +ok +use mysqltest; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) DEFAULT NULL, + `shape` geometry NOT NULL, + SPATIAL KEY `shape` (`shape`) +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +* TEST of UPDATE vs state.auto_increment +* copied t1 for feeding_recovery +update t1 set shape=POINT(5, 5) where i=2; +flush table t1; +* copied t1 for comparison +SET SESSION debug="+d,maria_flush_whole_log,maria_crash"; +* crashing mysqld intentionally +set global aria_checkpoint_interval=1; +ERROR HY000: Lost connection to MySQL server during query +* copied t1 back for feeding_recovery +* recovery happens +check table t1 extended; +Table Op Msg_type Msg_text +mysqltest.t1 check status OK +* testing that checksum after recovery is as expected +Checksum-check +ok +use mysqltest; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) DEFAULT NULL, + `shape` geometry NOT NULL, + SPATIAL KEY `shape` (`shape`) +) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 +drop table t1; +drop database mysqltest_for_feeding_recovery; +drop database mysqltest_for_comparison; +drop database mysqltest; diff --git a/mysql-test/suite/maria/t/maria-gis-recovery-master.opt b/mysql-test/suite/maria/t/maria-gis-recovery-master.opt new file mode 100644 index 00000000000..58d0d012c54 --- /dev/null +++ b/mysql-test/suite/maria/t/maria-gis-recovery-master.opt @@ -0,0 +1 @@ +--skip-stack-trace --skip-core-file --loose-aria-log-dir-path=$MYSQLTEST_VARDIR/tmp diff --git a/mysql-test/suite/maria/t/maria-gis-recovery.test b/mysql-test/suite/maria/t/maria-gis-recovery.test new file mode 100644 index 00000000000..c40cc3788de --- /dev/null +++ b/mysql-test/suite/maria/t/maria-gis-recovery.test @@ -0,0 +1,64 @@ +--source include/not_embedded.inc +# Don't test this under valgrind, memory leaks will occur as we crash +--source include/not_valgrind.inc +# Binary must be compiled with debug for crash to occur +--source include/have_debug.inc +--source include/have_maria.inc +--source include/have_geometry.inc + +set global aria_log_file_size=4294967295; +let $MARIA_LOG=../../tmp; + +--disable_warnings +drop database if exists mysqltest; +--enable_warnings +create database mysqltest; +let $mms_tname=t; + +# Include scripts can perform SQL. For it to not influence the main test +# they use a separate connection. This way if they use a DDL it would +# not autocommit in the main test. +connect (admin, localhost, root,,mysqltest,,); +--enable_reconnect + +connection default; +use mysqltest; +--enable_reconnect + +-- source include/maria_empty_logs.inc +let $mms_tables=1; +CREATE TABLE t1 ( + i int, + shape GEOMETRY NOT NULL, + SPATIAL (shape) +) ENGINE=ARIA; +insert into t1 values(1,POINT(1, 1)); +-- source include/maria_make_snapshot_for_feeding_recovery.inc +insert into t1 values(2,POINT(2, 2)), (3,POINT(3, 3)), (4,POINT(4, 4)); +-- source include/maria_make_snapshot_for_comparison.inc +let $mvr_restore_old_snapshot=1; +let $mms_compare_physically=0; +let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash"; +let $mvr_crash_statement= set global aria_checkpoint_interval=1; +-- source include/maria_verify_recovery.inc +show create table t1; + +# Test that UPDATE's effect on auto-increment is recovered +--echo * TEST of UPDATE vs state.auto_increment +-- source include/maria_make_snapshot_for_feeding_recovery.inc +update t1 set shape=POINT(5, 5) where i=2; +-- source include/maria_make_snapshot_for_comparison.inc +let $mvr_restore_old_snapshot=1; +let $mms_compare_physically=0; +let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash"; +let $mvr_crash_statement= set global aria_checkpoint_interval=1; +-- source include/maria_verify_recovery.inc +show create table t1; +drop table t1; + +# clean up everything +let $mms_purpose=feeding_recovery; +eval drop database mysqltest_for_$mms_purpose; +let $mms_purpose=comparison; +eval drop database mysqltest_for_$mms_purpose; +drop database mysqltest; From bbd20403c5f759fa3ce866703a5fba0d193a1734 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Feb 2012 13:24:03 +0100 Subject: [PATCH 79/83] Fix wrong error code in the test case. The replication slave sets first error 1913 and immediately after error 1595. Thus it is possible, but unlikely, to get 1913. The original test seems to realise this, but uses an invalid error code - my guess is that this was a temporary code used in a feature tree, which was then forgotten to be fixed when merged to main. The removed "1923" is something committed by mistake during tests. --- mysql-test/suite/rpl/r/rpl_corruption.result | 4 ++-- mysql-test/suite/rpl/t/rpl_corruption.test | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_corruption.result b/mysql-test/suite/rpl/r/rpl_corruption.result index 5ecf6b006c9..62f56e70993 100644 --- a/mysql-test/suite/rpl/r/rpl_corruption.result +++ b/mysql-test/suite/rpl/r/rpl_corruption.result @@ -25,14 +25,14 @@ SET GLOBAL debug_dbug="-d,corrupt_read_log_event2"; SET GLOBAL master_verify_checksum=0; SET GLOBAL debug_dbug="+d,corrupt_read_log_event2"; START SLAVE IO_THREAD; -include/wait_for_slave_io_error.inc [errno=1595,1722,1923] +include/wait_for_slave_io_error.inc [errno=1595,1913] SET GLOBAL debug_dbug="-d,corrupt_read_log_event2"; SET GLOBAL debug_dbug= ""; SET GLOBAL master_verify_checksum=1; # 5. Slave. Corruption in network SET GLOBAL debug_dbug="+d,corrupt_queue_event"; START SLAVE IO_THREAD; -include/wait_for_slave_io_error.inc [errno=1595,1722,1923] +include/wait_for_slave_io_error.inc [errno=1595,1913] SET GLOBAL debug_dbug="-d,corrupt_queue_event"; # 6. Slave. Corruption in relay log SET GLOBAL debug_dbug="+d,corrupt_read_log_event_char"; diff --git a/mysql-test/suite/rpl/t/rpl_corruption.test b/mysql-test/suite/rpl/t/rpl_corruption.test index 458e3f10e67..c5625b4d002 100644 --- a/mysql-test/suite/rpl/t/rpl_corruption.test +++ b/mysql-test/suite/rpl/t/rpl_corruption.test @@ -115,7 +115,11 @@ SET GLOBAL master_verify_checksum=0; SET GLOBAL debug_dbug="+d,corrupt_read_log_event2"; --connection slave START SLAVE IO_THREAD; -let $slave_io_errno= 1595,1722,1923; +# When the checksum error is detected, the slave sets error code 1913 +# (ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE) in queue_event(), then immediately +# sets error 1595 (ER_SLAVE_RELAY_LOG_WRITE_FAILURE) in handle_slave_io(). +# So we usually get 1595, but it is occasionally possible to get 1913. +let $slave_io_errno= 1595,1913; --source include/wait_for_slave_io_error.inc --connection master SET GLOBAL debug_dbug="-d,corrupt_read_log_event2"; @@ -127,7 +131,7 @@ SET GLOBAL master_verify_checksum=1; --connection slave SET GLOBAL debug_dbug="+d,corrupt_queue_event"; START SLAVE IO_THREAD; -let $slave_io_errno= 1595,1722,1923; +let $slave_io_errno= 1595,1913; --source include/wait_for_slave_io_error.inc SET GLOBAL debug_dbug="-d,corrupt_queue_event"; From 764eeeee74f999fe2107fc362236563be0025093 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Feb 2012 16:52:56 +0200 Subject: [PATCH 80/83] Fix for LP BUG#910123 MariaDB 5.3.3 causes 1093 error on Drupal Problem was that now we can merge derived table (subquery in the FROM clause). Fix: in case of detected conflict and presence of derived table "over" the table which cased the conflict - try materialization strategy. --- mysql-test/r/derived_opt.result | 9 +++++++++ mysql-test/t/derived_opt.test | 10 ++++++++++ sql/sql_base.cc | 22 ++++++++++++++++++---- sql/sql_lex.cc | 1 + sql/sql_union.cc | 1 + sql/table.cc | 33 ++++++++++++++++++++++++++++++++- sql/table.h | 14 +++++++++++--- 7 files changed, 82 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/derived_opt.result b/mysql-test/r/derived_opt.result index 721d4277775..c5376bee756 100644 --- a/mysql-test/r/derived_opt.result +++ b/mysql-test/r/derived_opt.result @@ -273,4 +273,13 @@ ON alias3.f4 != 0 ) ON alias3.f4 != 0; f4 f4 f2 f4 drop table t1,t2,t3,t4; +# +# LP BUG#910123 MariaDB 5.3.3 causes 1093 error on Drupal +# Fix: force materialization in case of conflict +# +SET optimizer_switch='derived_merge=on'; +CREATE TABLE t1 ( i INT ); +INSERT INTO t1 VALUES ( (SELECT 1 FROM ( SELECT * FROM t1 ) as a) ); +drop table t1; +set optimizer_switch=@save_optimizer_switch; set optimizer_switch=@exit_optimizer_switch; diff --git a/mysql-test/t/derived_opt.test b/mysql-test/t/derived_opt.test index 42f3ce296e1..c2f831036e1 100644 --- a/mysql-test/t/derived_opt.test +++ b/mysql-test/t/derived_opt.test @@ -202,5 +202,15 @@ RIGHT JOIN ( drop table t1,t2,t3,t4; +--echo # +--echo # LP BUG#910123 MariaDB 5.3.3 causes 1093 error on Drupal +--echo # Fix: force materialization in case of conflict +--echo # +SET optimizer_switch='derived_merge=on'; +CREATE TABLE t1 ( i INT ); +INSERT INTO t1 VALUES ( (SELECT 1 FROM ( SELECT * FROM t1 ) as a) ); +drop table t1; +set optimizer_switch=@save_optimizer_switch; + # The following command must be the last one the file set optimizer_switch=@exit_optimizer_switch; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 9c5d251c728..11fd5db2020 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1707,11 +1707,12 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, t_name= table->table_name; t_alias= table->alias; +retry: DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name)); - for (;;) + for (TABLE_LIST *tl= table_list;;) { - if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) && - (! (res= mysql_lock_have_duplicate(thd, table, table_list)))) || + if (((! (res= find_table_in_global_list(tl, d_name, t_name))) && + (! (res= mysql_lock_have_duplicate(thd, table, tl)))) || ((!res->table || res->table != table->table) && (!check_alias || !(lower_case_table_names ? my_strcasecmp(files_charset_info, t_alias, res->alias) : @@ -1724,10 +1725,23 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, processed in derived table or top select of multi-update/multi-delete (exclude_from_table_unique_test) or prelocking placeholder. */ - table_list= res->next_global; + tl= res->next_global; DBUG_PRINT("info", ("found same copy of table or table which we should skip")); } + if (res && res->belong_to_derived) + { + /* Try to fix */ + TABLE_LIST *derived= res->belong_to_derived; + if (derived->is_merged_derived()) + { + DBUG_PRINT("info", + ("convert merged to materialization to resolve the conflict")); + derived->change_refs_to_fields(); + derived->set_materialized_derived(); + } + goto retry; + } DBUG_RETURN(res); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f29f51325a9..4a69cd3b1fa 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2885,6 +2885,7 @@ void st_lex::cleanup_after_one_table_open() if (all_selects_list != &select_lex) { derived_tables= 0; + select_lex.exclude_from_table_unique_test= false; /* cleunup underlying units (units of VIEW) */ for (SELECT_LEX_UNIT *un= select_lex.first_inner_unit(); un; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 90d9405ebe5..599dc993483 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -961,6 +961,7 @@ bool st_select_lex::cleanup() } non_agg_fields.empty(); inner_refs_list.empty(); + exclude_from_table_unique_test= FALSE; DBUG_RETURN(error); } diff --git a/sql/table.cc b/sql/table.cc index f1ff353a8c4..13e643f015b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4378,6 +4378,36 @@ bool TABLE_LIST::prepare_security(THD *thd) DBUG_RETURN(FALSE); } +#ifndef DBUG_OFF +void TABLE_LIST::set_check_merged() +{ + DBUG_ASSERT(derived); + /* + It is not simple to check all, but at least this should be checked: + this select is not excluded or the exclusion came from above. + */ + DBUG_ASSERT(!derived->first_select()->exclude_from_table_unique_test || + derived->outer_select()-> + exclude_from_table_unique_test); +} +#endif + +void TABLE_LIST::set_check_materialized() +{ + DBUG_ASSERT(derived); + if (!derived->first_select()->exclude_from_table_unique_test) + derived->set_unique_exclude(); + else + { + /* + The subtree should be already excluded + */ + DBUG_ASSERT(!derived->first_select()->first_inner_unit() || + derived->first_select()->first_inner_unit()->first_select()-> + exclude_from_table_unique_test); + } +} + Natural_join_column::Natural_join_column(Field_translator *field_param, TABLE_LIST *tab) @@ -5919,8 +5949,9 @@ bool TABLE_LIST::init_derived(THD *thd, bool init_view) */ if (is_materialized_derived()) { - unit->master_unit()->set_unique_exclude(); + set_check_materialized(); } + /* Create field translation for mergeable derived tables/views. For derived tables field translation can be created only after diff --git a/sql/table.h b/sql/table.h index 8d91804eb06..8de71658493 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1747,16 +1747,18 @@ struct TABLE_LIST inline void set_merged_derived() { derived_type= ((derived_type & DTYPE_MASK) | - DTYPE_TABLE | DTYPE_MERGE); + DTYPE_TABLE | DTYPE_MERGE); + set_check_merged(); } inline bool is_materialized_derived() { return (derived_type & DTYPE_MATERIALIZE); } - inline void set_materialized_derived() + void set_materialized_derived() { derived_type= ((derived_type & DTYPE_MASK) | - DTYPE_TABLE | DTYPE_MATERIALIZE); + DTYPE_TABLE | DTYPE_MATERIALIZE); + set_check_materialized(); } inline bool is_multitable() { @@ -1802,6 +1804,12 @@ struct TABLE_LIST private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); + void set_check_materialized(); +#ifndef DBUG_OFF + void set_check_merged(); +#else + inline void set_check_merged() {} +#endif /* Cleanup for re-execution in a prepared statement or a stored procedure. From 452a59e09c9ae415d46b5900efd567a9fcb61267 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 15 Feb 2012 11:49:53 +0100 Subject: [PATCH 81/83] Updated with XtraDB from Percona Server 5.5.20-24.1 Files copied from Percona-Server-5.5.20-rel24.1.tar.gz source tarball. --- btr/btr0btr.c | 16 +- btr/btr0cur.c | 31 +- btr/btr0pcur.c | 2 + btr/btr0sea.c | 304 +++++++++-------- buf/buf0buf.c | 210 +++++------- buf/buf0flu.c | 66 +++- buf/buf0lru.c | 194 ++++++----- dict/dict0dict.c | 10 + dict/dict0load.c | 4 +- fil/fil0fil.c | 51 ++- fsp/fsp0fsp.c | 67 +--- ha/ha0ha.c | 70 ++-- handler/ha_innodb.cc | 274 +++++++++++++-- handler/ha_innodb.h | 7 + handler/i_s.cc | 83 ++++- ibuf/ibuf0ibuf.c | 319 +++++++----------- include/btr0cur.h | 18 - include/btr0pcur.h | 8 - include/btr0pcur.ic | 32 -- include/btr0sea.h | 42 +-- include/btr0types.h | 29 +- include/buf0buf.h | 68 ++-- include/buf0buf.ic | 44 +++ include/buf0types.h | 5 +- include/fil0fil.h | 23 +- include/fsp0fsp.h | 102 +++++- include/fsp0fsp.ic | 34 +- include/ha0ha.h | 23 +- include/ha0ha.ic | 54 +-- include/page0page.h | 4 + include/row0upd.ic | 1 - include/srv0srv.h | 3 + include/sync0rw.h | 5 +- include/sync0rw.ic | 1 + include/sync0sync.h | 1 - include/trx0trx.h | 1 + log/log0log.c | 45 ++- page/page0page.c | 16 +- page/page0zip.c | 2 +- ...cona_flush_contiguous_neighbors-master.opt | 1 + .../percona_flush_contiguous_neighbors.result | 21 ++ .../percona_flush_contiguous_neighbors.test | 36 ++ .../percona_query_cache_with_comments.inc | 22 ++ .../percona_query_cache_with_comments.result | 200 ++++++++++- ...a_query_cache_with_comments_disable.result | 200 ++++++++++- ...ona_query_response_time-replication.result | 52 +-- .../percona_query_response_time-stored.result | 52 +-- .../percona_query_response_time.result | 104 +++--- .../percona_server_variables_debug.result | 2 + .../percona_server_variables_release.result | 1 + ...rcona_status_wait_query_cache_mutex.result | 31 +- ...percona_status_wait_query_cache_mutex.test | 42 +-- percona-suite/percona_sync_flush.result | 35 ++ percona-suite/percona_sync_flush.test | 33 ++ row/row0ins.c | 25 +- row/row0mysql.c | 13 +- srv/srv0srv.c | 31 +- srv/srv0start.c | 28 +- sync/sync0rw.c | 9 +- sync/sync0sync.c | 1 - trx/trx0trx.c | 1 + 61 files changed, 2046 insertions(+), 1163 deletions(-) create mode 100644 percona-suite/percona_flush_contiguous_neighbors-master.opt create mode 100644 percona-suite/percona_flush_contiguous_neighbors.result create mode 100644 percona-suite/percona_flush_contiguous_neighbors.test create mode 100644 percona-suite/percona_sync_flush.result create mode 100644 percona-suite/percona_sync_flush.test diff --git a/btr/btr0btr.c b/btr/btr0btr.c index ca98afc04ad..433b062bcec 100644 --- a/btr/btr0btr.c +++ b/btr/btr0btr.c @@ -1523,7 +1523,7 @@ btr_free_root( } ut_a(block); - btr_search_drop_page_hash_index(block, NULL); + btr_search_drop_page_hash_index(block); header = buf_block_get_frame(block) + PAGE_HEADER + PAGE_BTR_SEG_TOP; #ifdef UNIV_BTR_DEBUG @@ -1592,7 +1592,7 @@ btr_page_reorganize_low( #ifndef UNIV_HOTBACKUP if (UNIV_LIKELY(!recovery)) { - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); } block->check_index_page_at_flush = TRUE; @@ -1760,7 +1760,7 @@ btr_page_empty( ut_a(!page_zip || page_zip_validate(page_zip, page)); #endif /* UNIV_ZIP_DEBUG */ - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); btr_blob_dbg_remove(page, index, "btr_page_empty"); /* Recreate the page: note that global data on page (possible @@ -3093,7 +3093,7 @@ btr_lift_page_up( mem_heap_free(heap); } - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); /* Make the father empty */ btr_page_empty(father_block, father_page_zip, index, page_level, mtr); @@ -3317,7 +3317,7 @@ err_exit: goto err_exit; } - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); /* Remove the page from the level list */ btr_level_list_remove(space, zip_size, page, index, mtr); @@ -3358,7 +3358,7 @@ err_exit: goto err_exit; } - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); #ifdef UNIV_BTR_DEBUG if (UNIV_LIKELY_NULL(merge_page_zip)) { @@ -3473,7 +3473,7 @@ btr_discard_only_page_on_level( ut_a(btr_page_get_next(page, mtr) == FIL_NULL); ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); btr_page_get_father(index, block, mtr, &cursor); father = btr_cur_get_block(&cursor); @@ -3578,7 +3578,7 @@ btr_discard_page( page = buf_block_get_frame(block); ut_a(page_is_comp(merge_page) == page_is_comp(page)); - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); if (left_page_no == FIL_NULL && !page_is_leaf(page)) { diff --git a/btr/btr0cur.c b/btr/btr0cur.c index 717663a123a..43313474071 100644 --- a/btr/btr0cur.c +++ b/btr/btr0cur.c @@ -488,8 +488,6 @@ btr_cur_search_to_nth_level( cursor->flag = BTR_CUR_BINARY; cursor->index = index; - cursor->ibuf_cnt = ULINT_UNDEFINED; - #ifndef BTR_CUR_ADAPT guess = NULL; #else @@ -800,21 +798,8 @@ retry_page_get: /* We're doing a search on an ibuf tree and we're one level above the leaf page. */ - ulint is_min_rec; - ut_ad(level == 0); - is_min_rec = rec_get_info_bits(node_ptr, 0) - & REC_INFO_MIN_REC_FLAG; - - if (!is_min_rec) { - cursor->ibuf_cnt - = ibuf_rec_get_counter(node_ptr); - - ut_a(cursor->ibuf_cnt <= 0xFFFF - || cursor->ibuf_cnt == ULINT_UNDEFINED); - } - buf_mode = BUF_GET; rw_latch = RW_NO_LATCH; goto retry_page_get; @@ -2007,7 +1992,7 @@ btr_cur_update_in_place( was_delete_marked = rec_get_deleted_flag( rec, page_is_comp(buf_block_get_frame(block))); - is_hashed = block->is_hashed; + is_hashed = (block->index != NULL); if (is_hashed) { /* TO DO: Can we skip this if none of the fields @@ -3683,16 +3668,11 @@ btr_record_not_null_field_in_rec( } for (i = 0; i < n_unique; i++) { - ulint rec_len; - - rec_get_nth_field_offs(offsets, i, &rec_len); - - if (rec_len != UNIV_SQL_NULL) { - n_not_null[i]++; - } else { - /* Break if we hit the first NULL value */ + if (rec_offs_nth_sql_null(offsets, i)) { break; } + + n_not_null[i]++; } } @@ -3840,8 +3820,7 @@ btr_estimate_number_of_different_key_vals( if (n_not_null) { btr_record_not_null_field_in_rec( - n_cols, offsets_next_rec, - n_not_null); + n_cols, offsets_next_rec, n_not_null); } total_external_size diff --git a/btr/btr0pcur.c b/btr/btr0pcur.c index 081ef9c9457..e6a9ddcf43e 100644 --- a/btr/btr0pcur.c +++ b/btr/btr0pcur.c @@ -253,6 +253,8 @@ btr_pcur_restore_position_func( cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE, index, latch_mode, btr_pcur_get_btr_cur(cursor), mtr); + cursor->latch_mode = latch_mode; + cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->block_when_stored = btr_pcur_get_block(cursor); return(FALSE); diff --git a/btr/btr0sea.c b/btr/btr0sea.c index f27afe216ec..bddbcc79dd6 100644 --- a/btr/btr0sea.c +++ b/btr/btr0sea.c @@ -44,15 +44,11 @@ Created 2/17/1996 Heikki Tuuri #include "ha0ha.h" #include "srv0srv.h" /** Flag: has the search system been enabled? -Protected by btr_search_latch and btr_search_enabled_mutex. */ +Protected by btr_search_latch. */ UNIV_INTERN char btr_search_enabled = TRUE; -UNIV_INTERN ibool btr_search_fully_disabled = FALSE; UNIV_INTERN ulint btr_search_index_num = 1; -/** Mutex protecting btr_search_enabled */ -static mutex_t btr_search_enabled_mutex; - #ifdef UNIV_PFS_MUTEX /* Key to register btr_search_enabled_mutex with performance schema */ UNIV_INTERN mysql_pfs_key_t btr_search_enabled_mutex_key; @@ -186,8 +182,6 @@ btr_search_sys_create( //rw_lock_create(btr_search_latch_key, &btr_search_latch, // SYNC_SEARCH_SYS); - mutex_create(btr_search_enabled_mutex_key, - &btr_search_enabled_mutex, SYNC_SEARCH_SYS_CONF); btr_search_sys = mem_alloc(sizeof(btr_search_sys_t)); @@ -238,27 +232,40 @@ void btr_search_disable(void) /*====================*/ { - mutex_enter(&btr_search_enabled_mutex); + dict_table_t* table; + ulint i; + + mutex_enter(&dict_sys->mutex); btr_search_x_lock_all(); - /* Disable access to hash index, also tell ha_insert_for_fold() - stop adding new nodes to hash index, but still allow updating - existing nodes */ btr_search_enabled = FALSE; - /* Clear all block->is_hashed flags and remove all entries - from btr_search_sys->hash_index. */ - buf_pool_drop_hash_index(); + /* Clear the index->search_info->ref_count of every index in + the data dictionary cache. */ + for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU); table; + table = UT_LIST_GET_NEXT(table_LRU, table)) { - /* hash index has been cleaned up, disallow any operation to - the hash index */ - btr_search_fully_disabled = TRUE; + dict_index_t* index; - /* btr_search_enabled_mutex should guarantee this. */ - ut_ad(!btr_search_enabled); + for (index = dict_table_get_first_index(table); index; + index = dict_table_get_next_index(index)) { + + index->search_info->ref_count = 0; + } + } + + mutex_exit(&dict_sys->mutex); + + /* Set all block->index = NULL. */ + buf_pool_clear_hash_index(); + + /* Clear the adaptive hash index. */ + for (i = 0; i < btr_search_index_num; i++) { + hash_table_clear(btr_search_sys->hash_index[i]); + mem_heap_empty(btr_search_sys->hash_index[i]->heap); + } btr_search_x_unlock_all(); - mutex_exit(&btr_search_enabled_mutex); } /********************************************************************//** @@ -268,14 +275,11 @@ void btr_search_enable(void) /*====================*/ { - mutex_enter(&btr_search_enabled_mutex); btr_search_x_lock_all(); btr_search_enabled = TRUE; - btr_search_fully_disabled = FALSE; btr_search_x_unlock_all(); - mutex_exit(&btr_search_enabled_mutex); } /*****************************************************************//** @@ -499,7 +503,7 @@ btr_search_update_block_hash_info( && (block->n_bytes == info->n_bytes) && (block->left_side == info->left_side)) { - if ((block->is_hashed) + if ((block->index) && (block->curr_n_fields == info->n_fields) && (block->curr_n_bytes == info->n_bytes) && (block->curr_left_side == info->left_side)) { @@ -528,7 +532,7 @@ btr_search_update_block_hash_info( / BTR_SEARCH_PAGE_BUILD_LIMIT) && (info->n_hash_potential >= BTR_SEARCH_BUILD_LIMIT)) { - if ((!block->is_hashed) + if ((!block->index) || (block->n_hash_helps > 2 * page_get_n_recs(block->frame)) || (block->n_fields != block->curr_n_fields) @@ -560,9 +564,9 @@ btr_search_update_hash_ref( buf_block_t* block, /*!< in: buffer block where cursor positioned */ btr_cur_t* cursor) /*!< in: cursor */ { + dict_index_t* index; ulint fold; - rec_t* rec; - index_id_t index_id; + const rec_t* rec; ut_ad(cursor->flag == BTR_CUR_HASH_FAIL); #ifdef UNIV_SYNC_DEBUG @@ -573,13 +577,15 @@ btr_search_update_hash_ref( ut_ad(page_align(btr_cur_get_rec(cursor)) == buf_block_get_frame(block)); - if (!block->is_hashed) { + index = block->index; + + if (!index) { return; } - ut_a(block->index == cursor->index); - ut_a(!dict_index_is_ibuf(cursor->index)); + ut_a(index == cursor->index); + ut_a(!dict_index_is_ibuf(index)); if ((info->n_hash_potential > 0) && (block->curr_n_fields == info->n_fields) @@ -596,12 +602,11 @@ btr_search_update_hash_ref( return; } - index_id = cursor->index->id; fold = rec_fold(rec, - rec_get_offsets(rec, cursor->index, offsets_, + rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), block->curr_n_fields, - block->curr_n_bytes, index_id); + block->curr_n_bytes, index->id); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } @@ -870,7 +875,7 @@ btr_search_guess_on_hash( { buf_pool_t* buf_pool; buf_block_t* block; - rec_t* rec; + const rec_t* rec; ulint fold; index_id_t index_id; #ifdef notdefined @@ -956,7 +961,7 @@ btr_search_guess_on_hash( ut_ad(page_rec_is_user_rec(rec)); - btr_cur_position(index, rec, block, cursor); + btr_cur_position(index, (rec_t*) rec, block, cursor); /* Check the validity of the guess within the page */ @@ -1058,11 +1063,10 @@ UNIV_INTERN void btr_search_drop_page_hash_index( /*============================*/ - buf_block_t* block, /*!< in: block containing index page, + buf_block_t* block) /*!< in: block containing index page, s- or x-latched, or an index page for which we know that block->buf_fix_count == 0 */ - dict_index_t* index_in) { hash_table_t* table; ulint n_fields; @@ -1080,24 +1084,14 @@ btr_search_drop_page_hash_index( const dict_index_t* index; ulint* offsets; -#ifdef UNIV_SYNC_DEBUG - if (index_in) { - ut_ad(!rw_lock_own(btr_search_get_latch(index_in->id), RW_LOCK_SHARED)); - ut_ad(!rw_lock_own(btr_search_get_latch(index_in->id), RW_LOCK_EX)); - } -#endif /* UNIV_SYNC_DEBUG */ - retry: - if (index_in) { - index = index_in; - rw_lock_s_lock(btr_search_get_latch(index->id)); - } else if (btr_search_index_num > 1) { + if (btr_search_index_num > 1) { rw_lock_t* btr_search_latch; /* FIXME: This may be optimistic implementation still. */ btr_search_latch = (rw_lock_t*)(block->btr_search_latch); if (UNIV_LIKELY(!btr_search_latch)) { - if (block->is_hashed) { + if (block->index) { goto retry; } return; @@ -1107,7 +1101,7 @@ retry: rw_lock_s_unlock(btr_search_latch); goto retry; } - if (UNIV_LIKELY(!block->is_hashed)) { + if (UNIV_LIKELY(!block->index)) { rw_lock_s_unlock(btr_search_latch); goto retry; } @@ -1116,18 +1110,16 @@ retry: } else { /* btr_search_index_num == 1 */ /* btr_search_latch is only one and able to obtain - before evaluating block->is_hashed. */ + before evaluating block->index. */ rw_lock_s_lock(btr_search_latch_part[0]); - if (UNIV_LIKELY(!block->is_hashed)) { + if (UNIV_LIKELY(!block->index)) { rw_lock_s_unlock(btr_search_latch_part[0]); return; } index = block->index; } - page = block->frame; - - if (UNIV_LIKELY(!block->is_hashed)) { + if (UNIV_LIKELY(!index)) { rw_lock_s_unlock(btr_search_get_latch(index->id)); @@ -1155,6 +1147,7 @@ retry: ut_a(n_fields + n_bytes > 0); + page = block->frame; n_recs = page_get_n_recs(page); /* Calculate and cache fold values into an array for fast deletion @@ -1203,7 +1196,7 @@ next_rec: rw_lock_x_lock(btr_search_get_latch(index->id)); - if (UNIV_UNLIKELY(!block->is_hashed)) { + if (UNIV_UNLIKELY(!block->index)) { /* Someone else has meanwhile dropped the hash index */ goto cleanup; @@ -1231,10 +1224,9 @@ next_rec: ut_a(index->search_info->ref_count > 0); index->search_info->ref_count--; - block->is_hashed = FALSE; block->index = NULL; block->btr_search_latch = NULL; - + cleanup: #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG if (UNIV_UNLIKELY(block->n_pointers)) { @@ -1309,7 +1301,7 @@ retry: if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE || block->index != index - || !block->is_hashed) { + || !block->index) { continue; } @@ -1375,7 +1367,7 @@ next_rec: rw_lock_x_lock(btr_search_get_latch(index->id)); - if (UNIV_UNLIKELY(!block->is_hashed)) { + if (UNIV_UNLIKELY(!block->index)) { goto cleanup; } @@ -1400,7 +1392,6 @@ next_rec: ut_a(index->search_info->ref_count > 0); index->search_info->ref_count--; - block->is_hashed = FALSE; block->index = NULL; block->btr_search_latch = NULL; @@ -1434,8 +1425,8 @@ cleanup: } /********************************************************************//** -Drops a page hash index when a page is freed from a fseg to the file system. -Drops possible hash index if the page happens to be in the buffer pool. */ +Drops a possible page hash index when a page is evicted from the buffer pool +or freed in a file segment. */ UNIV_INTERN void btr_search_drop_page_hash_when_freed( @@ -1448,32 +1439,23 @@ btr_search_drop_page_hash_when_freed( buf_block_t* block; mtr_t mtr; - if (!buf_page_peek_if_search_hashed(space, page_no)) { - - return; - } - mtr_start(&mtr); - /* We assume that if the caller has a latch on the page, then the - caller has already dropped the hash index for the page, and we never - get here. Therefore we can acquire the s-latch to the page without - having to fear a deadlock. */ + /* If the caller has a latch on the page, then the caller must + have a x-latch on the page and it must have already dropped + the hash index for the page. Because of the x-latch that we + are possibly holding, we cannot s-latch the page, but must + (recursively) x-latch it, even though we are only reading. */ - block = buf_page_get_gen(space, zip_size, page_no, RW_S_LATCH, NULL, + block = buf_page_get_gen(space, zip_size, page_no, RW_X_LATCH, NULL, BUF_PEEK_IF_IN_POOL, __FILE__, __LINE__, &mtr); - /* Because the buffer pool mutex was released by - buf_page_peek_if_search_hashed(), it is possible that the - block was removed from the buffer pool by another thread - before buf_page_get_gen() got a chance to acquire the buffer - pool mutex again. Thus, we must check for a NULL return. */ - if (UNIV_LIKELY(block != NULL)) { + if (block && block->index) { buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH); - btr_search_drop_page_hash_index(block, NULL); + btr_search_drop_page_hash_index(block); } mtr_commit(&mtr); @@ -1501,7 +1483,6 @@ btr_search_build_page_hash_index( rec_t* next_rec; ulint fold; ulint next_fold; - index_id_t index_id; ulint n_cached; ulint n_recs; ulint* folds; @@ -1526,13 +1507,13 @@ btr_search_build_page_hash_index( rw_lock_s_lock(btr_search_get_latch(index->id)); - if (block->is_hashed && ((block->curr_n_fields != n_fields) + if (block->index && ((block->curr_n_fields != n_fields) || (block->curr_n_bytes != n_bytes) || (block->curr_left_side != left_side))) { rw_lock_s_unlock(btr_search_get_latch(index->id)); - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); } else { rw_lock_s_unlock(btr_search_get_latch(index->id)); } @@ -1565,7 +1546,7 @@ btr_search_build_page_hash_index( n_cached = 0; - index_id = btr_page_get_index_id(page); + ut_a(index->id == btr_page_get_index_id(page)); rec = page_rec_get_next(page_get_infimum_rec(page)); @@ -1580,7 +1561,7 @@ btr_search_build_page_hash_index( } } - fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id); + fold = rec_fold(rec, offsets, n_fields, n_bytes, index->id); if (left_side) { @@ -1607,7 +1588,7 @@ btr_search_build_page_hash_index( offsets = rec_get_offsets(next_rec, index, offsets, n_fields + (n_bytes > 0), &heap); next_fold = rec_fold(next_rec, offsets, n_fields, - n_bytes, index_id); + n_bytes, index->id); if (fold != next_fold) { /* Insert an entry into the hash index */ @@ -1632,13 +1613,13 @@ btr_search_build_page_hash_index( rw_lock_x_lock(btr_search_get_latch(index->id)); - if (UNIV_UNLIKELY(btr_search_fully_disabled)) { + if (UNIV_UNLIKELY(!btr_search_enabled)) { goto exit_func; } - if (block->is_hashed && ((block->curr_n_fields != n_fields) - || (block->curr_n_bytes != n_bytes) - || (block->curr_left_side != left_side))) { + if (block->index && ((block->curr_n_fields != n_fields) + || (block->curr_n_bytes != n_bytes) + || (block->curr_left_side != left_side))) { goto exit_func; } @@ -1647,11 +1628,10 @@ btr_search_build_page_hash_index( rebuild hash index for a page that is already hashed, we have to take care not to increment the counter in that case. */ - if (!block->is_hashed) { + if (!block->index) { index->search_info->ref_count++; } - block->is_hashed = TRUE; block->n_hash_helps = 0; block->curr_n_fields = n_fields; @@ -1700,23 +1680,24 @@ btr_search_move_or_delete_hash_entries( ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); ut_ad(rw_lock_own(&(new_block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - ut_a(!new_block->is_hashed || new_block->index == index); - ut_a(!block->is_hashed || block->index == index); - ut_a(!(new_block->is_hashed || block->is_hashed) - || !dict_index_is_ibuf(index)); rw_lock_s_lock(btr_search_get_latch(index->id)); - if (new_block->is_hashed) { + ut_a(!new_block->index || new_block->index == index); + ut_a(!block->index || block->index == index); + ut_a(!(new_block->index || block->index) + || !dict_index_is_ibuf(index)); + + if (new_block->index) { rw_lock_s_unlock(btr_search_get_latch(index->id)); - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); return; } - if (block->is_hashed) { + if (block->index) { n_fields = block->curr_n_fields; n_bytes = block->curr_n_bytes; @@ -1753,42 +1734,48 @@ btr_search_update_hash_on_delete( { hash_table_t* table; buf_block_t* block; - rec_t* rec; + const rec_t* rec; ulint fold; - index_id_t index_id; + dict_index_t* index; ulint offsets_[REC_OFFS_NORMAL_SIZE]; mem_heap_t* heap = NULL; rec_offs_init(offsets_); - rec = btr_cur_get_rec(cursor); - block = btr_cur_get_block(cursor); #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - if (!block->is_hashed) { + index = block->index; + + if (!index) { return; } - ut_a(block->index == cursor->index); + ut_a(index == cursor->index); ut_a(block->curr_n_fields + block->curr_n_bytes > 0); - ut_a(!dict_index_is_ibuf(cursor->index)); + ut_a(!dict_index_is_ibuf(index)); table = btr_search_get_hash_index(cursor->index->id); - index_id = cursor->index->id; - fold = rec_fold(rec, rec_get_offsets(rec, cursor->index, offsets_, + rec = btr_cur_get_rec(cursor); + + fold = rec_fold(rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - block->curr_n_fields, block->curr_n_bytes, index_id); + block->curr_n_fields, block->curr_n_bytes, index->id); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } + rw_lock_x_lock(btr_search_get_latch(cursor->index->id)); - ha_search_and_delete_if_found(table, fold, rec); + if (block->index) { + ut_a(block->index == index); + + ha_search_and_delete_if_found(table, fold, rec); + } rw_lock_x_unlock(btr_search_get_latch(cursor->index->id)); } @@ -1806,6 +1793,7 @@ btr_search_update_hash_node_on_insert( { hash_table_t* table; buf_block_t* block; + dict_index_t* index; rec_t* rec; rec = btr_cur_get_rec(cursor); @@ -1816,16 +1804,25 @@ btr_search_update_hash_node_on_insert( ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - if (!block->is_hashed) { + index = block->index; + + if (!index) { return; } - ut_a(block->index == cursor->index); - ut_a(!dict_index_is_ibuf(cursor->index)); + ut_a(cursor->index == index); + ut_a(!dict_index_is_ibuf(index)); rw_lock_x_lock(btr_search_get_latch(cursor->index->id)); + if (!block->index) { + + goto func_exit; + } + + ut_a(block->index == index); + if ((cursor->flag == BTR_CUR_HASH) && (cursor->n_fields == block->curr_n_fields) && (cursor->n_bytes == block->curr_n_bytes) @@ -1836,6 +1833,7 @@ btr_search_update_hash_node_on_insert( ha_search_and_update_if_found(table, cursor->fold, rec, block, page_rec_get_next(rec)); +func_exit: rw_lock_x_unlock(btr_search_get_latch(cursor->index->id)); } else { rw_lock_x_unlock(btr_search_get_latch(cursor->index->id)); @@ -1857,10 +1855,10 @@ btr_search_update_hash_on_insert( { hash_table_t* table; buf_block_t* block; + dict_index_t* index; rec_t* rec; rec_t* ins_rec; rec_t* next_rec; - index_id_t index_id; ulint fold; ulint ins_fold; ulint next_fold = 0; /* remove warning (??? bug ???) */ @@ -1885,15 +1883,15 @@ btr_search_update_hash_on_insert( ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - if (!block->is_hashed) { + index = block->index; + + if (!index) { return; } - ut_a(block->index == cursor->index); - ut_a(!dict_index_is_ibuf(cursor->index)); - - index_id = cursor->index->id; + ut_a(index == cursor->index); + ut_a(!dict_index_is_ibuf(index)); n_fields = block->curr_n_fields; n_bytes = block->curr_n_bytes; @@ -1902,28 +1900,32 @@ btr_search_update_hash_on_insert( ins_rec = page_rec_get_next(rec); next_rec = page_rec_get_next(ins_rec); - offsets = rec_get_offsets(ins_rec, cursor->index, offsets, + offsets = rec_get_offsets(ins_rec, index, offsets, ULINT_UNDEFINED, &heap); - ins_fold = rec_fold(ins_rec, offsets, n_fields, n_bytes, index_id); + ins_fold = rec_fold(ins_rec, offsets, n_fields, n_bytes, index->id); if (!page_rec_is_supremum(next_rec)) { - offsets = rec_get_offsets(next_rec, cursor->index, offsets, + offsets = rec_get_offsets(next_rec, index, offsets, n_fields + (n_bytes > 0), &heap); next_fold = rec_fold(next_rec, offsets, n_fields, - n_bytes, index_id); + n_bytes, index->id); } if (!page_rec_is_infimum(rec)) { - offsets = rec_get_offsets(rec, cursor->index, offsets, + offsets = rec_get_offsets(rec, index, offsets, n_fields + (n_bytes > 0), &heap); - fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id); + fold = rec_fold(rec, offsets, n_fields, n_bytes, index->id); } else { if (left_side) { - rw_lock_x_lock(btr_search_get_latch(index_id)); + rw_lock_x_lock(btr_search_get_latch(index->id)); locked = TRUE; + if (!btr_search_enabled) { + goto function_exit; + } + ha_insert_for_fold(table, ins_fold, block, ins_rec); } @@ -1934,9 +1936,13 @@ btr_search_update_hash_on_insert( if (!locked) { - rw_lock_x_lock(btr_search_get_latch(index_id)); + rw_lock_x_lock(btr_search_get_latch(index->id)); locked = TRUE; + + if (!btr_search_enabled) { + goto function_exit; + } } if (!left_side) { @@ -1952,9 +1958,13 @@ check_next_rec: if (!left_side) { if (!locked) { - rw_lock_x_lock(btr_search_get_latch(index_id)); + rw_lock_x_lock(btr_search_get_latch(index->id)); locked = TRUE; + + if (!btr_search_enabled) { + goto function_exit; + } } ha_insert_for_fold(table, ins_fold, block, ins_rec); @@ -1967,9 +1977,13 @@ check_next_rec: if (!locked) { - rw_lock_x_lock(btr_search_get_latch(index_id)); + rw_lock_x_lock(btr_search_get_latch(index->id)); locked = TRUE; + + if (!btr_search_enabled) { + goto function_exit; + } } if (!left_side) { @@ -1977,7 +1991,7 @@ check_next_rec: ha_insert_for_fold(table, ins_fold, block, ins_rec); /* fputs("Hash insert for ", stderr); - dict_index_name_print(stderr, cursor->index); + dict_index_name_print(stderr, index); fprintf(stderr, " fold %lu\n", ins_fold); */ } else { @@ -1990,7 +2004,7 @@ function_exit: mem_heap_free(heap); } if (locked) { - rw_lock_x_unlock(btr_search_get_latch(index_id)); + rw_lock_x_unlock(btr_search_get_latch(index->id)); } } @@ -2082,21 +2096,20 @@ btr_search_validate(void) ut_a(!dict_index_is_ibuf(block->index)); - offsets = rec_get_offsets((const rec_t*) node->data, + page_index_id = btr_page_get_index_id(block->frame); + + offsets = rec_get_offsets(node->data, block->index, offsets, block->curr_n_fields + (block->curr_n_bytes > 0), &heap); - page_index_id = btr_page_get_index_id(block->frame); - - if (UNIV_UNLIKELY - (!block->is_hashed || node->fold - != rec_fold((rec_t*)(node->data), - offsets, - block->curr_n_fields, - block->curr_n_bytes, - page_index_id))) { + if (!block->index || node->fold + != rec_fold(node->data, + offsets, + block->curr_n_fields, + block->curr_n_bytes, + page_index_id)) { const page_t* page = block->frame; ok = FALSE; @@ -2112,20 +2125,19 @@ btr_search_validate(void) node->data, (ullint) page_index_id, (ulong) node->fold, - (ulong) rec_fold((rec_t*)(node->data), + (ulong) rec_fold(node->data, offsets, block->curr_n_fields, block->curr_n_bytes, page_index_id)); fputs("InnoDB: Record ", stderr); - rec_print_new(stderr, (rec_t*)node->data, - offsets); + rec_print_new(stderr, node->data, offsets); fprintf(stderr, "\nInnoDB: on that page." - " Page mem address %p, is hashed %lu," + " Page mem address %p, is hashed %p," " n fields %lu, n bytes %lu\n" "InnoDB: side %lu\n", - (void*) page, (ulong) block->is_hashed, + (void*) page, (void*) block->index, (ulong) block->curr_n_fields, (ulong) block->curr_n_bytes, (ulong) block->curr_left_side); diff --git a/buf/buf0buf.c b/buf/buf0buf.c index b75a7c82f42..b3f6600dca6 100644 --- a/buf/buf0buf.c +++ b/buf/buf0buf.c @@ -917,6 +917,16 @@ pfs_register_buffer_block( rwlock->pfs_psi = (PSI_server) ? PSI_server->init_rwlock(buf_block_lock_key, rwlock) : NULL; + +# ifdef UNIV_SYNC_DEBUG + rwlock = &block->debug_latch; + ut_a(!rwlock->pfs_psi); + rwlock->pfs_psi = (PSI_server) + ? PSI_server->init_rwlock(buf_block_debug_latch_key, + rwlock) + : NULL; +# endif /* UNIV_SYNC_DEBUG */ + # endif /* UNIV_PFS_RWLOCK */ block++; } @@ -952,8 +962,6 @@ buf_block_init( block->index = NULL; block->btr_search_latch = NULL; - block->is_hashed = FALSE; - #ifdef UNIV_DEBUG block->page.in_page_hash = FALSE; block->page.in_zip_hash = FALSE; @@ -980,17 +988,24 @@ buf_block_init( mutex_create(PFS_NOT_INSTRUMENTED, &block->mutex, SYNC_BUF_BLOCK); rw_lock_create(PFS_NOT_INSTRUMENTED, &block->lock, SYNC_LEVEL_VARYING); + +# ifdef UNIV_SYNC_DEBUG + rw_lock_create(PFS_NOT_INSTRUMENTED, + &block->debug_latch, SYNC_NO_ORDER_CHECK); +# endif /* UNIV_SYNC_DEBUG */ + #else /* PFS_SKIP_BUFFER_MUTEX_RWLOCK || PFS_GROUP_BUFFER_SYNC */ mutex_create(buffer_block_mutex_key, &block->mutex, SYNC_BUF_BLOCK); rw_lock_create(buf_block_lock_key, &block->lock, SYNC_LEVEL_VARYING); + +# ifdef UNIV_SYNC_DEBUG + rw_lock_create(buf_block_debug_latch_key, + &block->debug_latch, SYNC_NO_ORDER_CHECK); +# endif /* UNIV_SYNC_DEBUG */ #endif /* PFS_SKIP_BUFFER_MUTEX_RWLOCK || PFS_GROUP_BUFFER_SYNC */ ut_ad(rw_lock_validate(&(block->lock))); -#ifdef UNIV_SYNC_DEBUG - rw_lock_create(buf_block_debug_latch_key, - &block->debug_latch, SYNC_NO_ORDER_CHECK); -#endif /* UNIV_SYNC_DEBUG */ } /********************************************************************//** @@ -1317,6 +1332,26 @@ buf_pool_free_instance( { buf_chunk_t* chunk; buf_chunk_t* chunks; + buf_page_t* bpage; + + bpage = UT_LIST_GET_LAST(buf_pool->LRU); + while (bpage != NULL) { + buf_page_t* prev_bpage = UT_LIST_GET_PREV(LRU, bpage); + enum buf_page_state state = buf_page_get_state(bpage); + + ut_ad(buf_page_in_file(bpage)); + ut_ad(bpage->in_LRU_list); + + if (state != BUF_BLOCK_FILE_PAGE) { + /* We must not have any dirty block except + when doing a fast shutdown. */ + ut_ad(state == BUF_BLOCK_ZIP_PAGE + || srv_fast_shutdown == 2); + buf_page_free_descriptor(bpage); + } + + bpage = prev_bpage; + } chunks = buf_pool->chunks; chunk = chunks + buf_pool->n_chunks; @@ -1392,87 +1427,13 @@ buf_pool_free( } /********************************************************************//** -Drops adaptive hash index for a buffer pool instance. */ -static -void -buf_pool_drop_hash_index_instance( -/*==============================*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - ibool* released_search_latch) /*!< out: flag for signalling - whether the search latch was - released */ -{ - buf_chunk_t* chunks = buf_pool->chunks; - buf_chunk_t* chunk = chunks + buf_pool->n_chunks; - - while (--chunk >= chunks) { - ulint i; - buf_block_t* block = chunk->blocks; - - for (i = chunk->size; i--; block++) { - /* block->is_hashed cannot be modified - when we have an x-latch on btr_search_latch; - see the comment in buf0buf.h */ - - if (!block->is_hashed) { - continue; - } - - /* To follow the latching order, we - have to release btr_search_latch - before acquiring block->latch. */ - btr_search_x_unlock_all(); - /* When we release the search latch, - we must rescan all blocks, because - some may become hashed again. */ - *released_search_latch = TRUE; - - rw_lock_x_lock(&block->lock); - - /* This should be guaranteed by the - callers, which will be holding - btr_search_enabled_mutex. */ - ut_ad(!btr_search_enabled); - - /* Because we did not buffer-fix the - block by calling buf_block_get_gen(), - it is possible that the block has been - allocated for some other use after - btr_search_latch was released above. - We do not care which file page the - block is mapped to. All we want to do - is to drop any hash entries referring - to the page. */ - - /* It is possible that - block->page.state != BUF_FILE_PAGE. - Even that does not matter, because - btr_search_drop_page_hash_index() will - check block->is_hashed before doing - anything. block->is_hashed can only - be set on uncompressed file pages. */ - - btr_search_drop_page_hash_index(block, NULL); - - rw_lock_x_unlock(&block->lock); - - btr_search_x_lock_all(); - - ut_ad(!btr_search_enabled); - } - } -} - -/********************************************************************//** -Drops the adaptive hash index. To prevent a livelock, this function -is only to be called while holding btr_search_latch and while -btr_search_enabled == FALSE. */ +Clears the adaptive hash index on all pages in the buffer pool. */ UNIV_INTERN void -buf_pool_drop_hash_index(void) -/*==========================*/ +buf_pool_clear_hash_index(void) +/*===========================*/ { - ibool released_search_latch; + ulint p; #ifdef UNIV_SYNC_DEBUG ulint j; @@ -1483,21 +1444,34 @@ buf_pool_drop_hash_index(void) #endif /* UNIV_SYNC_DEBUG */ ut_ad(!btr_search_enabled); - do { - ulint i; + for (p = 0; p < srv_buf_pool_instances; p++) { + buf_pool_t* buf_pool = buf_pool_from_array(p); + buf_chunk_t* chunks = buf_pool->chunks; + buf_chunk_t* chunk = chunks + buf_pool->n_chunks; - released_search_latch = FALSE; + while (--chunk >= chunks) { + buf_block_t* block = chunk->blocks; + ulint i = chunk->size; - for (i = 0; i < srv_buf_pool_instances; i++) { - buf_pool_t* buf_pool; + for (; i--; block++) { + dict_index_t* index = block->index; - buf_pool = buf_pool_from_array(i); + /* We can set block->index = NULL + when we have an x-latch on btr_search_latch; + see the comment in buf0buf.h */ - buf_pool_drop_hash_index_instance( - buf_pool, &released_search_latch); + if (!index) { + /* Not hashed */ + continue; + } + + block->index = NULL; +# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG + block->n_pointers = 0; +# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ + } } - - } while (released_search_latch); + } } /********************************************************************//** @@ -1638,12 +1612,12 @@ buf_pool_watch_set( rw_lock_x_lock(&buf_pool->page_hash_latch); bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); - if (bpage) { - block_mutex = buf_page_get_mutex_enter(bpage); - ut_a(block_mutex); - } if (UNIV_LIKELY_NULL(bpage)) { + + block_mutex = buf_page_get_mutex_enter(bpage); + ut_a(block_mutex); + if (!buf_pool_watch_is_sentinel(buf_pool, bpage)) { /* The page was loaded meanwhile. */ rw_lock_x_unlock(&buf_pool->page_hash_latch); @@ -1895,40 +1869,6 @@ buf_reset_check_index_page_at_flush( rw_lock_s_unlock(&buf_pool->page_hash_latch); } -/********************************************************************//** -Returns the current state of is_hashed of a page. FALSE if the page is -not in the pool. NOTE that this operation does not fix the page in the -pool if it is found there. -@return TRUE if page hash index is built in search system */ -UNIV_INTERN -ibool -buf_page_peek_if_search_hashed( -/*===========================*/ - ulint space, /*!< in: space id */ - ulint offset) /*!< in: page number */ -{ - buf_block_t* block; - ibool is_hashed; - buf_pool_t* buf_pool = buf_pool_get(space, offset); - - //buf_pool_mutex_enter(buf_pool); - rw_lock_s_lock(&buf_pool->page_hash_latch); - - block = (buf_block_t*) buf_page_hash_get(buf_pool, space, offset); - - if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) { - is_hashed = FALSE; - } else { - ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page)); - is_hashed = block->is_hashed; - } - - //buf_pool_mutex_exit(buf_pool); - rw_lock_s_unlock(&buf_pool->page_hash_latch); - - return(is_hashed); -} - #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG /********************************************************************//** Sets file_page_was_freed TRUE if the page is found in the buffer pool. @@ -2218,7 +2158,6 @@ buf_block_init_low( block->btr_search_latch = NULL; block->n_hash_helps = 0; - block->is_hashed = FALSE; block->n_fields = 1; block->n_bytes = 0; block->left_side = TRUE; @@ -4473,6 +4412,9 @@ buf_pool_validate_instance( ut_a(rw_lock_is_locked(&block->lock, RW_LOCK_EX)); break; + + case BUF_IO_PIN: + break; } n_lru++; @@ -4502,6 +4444,7 @@ buf_pool_validate_instance( ut_a(buf_page_get_state(b) == BUF_BLOCK_ZIP_PAGE); switch (buf_page_get_io_fix(b)) { case BUF_IO_NONE: + case BUF_IO_PIN: /* All clean blocks should be I/O-unfixed. */ break; case BUF_IO_READ: @@ -4541,6 +4484,7 @@ buf_pool_validate_instance( switch (buf_page_get_io_fix(b)) { case BUF_IO_NONE: case BUF_IO_READ: + case BUF_IO_PIN: break; case BUF_IO_WRITE: switch (buf_page_get_flush_type(b)) { diff --git a/buf/buf0flu.c b/buf/buf0flu.c index 73a9ff96289..d776a274d14 100644 --- a/buf/buf0flu.c +++ b/buf/buf0flu.c @@ -1399,6 +1399,7 @@ buf_flush_try_neighbors( ulint high; ulint count = 0; buf_pool_t* buf_pool = buf_pool_get(space, offset); + ibool is_forward_scan; ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST); @@ -1429,7 +1430,32 @@ buf_flush_try_neighbors( high = fil_space_get_size(space); } - for (i = low; i < high; i++) { + if (srv_flush_neighbor_pages == 2) { + + /* In the case of contiguous flush where the requested page + does not fall at the start of flush area, first scan backward + from the page and later forward from it. */ + is_forward_scan = (offset == low); + } + else { + is_forward_scan = TRUE; + } + +scan: + if (srv_flush_neighbor_pages == 2) { + if (is_forward_scan) { + i = offset; + } + else { + i = offset - 1; + } + } + else { + i = low; + } + + for (; is_forward_scan ? (i < high) : (i >= low); + is_forward_scan ? i++ : i--) { buf_page_t* bpage; @@ -1460,6 +1486,12 @@ buf_flush_try_neighbors( //buf_pool_mutex_exit(buf_pool); rw_lock_s_unlock(&buf_pool->page_hash_latch); + if (srv_flush_neighbor_pages == 2) { + + /* This is contiguous neighbor page flush and + the pages here are not contiguous. */ + break; + } continue; } @@ -1495,6 +1527,22 @@ buf_flush_try_neighbors( } //buf_pool_mutex_exit(buf_pool); rw_lock_s_unlock(&buf_pool->page_hash_latch); + + if (srv_flush_neighbor_pages == 2) { + + /* We are trying to do the contiguous neighbor page + flush, but the last page we checked was unflushable, + making a "hole" in the flush, so stop this attempt. */ + break; + } + } + + if (!is_forward_scan) { + + /* Backward scan done, now do the forward scan */ + ut_a (srv_flush_neighbor_pages == 2); + is_forward_scan = TRUE; + goto scan; } return(count); @@ -1988,6 +2036,22 @@ buf_flush_list( buf_pool = buf_pool_from_array(i); + if (lsn_limit != IB_ULONGLONG_MAX) { + buf_page_t* bpage; + + buf_flush_list_mutex_enter(buf_pool); + bpage = UT_LIST_GET_LAST(buf_pool->flush_list); + if (!bpage + || bpage->oldest_modification >= lsn_limit) { + + buf_flush_list_mutex_exit(buf_pool); + continue; + } else { + + buf_flush_list_mutex_exit(buf_pool); + } + } + if (!buf_flush_start(buf_pool, BUF_FLUSH_LIST)) { /* We have two choices here. If lsn_limit was specified then skipping an instance of buffer diff --git a/buf/buf0lru.c b/buf/buf0lru.c index 06ce43a4d2d..daa2cd93255 100644 --- a/buf/buf0lru.c +++ b/buf/buf0lru.c @@ -68,8 +68,12 @@ allowed to point to either end of the LRU list. */ /** When dropping the search hash index entries before deleting an ibd file, we build a local array of pages belonging to that tablespace -in the buffer pool. Following is the size of that array. */ -#define BUF_LRU_DROP_SEARCH_HASH_SIZE 1024 +in the buffer pool. Following is the size of that array. +We also release buf_pool->mutex after scanning this many pages of the +flush_list when dropping a table. This is to ensure that other threads +are not blocked for extended period of time when using very large +buffer pools. */ +#define BUF_LRU_DROP_SEARCH_SIZE 1024 /** If we switch on the InnoDB monitor because there are too few available frames in the buffer pool, we set this to TRUE */ @@ -222,7 +226,7 @@ buf_LRU_drop_page_hash_batch( ulint i; ut_ad(arr != NULL); - ut_ad(count <= BUF_LRU_DROP_SEARCH_HASH_SIZE); + ut_ad(count <= BUF_LRU_DROP_SEARCH_SIZE); for (i = 0; i < count; ++i) { btr_search_drop_page_hash_when_freed(space_id, zip_size, @@ -256,7 +260,7 @@ buf_LRU_drop_page_hash_for_tablespace( } page_arr = ut_malloc( - sizeof(ulint) * BUF_LRU_DROP_SEARCH_HASH_SIZE); + sizeof(ulint) * BUF_LRU_DROP_SEARCH_SIZE); //buf_pool_mutex_enter(buf_pool); mutex_enter(&buf_pool->LRU_list_mutex); @@ -293,7 +297,7 @@ next_page: //mutex_enter(&((buf_block_t*) bpage)->mutex); is_fixed = bpage->buf_fix_count > 0 - || !((buf_block_t*) bpage)->is_hashed; + || !((buf_block_t*) bpage)->index; //mutex_exit(&((buf_block_t*) bpage)->mutex); if (is_fixed) { @@ -304,12 +308,14 @@ next_page: /* Store the page number so that we can drop the hash index in a batch later. */ page_arr[num_entries] = bpage->offset; + mutex_exit(block_mutex); - ut_a(num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE); + ut_a(num_entries < BUF_LRU_DROP_SEARCH_SIZE); + ++num_entries; - if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) { + if (num_entries < BUF_LRU_DROP_SEARCH_SIZE) { goto next_page; } @@ -366,39 +372,42 @@ next_page: } /******************************************************************//** -Invalidates all pages belonging to a given tablespace inside a specific +Remove all dirty pages belonging to a given tablespace inside a specific buffer pool instance when we are deleting the data file(s) of that -tablespace. */ +tablespace. The pages still remain a part of LRU and are evicted from +the list as they age towards the tail of the LRU. */ static void -buf_LRU_invalidate_tablespace_buf_pool_instance( -/*============================================*/ +buf_LRU_remove_dirty_pages_for_tablespace( +/*======================================*/ buf_pool_t* buf_pool, /*!< buffer pool instance */ ulint id) /*!< in: space id */ { buf_page_t* bpage; ibool all_freed; + ulint i; scan_again: //buf_pool_mutex_enter(buf_pool); mutex_enter(&buf_pool->LRU_list_mutex); rw_lock_x_lock(&buf_pool->page_hash_latch); + buf_flush_list_mutex_enter(buf_pool); all_freed = TRUE; - bpage = UT_LIST_GET_LAST(buf_pool->LRU); + for (bpage = UT_LIST_GET_LAST(buf_pool->flush_list), i = 0; + bpage != NULL; ++i) { - while (bpage != NULL) { buf_page_t* prev_bpage; mutex_t* block_mutex = NULL; ut_a(buf_page_in_file(bpage)); - prev_bpage = UT_LIST_GET_PREV(LRU, bpage); + prev_bpage = UT_LIST_GET_PREV(flush_list, bpage); /* bpage->space and bpage->io_fix are protected by - buf_pool_mutex and block_mutex. It is safe to check - them while holding buf_pool_mutex only. */ + buf_pool->mutex and block_mutex. It is safe to check + them while holding buf_pool->mutex only. */ if (buf_page_get_space(bpage) != id) { /* Skip this block, as it does not belong to @@ -411,90 +420,97 @@ scan_again: all_freed = FALSE; goto next_page; - } else { - block_mutex = buf_page_get_mutex_enter(bpage); - - if (!block_mutex) { - /* It may be impossible case... - Something wrong, so will be scan_again */ - - all_freed = FALSE; - goto next_page; - } - - if (bpage->buf_fix_count > 0) { - - mutex_exit(block_mutex); - /* We cannot remove this page during - this scan yet; maybe the system is - currently reading it in, or flushing - the modifications to the file */ - - all_freed = FALSE; - - goto next_page; - } } - ut_ad(mutex_own(block_mutex)); + /* We have to release the flush_list_mutex to obey the + latching order. We are however guaranteed that the page + will stay in the flush_list because buf_flush_remove() + needs buf_pool->mutex as well. */ + buf_flush_list_mutex_exit(buf_pool); + block_mutex = buf_page_get_mutex_enter(bpage); -#ifdef UNIV_DEBUG - if (buf_debug_prints) { - fprintf(stderr, - "Dropping space %lu page %lu\n", - (ulong) buf_page_get_space(bpage), - (ulong) buf_page_get_page_no(bpage)); + if (!block_mutex) { + /* It may be impossible case... + Something wrong, so will be scan_again */ + all_freed = FALSE; + goto next_page; } -#endif - if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) { - /* This is a compressed-only block - descriptor. Do nothing. */ - } else if (((buf_block_t*) bpage)->is_hashed) { - ulint page_no; - ulint zip_size; - - //buf_pool_mutex_exit(buf_pool); - mutex_exit(&buf_pool->LRU_list_mutex); - rw_lock_x_unlock(&buf_pool->page_hash_latch); - - zip_size = buf_page_get_zip_size(bpage); - page_no = buf_page_get_page_no(bpage); + if (bpage->buf_fix_count > 0) { mutex_exit(block_mutex); + buf_flush_list_mutex_enter(buf_pool); - /* Note that the following call will acquire - an S-latch on the page */ + /* We cannot remove this page during + this scan yet; maybe the system is + currently reading it in, or flushing + the modifications to the file */ - btr_search_drop_page_hash_when_freed( - id, zip_size, page_no); - goto scan_again; + all_freed = FALSE; + goto next_page; } - if (bpage->oldest_modification != 0) { + ut_ad(bpage->oldest_modification != 0); - buf_flush_remove(bpage); - } + buf_flush_remove(bpage); - /* Remove from the LRU list. */ - - if (buf_LRU_block_remove_hashed_page(bpage, TRUE) - != BUF_BLOCK_ZIP_FREE) { - buf_LRU_block_free_hashed_page((buf_block_t*) bpage, TRUE); - mutex_exit(block_mutex); - } else { - /* The block_mutex should have been released - by buf_LRU_block_remove_hashed_page() when it - returns BUF_BLOCK_ZIP_FREE. */ - ut_ad(block_mutex == &buf_pool->zip_mutex); - ut_ad(!mutex_own(block_mutex)); - } + mutex_exit(block_mutex); + buf_flush_list_mutex_enter(buf_pool); next_page: bpage = prev_bpage; + + if (!bpage) { + break; + } + + /* Every BUF_LRU_DROP_SEARCH_SIZE iterations in the + loop we release buf_pool->mutex to let other threads + do their job. */ + if (i < BUF_LRU_DROP_SEARCH_SIZE) { + continue; + } + + /* We IO-fix the block to make sure that the block + stays in its position in the flush_list. */ + if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) { + /* Block is already IO-fixed. We don't + want to change the value. Lets leave + this block alone. */ + continue; + } + + buf_flush_list_mutex_exit(buf_pool); + block_mutex = buf_page_get_mutex(bpage); + mutex_enter(block_mutex); + buf_page_set_sticky(bpage); + mutex_exit(block_mutex); + + /* Now it is safe to release the buf_pool->mutex. */ + //buf_pool_mutex_exit(buf_pool); + mutex_exit(&buf_pool->LRU_list_mutex); + rw_lock_x_unlock(&buf_pool->page_hash_latch); + + os_thread_yield(); + //buf_pool_mutex_enter(buf_pool); + mutex_enter(&buf_pool->LRU_list_mutex); + rw_lock_x_lock(&buf_pool->page_hash_latch); + + + mutex_enter(block_mutex); + buf_page_unset_sticky(bpage); + mutex_exit(block_mutex); + + buf_flush_list_mutex_enter(buf_pool); + ut_ad(bpage->in_flush_list); + + i = 0; } - //buf_pool_mutex_exit(buf_pool); +// buf_pool_mutex_exit(buf_pool); mutex_exit(&buf_pool->LRU_list_mutex); rw_lock_x_unlock(&buf_pool->page_hash_latch); + buf_flush_list_mutex_exit(buf_pool); + + ut_ad(buf_flush_validate(buf_pool)); if (!all_freed) { os_thread_sleep(20000); @@ -525,7 +541,7 @@ buf_LRU_invalidate_tablespace( buf_pool = buf_pool_from_array(i); buf_LRU_drop_page_hash_for_tablespace(buf_pool, id); - buf_LRU_invalidate_tablespace_buf_pool_instance(buf_pool, id); + buf_LRU_remove_dirty_pages_for_tablespace(buf_pool, id); } } @@ -567,7 +583,7 @@ buf_LRU_mark_space_was_deleted( for (k = chunk->size; k--; block++) { if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE - || !block->is_hashed + || !block->index || buf_page_get_space(&block->page) != id) { continue; } @@ -575,7 +591,7 @@ buf_LRU_mark_space_was_deleted( btr_search_s_unlock_all(); rw_lock_x_lock(&block->lock); - btr_search_drop_page_hash_index(block, NULL); + btr_search_drop_page_hash_index(block); rw_lock_x_unlock(&block->lock); btr_search_s_lock_all(); @@ -1726,8 +1742,7 @@ not_freed: /* Prevent buf_page_get_gen() from decompressing the block while we release buf_pool->mutex and block_mutex. */ - b->buf_fix_count++; - b->io_fix = BUF_IO_READ; + buf_page_set_sticky(b); mutex_exit(&buf_pool->zip_mutex); } @@ -1744,7 +1759,7 @@ not_freed: UNIV_MEM_VALID(((buf_block_t*) bpage)->frame, UNIV_PAGE_SIZE); - btr_search_drop_page_hash_index((buf_block_t*) bpage, NULL); + btr_search_drop_page_hash_index((buf_block_t*) bpage); UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame, UNIV_PAGE_SIZE); @@ -1772,8 +1787,7 @@ not_freed: if (b) { mutex_enter(&buf_pool->zip_mutex); - b->buf_fix_count--; - buf_page_set_io_fix(b, BUF_IO_NONE); + buf_page_unset_sticky(b); mutex_exit(&buf_pool->zip_mutex); } diff --git a/dict/dict0dict.c b/dict/dict0dict.c index edcacb5919d..43f28751a31 100644 --- a/dict/dict0dict.c +++ b/dict/dict0dict.c @@ -916,6 +916,11 @@ dict_index_find_on_id_low( dict_table_t* table; dict_index_t* index; + /* This can happen if the system tablespace is the wrong page size */ + if (dict_sys == NULL) { + return(NULL); + } + table = UT_LIST_GET_FIRST(dict_sys->table_LRU); while (table) { @@ -3137,10 +3142,15 @@ dict_scan_table_name( memcpy(ref, database_name, database_name_len); ref[database_name_len] = '/'; memcpy(ref + database_name_len + 1, table_name, table_name_len + 1); + } else { +#ifndef __WIN__ if (innobase_get_lower_case_table_names() == 1) { innobase_casedn_str(ref); } +#else + innobase_casedn_str(ref); +#endif /* !__WIN__ */ *table = dict_table_get_low(ref); } diff --git a/dict/dict0load.c b/dict/dict0load.c index 20b9caf7322..0e7c777ea1f 100644 --- a/dict/dict0load.c +++ b/dict/dict0load.c @@ -850,7 +850,7 @@ loop: object and check that the .ibd file exists. */ fil_open_single_table_tablespace(FALSE, space_id, - flags, name); + flags, name, NULL); } mem_free(name); @@ -1905,7 +1905,7 @@ err_exit: if (!fil_open_single_table_tablespace( TRUE, table->space, table->flags == DICT_TF_COMPACT ? 0 : - table->flags & ~(~0 << DICT_TF_BITS), name)) { + table->flags & ~(~0 << DICT_TF_BITS), name, NULL)) { /* We failed to find a sensible tablespace file */ diff --git a/fil/fil0fil.c b/fil/fil0fil.c index 380f471e67b..649b6c36bcd 100644 --- a/fil/fil0fil.c +++ b/fil/fil0fil.c @@ -1827,36 +1827,44 @@ fil_write_flushed_lsn_to_data_files( } /*******************************************************************//** -Reads the flushed lsn and arch no fields from a data file at database -startup. */ +Reads the flushed lsn, arch no, and tablespace flag fields from a data +file at database startup. */ UNIV_INTERN void -fil_read_flushed_lsn_and_arch_log_no( -/*=================================*/ +fil_read_first_page( +/*================*/ os_file_t data_file, /*!< in: open data file */ ibool one_read_already, /*!< in: TRUE if min and max parameters below already contain sensible data */ + ulint* flags, /*!< out: tablespace flags */ #ifdef UNIV_LOG_ARCHIVE - ulint* min_arch_log_no, /*!< in/out: */ - ulint* max_arch_log_no, /*!< in/out: */ + ulint* min_arch_log_no, /*!< out: min of archived + log numbers in data files */ + ulint* max_arch_log_no, /*!< out: max of archived + log numbers in data files */ #endif /* UNIV_LOG_ARCHIVE */ - ib_uint64_t* min_flushed_lsn, /*!< in/out: */ - ib_uint64_t* max_flushed_lsn) /*!< in/out: */ + ib_uint64_t* min_flushed_lsn, /*!< out: min of flushed + lsn values in data files */ + ib_uint64_t* max_flushed_lsn) /*!< out: max of flushed + lsn values in data files */ { byte* buf; - byte* buf2; + page_t* page; ib_uint64_t flushed_lsn; - buf2 = ut_malloc(2 * UNIV_PAGE_SIZE); + buf = ut_malloc(2 * UNIV_PAGE_SIZE); /* Align the memory for a possible read from a raw device */ - buf = ut_align(buf2, UNIV_PAGE_SIZE); + page = ut_align(buf, UNIV_PAGE_SIZE); - os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE); + os_file_read(data_file, page, 0, 0, UNIV_PAGE_SIZE); - flushed_lsn = mach_read_from_8(buf + FIL_PAGE_FILE_FLUSH_LSN); + *flags = mach_read_from_4(page + + FSP_HEADER_OFFSET + FSP_SPACE_FLAGS); - ut_free(buf2); + flushed_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN); + + ut_free(buf); if (!one_read_already) { *min_flushed_lsn = flushed_lsn; @@ -3174,8 +3182,11 @@ fil_open_single_table_tablespace( accessing the first page of the file */ ulint id, /*!< in: space id */ ulint flags, /*!< in: tablespace flags */ - const char* name) /*!< in: table name in the + const char* name, /*!< in: table name in the databasename/tablename format */ + trx_t* trx) /*!< in: transaction. This is only used + for IMPORT TABLESPACE, must be NULL + otherwise */ { os_file_t file; char* filepath; @@ -3393,6 +3404,11 @@ skip_info: /* over write space id of all pages */ rec_offs_init(offsets_); + /* Unlock the data dictionary to not block queries + accessing other tables */ + ut_a(trx); + row_mysql_unlock_data_dictionary(trx); + fprintf(stderr, "InnoDB: Progress in %%:"); for (offset = 0; offset < free_limit_bytes; @@ -3594,6 +3610,9 @@ skip_write: fprintf(stderr, " done.\n"); + /* Reacquire the data dictionary lock */ + row_mysql_lock_data_dictionary(trx); + /* update SYS_INDEXES set root page */ index = dict_table_get_first_index(table); while (index) { @@ -3729,7 +3748,6 @@ func_exit: ulint page_no; ulint zip_size; ulint height; - ulint root_height = 0; rec_t* node_ptr; dict_table_t* table; dict_index_t* index; @@ -3768,7 +3786,6 @@ func_exit: if (height == ULINT_UNDEFINED) { height = btr_page_get_level(page, &mtr); - root_height = height; } if (height == 0) { diff --git a/fsp/fsp0fsp.c b/fsp/fsp0fsp.c index 5e3959a3c7f..6102c5decd8 100644 --- a/fsp/fsp0fsp.c +++ b/fsp/fsp0fsp.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ @@ -50,67 +50,6 @@ Created 11/29/1995 Heikki Tuuri #include "dict0mem.h" #include "trx0sys.h" -#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header - within a file page */ - -/* The data structures in files are defined just as byte strings in C */ -typedef byte fsp_header_t; -typedef byte xdes_t; - -/* SPACE HEADER - ============ - -File space header data structure: this data structure is contained in the -first page of a space. The space for this header is reserved in every extent -descriptor page, but used only in the first. */ - -/*-------------------------------------*/ -#define FSP_SPACE_ID 0 /* space id */ -#define FSP_NOT_USED 4 /* this field contained a value up to - which we know that the modifications - in the database have been flushed to - the file space; not used now */ -#define FSP_SIZE 8 /* Current size of the space in - pages */ -#define FSP_FREE_LIMIT 12 /* Minimum page number for which the - free list has not been initialized: - the pages >= this limit are, by - definition, free; note that in a - single-table tablespace where size - < 64 pages, this number is 64, i.e., - we have initialized the space - about the first extent, but have not - physically allocted those pages to the - file */ -#define FSP_SPACE_FLAGS 16 /* table->flags & ~DICT_TF_COMPACT */ -#define FSP_FRAG_N_USED 20 /* number of used pages in the - FSP_FREE_FRAG list */ -#define FSP_FREE 24 /* list of free extents */ -#define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE) - /* list of partially free extents not - belonging to any segment */ -#define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE) - /* list of full extents not belonging - to any segment */ -#define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE) - /* 8 bytes which give the first unused - segment id */ -#define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE) - /* list of pages containing segment - headers, where all the segment inode - slots are reserved */ -#define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE) - /* list of pages containing segment - headers, where not all the segment - header slots are reserved */ -/*-------------------------------------*/ -/* File space header size */ -#define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE) - -#define FSP_FREE_ADD 4 /* this many free extents are added - to the free list from above - FSP_FREE_LIMIT at a time */ - /* FILE SEGMENT INODE ================== diff --git a/ha/ha0ha.c b/ha/ha0ha.c index b28995553e0..2f5051e541f 100644 --- a/ha/ha0ha.c +++ b/ha/ha0ha.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -88,41 +88,6 @@ ha_create_func( return(table); } -/*************************************************************//** -Empties a hash table and frees the memory heaps. */ -UNIV_INTERN -void -ha_clear( -/*=====*/ - hash_table_t* table) /*!< in, own: hash table */ -{ - ulint i; - ulint n; - - ut_ad(table); - ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); -#ifdef UNIV_SYNC_DEBUG - /* cannot identificate which btr_search_latch[i] for now */ - //ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE)); -#endif /* UNIV_SYNC_DEBUG */ - -#ifndef UNIV_HOTBACKUP - /* Free the memory heaps. */ - n = table->n_mutexes; - - for (i = 0; i < n; i++) { - mem_heap_free(table->heaps[i]); - } -#endif /* !UNIV_HOTBACKUP */ - - /* Clear the hash table. */ - n = hash_get_n_cells(table); - - for (i = 0; i < n; i++) { - hash_get_nth_cell(table, i)->node = NULL; - } -} - /*************************************************************//** Inserts an entry into a hash table. If an entry with the same fold number is found, its node is updated to point to the new data, and no new node @@ -141,7 +106,7 @@ ha_insert_for_fold_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block, /*!< in: buffer block containing the data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* data) /*!< in: data, must not be NULL */ + const rec_t* data) /*!< in: data, must not be NULL */ { hash_cell_t* cell; ha_node_t* node; @@ -154,7 +119,11 @@ ha_insert_for_fold_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG ut_a(block->frame == page_align(data)); #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ +#ifdef UNIV_SYNC_DEBUG + ut_ad(rw_lock_own(block->btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ ASSERT_HASH_MUTEX_OWN(table, fold); + ut_ad(btr_search_enabled); hash = hash_calc_hash(fold, table); @@ -174,7 +143,6 @@ ha_insert_for_fold_func( prev_block->n_pointers--; block->n_pointers++; } - ut_ad(!btr_search_fully_disabled); # endif /* !UNIV_HOTBACKUP */ prev_node->block = block; @@ -187,13 +155,6 @@ ha_insert_for_fold_func( prev_node = prev_node->next; } - /* We are in the process of disabling hash index, do not add - new chain node */ - if (!btr_search_enabled) { - ut_ad(!btr_search_fully_disabled); - return(TRUE); - } - /* We have to allocate a new chain node */ node = mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t)); @@ -251,6 +212,10 @@ ha_delete_hash_node( { ut_ad(table); ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); +#ifdef UNIV_SYNC_DEBUG + // ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + ut_ad(btr_search_enabled); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG # ifndef UNIV_HOTBACKUP if (table->adaptive) { @@ -273,11 +238,11 @@ ha_search_and_update_if_found_func( /*===============================*/ hash_table_t* table, /*!< in/out: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data, /*!< in: pointer to the data */ + const rec_t* data, /*!< in: pointer to the data */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* new_block,/*!< in: block containing new_data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* new_data)/*!< in: new pointer to the data */ + const rec_t* new_data)/*!< in: new pointer to the data */ { ha_node_t* node; @@ -287,6 +252,13 @@ ha_search_and_update_if_found_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG ut_a(new_block->frame == page_align(new_data)); #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ +#ifdef UNIV_SYNC_DEBUG + // ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + + if (!btr_search_enabled) { + return; + } node = ha_search_with_data(table, fold, data); @@ -323,6 +295,10 @@ ha_remove_all_nodes_to_page( ut_ad(table); ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ASSERT_HASH_MUTEX_OWN(table, fold); +#ifdef UNIV_SYNC_DEBUG + // ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + ut_ad(btr_search_enabled); node = ha_chain_get_first(table, fold); diff --git a/handler/ha_innodb.cc b/handler/ha_innodb.cc index 26212cca36e..9b07c82c037 100644 --- a/handler/ha_innodb.cc +++ b/handler/ha_innodb.cc @@ -375,6 +375,9 @@ static PSI_file_info all_innodb_files[] = { static INNOBASE_SHARE *get_share(const char *table_name); static void free_share(INNOBASE_SHARE *share); static int innobase_close_connection(handlerton *hton, THD* thd); +#ifdef EXTENDED_FOR_COMMIT_ORDERED +static void innobase_commit_ordered(handlerton *hton, THD* thd, bool all); +#endif static int innobase_commit(handlerton *hton, THD* thd, bool all); static int innobase_rollback(handlerton *hton, THD* thd, bool all); static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, @@ -1699,7 +1702,10 @@ innobase_trx_init( trx_t* trx) /*!< in/out: InnoDB transaction handle */ { DBUG_ENTER("innobase_trx_init"); +#ifndef EXTENDED_FOR_COMMIT_ORDERED + /* used by innobase_commit_ordered */ DBUG_ASSERT(EQ_CURRENT_THD(thd)); +#endif DBUG_ASSERT(thd == trx->mysql_thd); trx->check_foreigns = !thd_test_options( @@ -1760,7 +1766,10 @@ check_trx_exists( { trx_t*& trx = thd_to_trx(thd); +#ifndef EXTENDED_FOR_COMMIT_ORDERED + /* used by innobase_commit_ordered */ ut_ad(EQ_CURRENT_THD(thd)); +#endif if (trx == NULL) { trx = innobase_trx_allocate(thd); @@ -1846,6 +1855,7 @@ trx_deregister_from_2pc( { trx->is_registered = 0; trx->owns_prepare_mutex = 0; + trx->called_commit_ordered = 0; } /*********************************************************************//** @@ -1860,6 +1870,29 @@ trx_has_prepare_commit_mutex( return(trx->owns_prepare_mutex == 1); } +/*********************************************************************//** +*/ +static inline +void +trx_called_commit_ordered_set( +/*==========================*/ + trx_t* trx) +{ + ut_a(trx_is_registered_for_2pc(trx)); + trx->called_commit_ordered = 1; +} + +/*********************************************************************//** +*/ +static inline +bool +trx_called_commit_ordered( +/*======================*/ + const trx_t* trx) +{ + return(trx->called_commit_ordered == 1); +} + /*********************************************************************//** Check if transaction is started. @reutrn true if transaction is in state started */ @@ -2435,6 +2468,9 @@ innobase_init( innobase_hton->savepoint_set=innobase_savepoint; innobase_hton->savepoint_rollback=innobase_rollback_to_savepoint; innobase_hton->savepoint_release=innobase_release_savepoint; +#ifdef EXTENDED_FOR_COMMIT_ORDERED + innobase_hton->commit_ordered=innobase_commit_ordered; +#endif innobase_hton->commit=innobase_commit; innobase_hton->rollback=innobase_rollback; innobase_hton->prepare=innobase_xa_prepare; @@ -3031,7 +3067,6 @@ skip_overwrite: /* Get the current high water mark format. */ innobase_file_format_max = (char*) trx_sys_file_format_max_get(); - btr_search_fully_disabled = (!btr_search_enabled); DBUG_RETURN(FALSE); error: DBUG_RETURN(TRUE); @@ -3188,6 +3223,126 @@ innobase_start_trx_and_assign_read_view( DBUG_RETURN(0); } +#ifdef EXTENDED_FOR_COMMIT_ORDERED +/* MEMO: + InnoDB is coded with intention that always trx is accessed by the owner thd. + (not protected by any mutex/lock) + So, the caller of innobase_commit_ordered() should be conscious of + cache coherency between multi CPU about the trx, if called from another thd. + + MariaDB's first implementation about it seems the cherency is protected by + the pthread_mutex LOCK_wakeup_ready. So, no problem for now. + + But we should be aware the importance of the coherency. + */ +/*****************************************************************//** +low function function innobase_commit_ordered().*/ +static +void +innobase_commit_ordered_low( +/*========================*/ + trx_t* trx, /*!< in: Innodb transaction */ + THD* thd) /*!< in: MySQL thread handle */ +{ + ulonglong tmp_pos; + DBUG_ENTER("innobase_commit_ordered"); + + /* This part was from innobase_commit() */ + + /* We need current binlog position for ibbackup to work. + Note, the position is current because commit_ordered is guaranteed + to be called in same sequenece as writing to binlog. */ +retry: + if (innobase_commit_concurrency > 0) { + mysql_mutex_lock(&commit_cond_m); + commit_threads++; + + if (commit_threads > innobase_commit_concurrency) { + commit_threads--; + mysql_cond_wait(&commit_cond, + &commit_cond_m); + mysql_mutex_unlock(&commit_cond_m); + goto retry; + } + else { + mysql_mutex_unlock(&commit_cond_m); + } + } + + mysql_bin_log_commit_pos(thd, &tmp_pos, &(trx->mysql_log_file_name)); + trx->mysql_log_offset = (ib_int64_t) tmp_pos; + + /* Don't do write + flush right now. For group commit + to work we want to do the flush in the innobase_commit() + method, which runs without holding any locks. */ + trx->flush_log_later = TRUE; + innobase_commit_low(trx); + trx->flush_log_later = FALSE; + + if (innobase_commit_concurrency > 0) { + mysql_mutex_lock(&commit_cond_m); + commit_threads--; + mysql_cond_signal(&commit_cond); + mysql_mutex_unlock(&commit_cond_m); + } + + DBUG_VOID_RETURN; +} + +/*****************************************************************//** +Perform the first, fast part of InnoDB commit. + +Doing it in this call ensures that we get the same commit order here +as in binlog and any other participating transactional storage engines. + +Note that we want to do as little as really needed here, as we run +under a global mutex. The expensive fsync() is done later, in +innobase_commit(), without a lock so group commit can take place. + +Note also that this method can be called from a different thread than +the one handling the rest of the transaction. */ +static +void +innobase_commit_ordered( +/*====================*/ + handlerton *hton, /*!< in: Innodb handlerton */ + THD* thd, /*!< in: MySQL thread handle of the user for whom + the transaction should be committed */ + bool all) /*!< in: TRUE - commit transaction + FALSE - the current SQL statement ended */ +{ + trx_t* trx; + DBUG_ENTER("innobase_commit_ordered"); + DBUG_ASSERT(hton == innodb_hton_ptr); + + trx = check_trx_exists(thd); + + /* Since we will reserve the kernel mutex, we have to release + the search system latch first to obey the latching order. */ + + if (trx->has_search_latch) { + trx_search_latch_release_if_reserved(trx); + } + + if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) { + /* We cannot throw error here; instead we will catch this error + again in innobase_commit() and report it from there. */ + DBUG_VOID_RETURN; + } + + /* commit_ordered is only called when committing the whole transaction + (or an SQL statement when autocommit is on). */ + DBUG_ASSERT(all || + (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))); + + innobase_commit_ordered_low(trx, thd); + + trx_called_commit_ordered_set(trx); + + DBUG_VOID_RETURN; +} +#endif /* EXTENDED_FOR_COMMIT_ORDERED */ + /*****************************************************************//** Commits a transaction in an InnoDB database or marks an SQL statement ended. @@ -3239,6 +3394,16 @@ innobase_commit( /* We were instructed to commit the whole transaction, or this is an SQL statement end and autocommit is on */ +#ifdef EXTENDED_FOR_COMMIT_ORDERED + ut_ad(!trx_has_prepare_commit_mutex(trx)); + + /* Run the fast part of commit if we did not already. */ + if (!trx_called_commit_ordered(trx)) { + innobase_commit_ordered_low(trx, thd); + } +#else + ut_ad(!trx_called_commit_ordered(trx)); + /* We need current binlog position for ibbackup to work. Note, the position is current because of prepare_commit_mutex */ @@ -3293,6 +3458,7 @@ retry: mysql_mutex_unlock(&prepare_commit_mutex); } +#endif /* EXTENDED_FOR_COMMIT_ORDERED */ trx_deregister_from_2pc(trx); @@ -5563,8 +5729,7 @@ no_commit: switch (sql_command) { case SQLCOM_LOAD: - if ((trx->duplicates - & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) { + if (trx->duplicates) { goto set_max_autoinc; } @@ -5745,14 +5910,15 @@ calc_row_difference( /* The field has changed */ ufield = uvect->fields + n_changed; + UNIV_MEM_INVALID(ufield, sizeof *ufield); /* Let us use a dummy dfield to make the conversion from the MySQL column format to the InnoDB format */ - dict_col_copy_type(prebuilt->table->cols + i, - dfield_get_type(&dfield)); - if (n_len != UNIV_SQL_NULL) { + dict_col_copy_type(prebuilt->table->cols + i, + dfield_get_type(&dfield)); + buf = row_mysql_store_col_in_innobase_format( &dfield, (byte*)buf, @@ -5760,7 +5926,7 @@ calc_row_difference( new_mysql_row_col, col_pack_len, dict_table_is_comp(prebuilt->table)); - dfield_copy_data(&ufield->new_val, &dfield); + dfield_copy(&ufield->new_val, &dfield); } else { dfield_set_null(&ufield->new_val); } @@ -5847,8 +6013,7 @@ ha_innobase::update_row( && table->next_number_field && new_row == table->record[0] && thd_sql_command(user_thd) == SQLCOM_INSERT - && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE)) - == TRX_DUP_IGNORE) { + && trx->duplicates) { ulonglong auto_inc; ulonglong col_max_value; @@ -6232,6 +6397,7 @@ ha_innobase::index_read( (byte*) key_ptr, (ulint) key_len, prebuilt->trx); + DBUG_ASSERT(prebuilt->search_tuple->n_fields > 0); } else { /* We position the cursor to the last or the first entry in the index */ @@ -6333,7 +6499,6 @@ ha_innobase::innobase_get_index( dict_index_t* index = 0; DBUG_ENTER("innobase_get_index"); - ha_statistic_increment(&SSV::ha_read_key_count); if (keynr != MAX_KEY && table->s->keys > 0) { key = table->key_info + keynr; @@ -6347,13 +6512,13 @@ ha_innobase::innobase_get_index( table. Only print message if the index translation table exists */ if (share->idx_trans_tbl.index_mapping) { - sql_print_error("InnoDB could not find " - "index %s key no %u for " - "table %s through its " - "index translation table", - key ? key->name : "NULL", - keynr, - prebuilt->table->name); + sql_print_warning("InnoDB could not find " + "index %s key no %u for " + "table %s through its " + "index translation table", + key ? key->name : "NULL", + keynr, + prebuilt->table->name); } index = dict_table_get_index_on_name(prebuilt->table, @@ -8128,6 +8293,7 @@ ha_innobase::records_in_range( mem_heap_t* heap; DBUG_ENTER("records_in_range"); + DBUG_ASSERT(min_key || max_key); ut_a(prebuilt->trx == thd_to_trx(ha_thd())); @@ -8177,6 +8343,9 @@ ha_innobase::records_in_range( (const uchar*) 0), (ulint) (min_key ? min_key->length : 0), prebuilt->trx); + DBUG_ASSERT(min_key + ? range_start->n_fields > 0 + : range_start->n_fields == 0); row_sel_convert_mysql_key_to_innobase( range_end, (byte*) key_val_buff2, @@ -8185,6 +8354,9 @@ ha_innobase::records_in_range( (const uchar*) 0), (ulint) (max_key ? max_key->length : 0), prebuilt->trx); + DBUG_ASSERT(max_key + ? range_end->n_fields > 0 + : range_end->n_fields == 0); mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag : HA_READ_KEY_EXACT); @@ -8928,7 +9100,10 @@ ha_innobase::check( putc('\n', stderr); #endif - if (!btr_validate_index(index, prebuilt->trx)) { + /* If this is an index being created, break */ + if (*index->name == TEMP_INDEX_PREFIX) { + break; + } else if (!btr_validate_index(index, prebuilt->trx)) { is_ok = FALSE; innobase_format_name( @@ -9481,6 +9656,7 @@ ha_innobase::extra( break; case HA_EXTRA_RESET_STATE: reset_template(prebuilt); + thd_to_trx(ha_thd())->duplicates = 0; break; case HA_EXTRA_NO_KEYREAD: prebuilt->read_just_key = 0; @@ -9498,19 +9674,18 @@ ha_innobase::extra( parameters below. We must not invoke update_thd() either, because the calling threads may change. CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */ - case HA_EXTRA_IGNORE_DUP_KEY: + case HA_EXTRA_INSERT_WITH_UPDATE: thd_to_trx(ha_thd())->duplicates |= TRX_DUP_IGNORE; break; + case HA_EXTRA_NO_IGNORE_DUP_KEY: + thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_IGNORE; + break; case HA_EXTRA_WRITE_CAN_REPLACE: thd_to_trx(ha_thd())->duplicates |= TRX_DUP_REPLACE; break; case HA_EXTRA_WRITE_CANNOT_REPLACE: thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_REPLACE; break; - case HA_EXTRA_NO_IGNORE_DUP_KEY: - thd_to_trx(ha_thd())->duplicates &= - ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE); - break; default:/* Do nothing */ ; } @@ -10973,6 +11148,7 @@ innobase_xa_prepare( srv_active_wake_master_thread(); +#ifndef EXTENDED_FOR_COMMIT_ORDERED if (thd_sql_command(thd) != SQLCOM_XA_PREPARE && (all || !thd_test_options( @@ -10999,6 +11175,7 @@ innobase_xa_prepare( mysql_mutex_lock(&prepare_commit_mutex); trx_owns_prepare_commit_mutex_set(trx); } +#endif /* ifndef EXTENDED_FOR_COMMIT_ORDERED */ return(error); } @@ -12269,10 +12446,42 @@ static MYSQL_SYSVAR_ULONG(checkpoint_age_target, srv_checkpoint_age_target, "Control soft limit of checkpoint age. (0 : not control)", NULL, NULL, 0, 0, ~0UL, 0); -static MYSQL_SYSVAR_ULONG(flush_neighbor_pages, srv_flush_neighbor_pages, - PLUGIN_VAR_RQCMDARG, - "Enable/Disable flushing also neighbor pages. 0:disable 1:enable", - NULL, NULL, 1, 0, 1, 0); +static +void +innodb_flush_neighbor_pages_update( + THD* thd, + struct st_mysql_sys_var* var, + void* var_ptr, + const void* save) +{ + *(long *)var_ptr = (*(long *)save) % 3; +} + +const char *flush_neighbor_pages_names[]= +{ + "none", /* 0 */ + "area", + "cont", /* 2 */ + /* For compatibility with the older patch */ + "0", /* "none" + 3 */ + "1", /* "area" + 3 */ + "2", /* "cont" + 3 */ + NullS +}; + +TYPELIB flush_neighbor_pages_typelib= +{ + array_elements(flush_neighbor_pages_names) - 1, + "flush_neighbor_pages_typelib", + flush_neighbor_pages_names, + NULL +}; + +static MYSQL_SYSVAR_ENUM(flush_neighbor_pages, srv_flush_neighbor_pages, + PLUGIN_VAR_RQCMDARG, "Neighbor page flushing behaviour: none: do not flush, " + "[area]: flush selected pages one-by-one, " + "cont: flush a contiguous block of pages", NULL, + innodb_flush_neighbor_pages_update, 1, &flush_neighbor_pages_typelib); static void @@ -12338,6 +12547,14 @@ static MYSQL_SYSVAR_ENUM(adaptive_flushing_method, srv_adaptive_flushing_method, "Choose method of innodb_adaptive_flushing. (native, [estimate], keep_average)", NULL, innodb_adaptive_flushing_method_update, 1, &adaptive_flushing_method_typelib); +#ifdef UNIV_DEBUG +static MYSQL_SYSVAR_ULONG(flush_checkpoint_debug, srv_flush_checkpoint_debug, + PLUGIN_VAR_RQCMDARG, + "Debug flags for InnoDB flushing and checkpointing (0=none," + "1=stop preflush and checkpointing)", + NULL, NULL, 0, 0, 1, 0); +#endif + static MYSQL_SYSVAR_ULONG(import_table_from_xtrabackup, srv_expand_import, PLUGIN_VAR_RQCMDARG, "Enable/Disable converting automatically *.ibd files when import tablespace.", @@ -12484,6 +12701,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(purge_threads), MYSQL_SYSVAR(purge_batch_size), MYSQL_SYSVAR(rollback_segments), +#ifdef UNIV_DEBUG + MYSQL_SYSVAR(flush_checkpoint_debug), +#endif MYSQL_SYSVAR(corrupt_table_action), MYSQL_SYSVAR(lazy_drop_table), MYSQL_SYSVAR(fake_changes), diff --git a/handler/ha_innodb.h b/handler/ha_innodb.h index dbd360e0ec9..9506f309827 100644 --- a/handler/ha_innodb.h +++ b/handler/ha_innodb.h @@ -240,6 +240,12 @@ extern "C" { struct charset_info_st *thd_charset(MYSQL_THD thd); LEX_STRING *thd_query_string(MYSQL_THD thd); +#ifdef EXTENDED_FOR_COMMIT_ORDERED +/** Get the file name and position of the MySQL binlog corresponding to the + * current commit. + */ +void mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file); +#else /** Get the file name of the MySQL binlog. * @return the name of the binlog file */ @@ -249,6 +255,7 @@ const char* mysql_bin_log_file_name(void); * @return byte offset from the beginning of the binlog */ ulonglong mysql_bin_log_file_pos(void); +#endif /** Check if a user thread is a replication slave thread diff --git a/handler/i_s.cc b/handler/i_s.cc index c0ad731e336..a2497518da3 100644 --- a/handler/i_s.cc +++ b/handler/i_s.cc @@ -2062,7 +2062,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_tables = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* flags for plugin */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL) }; /* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLESTATS */ @@ -2359,7 +2363,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_tablestats = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* flags for plugin */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL) }; /* Fields of the dynamic table INFORMATION_SCHEMA.SYS_INDEXES */ @@ -2605,7 +2613,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_indexes = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* flags for plugin */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL) }; /* Fields of the dynamic table INFORMATION_SCHEMA.SYS_COLUMNS */ @@ -2841,7 +2853,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_columns = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* flags for plugin */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL) }; /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_fields */ static ST_FIELD_INFO innodb_sys_fields_fields_info[] = @@ -3048,7 +3064,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_fields = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* flags for plugin */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL) }; /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign */ @@ -3269,7 +3289,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_foreign = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* flags for plugin */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL) }; /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign_cols */ static ST_FIELD_INFO innodb_sys_foreign_cols_fields_info[] = @@ -3483,7 +3507,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_foreign_cols = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* flags for plugin */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL) }; /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_stats */ @@ -3698,7 +3726,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_stats = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* flags for plugin */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL) }; /*********************************************************************** @@ -3861,7 +3893,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_rseg = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* Plugin flags */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL), }; /*********************************************************************** @@ -4189,7 +4225,8 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_table_stats = STRUCT_FLD(version, 0x0100 /* 1.0 */), STRUCT_FLD(status_vars, NULL), STRUCT_FLD(system_vars, NULL), - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + STRUCT_FLD(flags, 0UL) }; UNIV_INTERN struct st_mysql_plugin i_s_innodb_index_stats = @@ -4205,7 +4242,8 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_index_stats = STRUCT_FLD(version, 0x0100 /* 1.0 */), STRUCT_FLD(status_vars, NULL), STRUCT_FLD(system_vars, NULL), - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + STRUCT_FLD(flags, 0UL) }; /*********************************************************************** @@ -4371,7 +4409,8 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_admin_command = STRUCT_FLD(version, 0x0100 /* 1.0 */), STRUCT_FLD(status_vars, NULL), STRUCT_FLD(system_vars, NULL), - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + STRUCT_FLD(flags, 0UL) }; /*********************************************************************** @@ -4756,7 +4795,7 @@ i_s_innodb_buffer_pool_pages_index_fill( table->field[2]->store(block->page.offset); table->field[3]->store(page_get_n_recs(frame)); table->field[4]->store(page_get_data_size(frame)); - table->field[5]->store(block->is_hashed); + table->field[5]->store(block->index != NULL); table->field[6]->store(block->page.access_time); table->field[7]->store(block->page.newest_modification != 0); table->field[8]->store(block->page.oldest_modification != 0); @@ -4970,7 +5009,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_buffer_pool_pages = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* flags for plugin */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL) }; UNIV_INTERN struct st_mysql_plugin i_s_innodb_buffer_pool_pages_index = @@ -5019,7 +5062,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_buffer_pool_pages_index = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* flags for plugin */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL) }; UNIV_INTERN struct st_mysql_plugin i_s_innodb_buffer_pool_pages_blob = @@ -5068,6 +5115,10 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_buffer_pool_pages_blob = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* flags for plugin */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL) }; diff --git a/ibuf/ibuf0ibuf.c b/ibuf/ibuf0ibuf.c index 7def360867d..00b7ea7347d 100644 --- a/ibuf/ibuf0ibuf.c +++ b/ibuf/ibuf0ibuf.c @@ -254,11 +254,20 @@ ibuf_count_check( list of the ibuf */ /* @} */ +#define IBUF_REC_FIELD_SPACE 0 /*!< in the pre-4.1 format, + the page number. later, the space_id */ +#define IBUF_REC_FIELD_MARKER 1 /*!< starting with 4.1, a marker + consisting of 1 byte that is 0 */ +#define IBUF_REC_FIELD_PAGE 2 /*!< starting with 4.1, the + page number */ +#define IBUF_REC_FIELD_METADATA 3 /* the metadata field */ +#define IBUF_REC_FIELD_USER 4 /* first user field */ + /* Various constants for checking the type of an ibuf record and extracting data from it. For details, see the description of the record format at the top of this file. */ -/** @name Format of the fourth column of an insert buffer record +/** @name Format of the IBUF_REC_FIELD_METADATA of an insert buffer record The fourth column in the MySQL 5.5 format contains an operation type, counter, and some flags. */ /* @{ */ @@ -1275,13 +1284,13 @@ ibuf_rec_get_page_no_func( ut_ad(ibuf_inside(mtr)); ut_ad(rec_get_n_fields_old(rec) > 2); - field = rec_get_nth_field_old(rec, 1, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_MARKER, &len); if (len == 1) { /* This is of the >= 4.1.x record format */ ut_a(trx_sys_multiple_tablespace_format); - field = rec_get_nth_field_old(rec, 2, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_PAGE, &len); } else { ut_a(trx_doublewrite_must_reset_space_ids); ut_a(!trx_sys_multiple_tablespace_format); @@ -1321,13 +1330,13 @@ ibuf_rec_get_space_func( ut_ad(ibuf_inside(mtr)); ut_ad(rec_get_n_fields_old(rec) > 2); - field = rec_get_nth_field_old(rec, 1, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_MARKER, &len); if (len == 1) { /* This is of the >= 4.1.x record format */ ut_a(trx_sys_multiple_tablespace_format); - field = rec_get_nth_field_old(rec, 0, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_SPACE, &len); ut_a(len == 4); return(mach_read_from_4(field)); @@ -1377,9 +1386,9 @@ ibuf_rec_get_info_func( || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX)); ut_ad(ibuf_inside(mtr)); fields = rec_get_n_fields_old(rec); - ut_a(fields > 4); + ut_a(fields > IBUF_REC_FIELD_USER); - types = rec_get_nth_field_old(rec, 3, &len); + types = rec_get_nth_field_old(rec, IBUF_REC_FIELD_METADATA, &len); info_len_local = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE; @@ -1405,7 +1414,8 @@ ibuf_rec_get_info_func( ut_a(op_local < IBUF_OP_COUNT); ut_a((len - info_len_local) == - (fields - 4) * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); + (fields - IBUF_REC_FIELD_USER) + * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); if (op) { *op = op_local; @@ -1449,7 +1459,7 @@ ibuf_rec_get_op_type_func( ut_ad(ibuf_inside(mtr)); ut_ad(rec_get_n_fields_old(rec) > 2); - (void) rec_get_nth_field_old(rec, 1, &len); + (void) rec_get_nth_field_old(rec, IBUF_REC_FIELD_MARKER, &len); if (len > 1) { /* This is a < 4.1.x format record */ @@ -1478,12 +1488,12 @@ ibuf_rec_get_counter( const byte* ptr; ulint len; - if (rec_get_n_fields_old(rec) < 4) { + if (rec_get_n_fields_old(rec) <= IBUF_REC_FIELD_METADATA) { return(ULINT_UNDEFINED); } - ptr = rec_get_nth_field_old(rec, 3, &len); + ptr = rec_get_nth_field_old(rec, IBUF_REC_FIELD_METADATA, &len); if (len >= 2) { @@ -1708,7 +1718,7 @@ ibuf_build_entry_from_ibuf_rec_func( || mtr_memo_contains_page(mtr, ibuf_rec, MTR_MEMO_PAGE_S_FIX)); ut_ad(ibuf_inside(mtr)); - data = rec_get_nth_field_old(ibuf_rec, 1, &len); + data = rec_get_nth_field_old(ibuf_rec, IBUF_REC_FIELD_MARKER, &len); if (len > 1) { /* This a < 4.1.x format record */ @@ -1720,13 +1730,13 @@ ibuf_build_entry_from_ibuf_rec_func( ut_a(trx_sys_multiple_tablespace_format); ut_a(*data == 0); - ut_a(rec_get_n_fields_old(ibuf_rec) > 4); + ut_a(rec_get_n_fields_old(ibuf_rec) > IBUF_REC_FIELD_USER); - n_fields = rec_get_n_fields_old(ibuf_rec) - 4; + n_fields = rec_get_n_fields_old(ibuf_rec) - IBUF_REC_FIELD_USER; tuple = dtuple_create(heap, n_fields); - types = rec_get_nth_field_old(ibuf_rec, 3, &len); + types = rec_get_nth_field_old(ibuf_rec, IBUF_REC_FIELD_METADATA, &len); ibuf_rec_get_info(mtr, ibuf_rec, NULL, &comp, &info_len, NULL); @@ -1740,7 +1750,8 @@ ibuf_build_entry_from_ibuf_rec_func( for (i = 0; i < n_fields; i++) { field = dtuple_get_nth_field(tuple, i); - data = rec_get_nth_field_old(ibuf_rec, i + 4, &len); + data = rec_get_nth_field_old( + ibuf_rec, i + IBUF_REC_FIELD_USER, &len); dfield_set_data(field, data, len); @@ -1787,7 +1798,7 @@ ibuf_rec_get_size( field_offset = 2; types_offset = DATA_ORDER_NULL_TYPE_BUF_SIZE; } else { - field_offset = 4; + field_offset = IBUF_REC_FIELD_USER; types_offset = DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE; } @@ -1848,7 +1859,7 @@ ibuf_rec_get_volume_func( ut_ad(ibuf_inside(mtr)); ut_ad(rec_get_n_fields_old(ibuf_rec) > 2); - data = rec_get_nth_field_old(ibuf_rec, 1, &len); + data = rec_get_nth_field_old(ibuf_rec, IBUF_REC_FIELD_MARKER, &len); pre_4_1 = (len > 1); if (pre_4_1) { @@ -1871,7 +1882,8 @@ ibuf_rec_get_volume_func( ut_a(trx_sys_multiple_tablespace_format); ut_a(*data == 0); - types = rec_get_nth_field_old(ibuf_rec, 3, &len); + types = rec_get_nth_field_old( + ibuf_rec, IBUF_REC_FIELD_METADATA, &len); ibuf_rec_get_info(mtr, ibuf_rec, &op, &comp, &info_len, NULL); @@ -1901,7 +1913,8 @@ ibuf_rec_get_volume_func( } types += info_len; - n_fields = rec_get_n_fields_old(ibuf_rec) - 4; + n_fields = rec_get_n_fields_old(ibuf_rec) + - IBUF_REC_FIELD_USER; } data_size = ibuf_rec_get_size(ibuf_rec, types, n_fields, pre_4_1, comp); @@ -1956,11 +1969,11 @@ ibuf_entry_build( n_fields = dtuple_get_n_fields(entry); - tuple = dtuple_create(heap, n_fields + 4); + tuple = dtuple_create(heap, n_fields + IBUF_REC_FIELD_USER); /* 1) Space Id */ - field = dtuple_get_nth_field(tuple, 0); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_SPACE); buf = mem_heap_alloc(heap, 4); @@ -1970,7 +1983,7 @@ ibuf_entry_build( /* 2) Marker byte */ - field = dtuple_get_nth_field(tuple, 1); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_MARKER); buf = mem_heap_alloc(heap, 1); @@ -1982,7 +1995,7 @@ ibuf_entry_build( /* 3) Page number */ - field = dtuple_get_nth_field(tuple, 2); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_PAGE); buf = mem_heap_alloc(heap, 4); @@ -2030,10 +2043,7 @@ ibuf_entry_build( ulint fixed_len; const dict_field_t* ifield; - /* We add 4 below because we have the 4 extra fields at the - start of an ibuf record */ - - field = dtuple_get_nth_field(tuple, i + 4); + field = dtuple_get_nth_field(tuple, i + IBUF_REC_FIELD_USER); entry_field = dtuple_get_nth_field(entry, i); dfield_copy(field, entry_field); @@ -2066,13 +2076,13 @@ ibuf_entry_build( /* 4) Type info, part #2 */ - field = dtuple_get_nth_field(tuple, 3); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_METADATA); dfield_set_data(field, type_info, ti - type_info); /* Set all the types in the new tuple binary */ - dtuple_set_types_binary(tuple, n_fields + 4); + dtuple_set_types_binary(tuple, n_fields + IBUF_REC_FIELD_USER); return(tuple); } @@ -2132,11 +2142,11 @@ ibuf_new_search_tuple_build( ut_a(trx_sys_multiple_tablespace_format); - tuple = dtuple_create(heap, 3); + tuple = dtuple_create(heap, IBUF_REC_FIELD_METADATA); /* Store the space id in tuple */ - field = dtuple_get_nth_field(tuple, 0); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_SPACE); buf = mem_heap_alloc(heap, 4); @@ -2146,7 +2156,7 @@ ibuf_new_search_tuple_build( /* Store the new format record marker byte */ - field = dtuple_get_nth_field(tuple, 1); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_MARKER); buf = mem_heap_alloc(heap, 1); @@ -2156,7 +2166,7 @@ ibuf_new_search_tuple_build( /* Store the page number in tuple */ - field = dtuple_get_nth_field(tuple, 2); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_PAGE); buf = mem_heap_alloc(heap, 4); @@ -2164,7 +2174,7 @@ ibuf_new_search_tuple_build( dfield_set_data(field, buf, 4); - dtuple_set_types_binary(tuple, 3); + dtuple_set_types_binary(tuple, IBUF_REC_FIELD_METADATA); return(tuple); } @@ -2833,8 +2843,10 @@ ibuf_get_volume_buffered_hash( ulint fold; ulint bitmask; - len = ibuf_rec_get_size(rec, types, rec_get_n_fields_old(rec) - 4, - FALSE, comp); + len = ibuf_rec_get_size( + rec, types, + rec_get_n_fields_old(rec) - IBUF_REC_FIELD_USER, + FALSE, comp); fold = ut_fold_binary(data, len); hash += (fold / (CHAR_BIT * sizeof *hash)) % size; @@ -2886,8 +2898,8 @@ ibuf_get_volume_buffered_count_func( ut_ad(ibuf_inside(mtr)); n_fields = rec_get_n_fields_old(rec); - ut_ad(n_fields > 4); - n_fields -= 4; + ut_ad(n_fields > IBUF_REC_FIELD_USER); + n_fields -= IBUF_REC_FIELD_USER; rec_get_nth_field_offs_old(rec, 1, &len); /* This function is only invoked when buffering new @@ -2896,7 +2908,7 @@ ibuf_get_volume_buffered_count_func( ut_a(len == 1); ut_ad(trx_sys_multiple_tablespace_format); - types = rec_get_nth_field_old(rec, 3, &len); + types = rec_get_nth_field_old(rec, IBUF_REC_FIELD_METADATA, &len); switch (UNIV_EXPECT(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE, IBUF_REC_INFO_SIZE)) { @@ -3208,7 +3220,7 @@ ibuf_update_max_tablespace_id(void) } else { rec = btr_pcur_get_rec(&pcur); - field = rec_get_nth_field_old(rec, 0, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_SPACE, &len); ut_a(len == 4); @@ -3230,10 +3242,12 @@ ibuf_update_max_tablespace_id(void) ibuf_get_entry_counter_low_func(rec,space,page_no) #endif /****************************************************************//** -Helper function for ibuf_set_entry_counter. Checks if rec is for (space, -page_no), and if so, reads counter value from it and returns that + 1. -Otherwise, returns 0. -@return new counter value, or 0 */ +Helper function for ibuf_get_entry_counter_func. Checks if rec is for +(space, page_no), and if so, reads counter value from it and returns +that + 1. +@retval ULINT_UNDEFINED if the record does not contain any counter +@retval 0 if the record is not for (space, page_no) +@retval 1 + previous counter value, otherwise */ static ulint ibuf_get_entry_counter_low_func( @@ -3254,7 +3268,7 @@ ibuf_get_entry_counter_low_func( || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX)); ut_ad(rec_get_n_fields_old(rec) > 2); - field = rec_get_nth_field_old(rec, 1, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_MARKER, &len); if (UNIV_UNLIKELY(len != 1)) { /* pre-4.1 format */ @@ -3267,7 +3281,7 @@ ibuf_get_entry_counter_low_func( ut_a(trx_sys_multiple_tablespace_format); /* Check the tablespace identifier. */ - field = rec_get_nth_field_old(rec, 0, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_SPACE, &len); ut_a(len == 4); if (mach_read_from_4(field) != space) { @@ -3276,7 +3290,7 @@ ibuf_get_entry_counter_low_func( } /* Check the page offset. */ - field = rec_get_nth_field_old(rec, 2, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_PAGE, &len); ut_a(len == 4); if (mach_read_from_4(field) != page_no) { @@ -3285,7 +3299,7 @@ ibuf_get_entry_counter_low_func( } /* Check if the record contains a counter field. */ - field = rec_get_nth_field_old(rec, 3, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_METADATA, &len); switch (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) { default: @@ -3301,147 +3315,61 @@ ibuf_get_entry_counter_low_func( } } +#ifdef UNIV_DEBUG +# define ibuf_get_entry_counter(space,page_no,rec,mtr,exact_leaf) \ + ibuf_get_entry_counter_func(space,page_no,rec,mtr,exact_leaf) +#else /* UNIV_DEBUG */ +# define ibuf_get_entry_counter(space,page_no,rec,mtr,exact_leaf) \ + ibuf_get_entry_counter_func(space,page_no,rec,exact_leaf) +#endif + /****************************************************************//** -Set the counter field in entry to the correct value based on the current +Calculate the counter field for an entry based on the current last record in ibuf for (space, page_no). -@return FALSE if we should abort this insertion to ibuf */ +@return the counter field, or ULINT_UNDEFINED +if we should abort this insertion to ibuf */ static -ibool -ibuf_set_entry_counter( -/*===================*/ - dtuple_t* entry, /*!< in/out: entry to patch */ +ulint +ibuf_get_entry_counter_func( +/*========================*/ ulint space, /*!< in: space id of entry */ ulint page_no, /*!< in: page number of entry */ - btr_pcur_t* pcur, /*!< in: pcur positioned on the record - found by btr_pcur_open(.., entry, - PAGE_CUR_LE, ..., pcur, ...) */ - ibool is_optimistic, /*!< in: is this an optimistic insert */ - mtr_t* mtr) /*!< in: mtr */ + const rec_t* rec, /*!< in: the record preceding the + insertion point */ +#ifdef UNIV_DEBUG + mtr_t* mtr, /*!< in: mini-transaction */ +#endif /* UNIV_DEBUG */ + ibool only_leaf) /*!< in: TRUE if this is the only + leaf page that can contain entries + for (space,page_no), that is, there + was no exact match for (space,page_no) + in the node pointer */ { - dfield_t* field; - byte* data; - ulint counter = 0; - - /* pcur points to either a user rec or to a page's infimum record. */ ut_ad(ibuf_inside(mtr)); - ut_ad(mtr_memo_contains(mtr, btr_pcur_get_block(pcur), - MTR_MEMO_PAGE_X_FIX)); - ut_ad(page_validate(btr_pcur_get_page(pcur), ibuf->index)); + ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)); + ut_ad(page_validate(page_align(rec), ibuf->index)); - if (btr_pcur_is_on_user_rec(pcur)) { - - counter = ibuf_get_entry_counter_low( - mtr, btr_pcur_get_rec(pcur), space, page_no); - - if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) { - /* The record lacks a counter field. - Such old records must be merged before - new records can be buffered. */ - - return(FALSE); - } - } else if (btr_pcur_is_before_first_in_tree(pcur, mtr)) { - /* Ibuf tree is either completely empty, or the insert - position is at the very first record of a non-empty tree. In - either case we have no previous records for (space, - page_no). */ - - counter = 0; - } else if (btr_pcur_is_before_first_on_page(pcur)) { - btr_cur_t* cursor = btr_pcur_get_btr_cur(pcur); - - if (cursor->low_match < 3) { - /* If low_match < 3, we know that the father node - pointer did not contain the searched for (space, - page_no), which means that the search ended on the - right page regardless of the counter value, and - since we're at the infimum record, there are no - existing records. */ - - counter = 0; - } else { - rec_t* rec; - const page_t* page; - buf_block_t* block; - page_t* prev_page; - ulint prev_page_no; - - ut_a(cursor->ibuf_cnt != ULINT_UNDEFINED); - - page = btr_pcur_get_page(pcur); - prev_page_no = btr_page_get_prev(page, mtr); - - ut_a(prev_page_no != FIL_NULL); - - block = buf_page_get( - IBUF_SPACE_ID, 0, prev_page_no, - RW_X_LATCH, mtr); - - buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); - - prev_page = buf_block_get_frame(block); - - rec = page_rec_get_prev( - page_get_supremum_rec(prev_page)); - - ut_ad(page_rec_is_user_rec(rec)); - - counter = ibuf_get_entry_counter_low( - mtr, rec, space, page_no); - - if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) { - /* The record lacks a counter field. - Such old records must be merged before - new records can be buffered. */ - - return(FALSE); - } - - if (counter < cursor->ibuf_cnt) { - /* Search ended on the wrong page. */ - - if (is_optimistic) { - /* In an optimistic insert, we can - shift the insert position to the left - page, since it only needs an X-latch - on the page itself, which the - original search acquired for us. */ - - btr_cur_position( - ibuf->index, rec, block, - btr_pcur_get_btr_cur(pcur)); - } else { - /* We can't shift the insert - position to the left page in a - pessimistic insert since it would - require an X-latch on the left - page's left page, so we have to - abort. */ - - return(FALSE); - } - } else { - /* The counter field in the father node is - the same as we would insert; we don't know - whether the insert should go to this page or - the left page (the later fields can differ), - so refuse the insert. */ - - return(FALSE); - } - } + if (page_rec_is_supremum(rec)) { + /* This is just for safety. The record should be a + page infimum or a user record. */ + ut_ad(0); + return(ULINT_UNDEFINED); + } else if (!page_rec_is_infimum(rec)) { + return(ibuf_get_entry_counter_low(mtr, rec, space, page_no)); + } else if (only_leaf + || fil_page_get_prev(page_align(rec)) == FIL_NULL) { + /* The parent node pointer did not contain the + searched for (space, page_no), which means that the + search ended on the correct page regardless of the + counter value, and since we're at the infimum record, + there are no existing records. */ + return(0); } else { - /* The cursor is not positioned at or before a user record. */ - return(FALSE); + /* We used to read the previous page here. It would + break the latching order, because the caller has + buffer-fixed an insert buffer bitmap page. */ + return(ULINT_UNDEFINED); } - - /* Patch counter value in already built entry. */ - field = dtuple_get_nth_field(entry, 3); - data = dfield_get_data(field); - - mach_write_to_2(data + IBUF_REC_OFFSET_COUNTER, counter); - - return(TRUE); } /*********************************************************************//** @@ -3650,16 +3578,27 @@ fail_exit: } } - /* Patch correct counter value to the entry to insert. This can - change the insert position, which can result in the need to abort in - some cases. */ - if (!no_counter - && !ibuf_set_entry_counter(ibuf_entry, space, page_no, &pcur, - mode == BTR_MODIFY_PREV, &mtr)) { -bitmap_fail: - ibuf_mtr_commit(&bitmap_mtr); + if (!no_counter) { + /* Patch correct counter value to the entry to + insert. This can change the insert position, which can + result in the need to abort in some cases. */ + ulint counter = ibuf_get_entry_counter( + space, page_no, btr_pcur_get_rec(&pcur), &mtr, + btr_pcur_get_btr_cur(&pcur)->low_match + < IBUF_REC_FIELD_METADATA); + dfield_t* field; - goto fail_exit; + if (counter == ULINT_UNDEFINED) { +bitmap_fail: + ibuf_mtr_commit(&bitmap_mtr); + goto fail_exit; + } + + field = dtuple_get_nth_field( + ibuf_entry, IBUF_REC_FIELD_METADATA); + mach_write_to_2( + (byte*) dfield_get_data(field) + + IBUF_REC_OFFSET_COUNTER, counter); } /* Set the bitmap bit denoting that the insert buffer contains @@ -4003,7 +3942,7 @@ ibuf_insert_to_index_page( ut_ad(ibuf_inside(mtr)); ut_ad(dtuple_check_typed(entry)); - ut_ad(!buf_block_align(page)->is_hashed); + ut_ad(!buf_block_align(page)->index); if (UNIV_UNLIKELY(dict_table_is_comp(index->table) != (ibool)!!page_is_comp(page))) { diff --git a/include/btr0cur.h b/include/btr0cur.h index be918439f59..4f33aacc48e 100644 --- a/include/btr0cur.h +++ b/include/btr0cur.h @@ -743,24 +743,6 @@ struct btr_cur_struct { NULL */ ulint fold; /*!< fold value used in the search if flag is BTR_CUR_HASH */ - /*----- Delete buffering -------*/ - ulint ibuf_cnt; /* in searches done on insert buffer - trees, this contains the "counter" - value (the first two bytes of the - fourth field) extracted from the - page above the leaf page, from the - father node pointer that pointed to - the leaf page. in other words, it - contains the minimum counter value - for records to be inserted on the - chosen leaf page. If for some reason - this can't be read, or if the search - ended on the leftmost leaf page in - the tree (in which case the father - node pointer had the 'minimum - record' flag set), this is - ULINT_UNDEFINED. */ - /*------------------------------*/ /* @} */ btr_path_t* path_arr; /*!< in estimating the number of rows in range, we store in this array diff --git a/include/btr0pcur.h b/include/btr0pcur.h index f605c476844..140f94466db 100644 --- a/include/btr0pcur.h +++ b/include/btr0pcur.h @@ -263,14 +263,6 @@ btr_pcur_commit_specify_mtr( /*========================*/ btr_pcur_t* pcur, /*!< in: persistent cursor */ mtr_t* mtr); /*!< in: mtr to commit */ -/**************************************************************//** -Tests if a cursor is detached: that is the latch mode is BTR_NO_LATCHES. -@return TRUE if detached */ -UNIV_INLINE -ibool -btr_pcur_is_detached( -/*=================*/ - btr_pcur_t* pcur); /*!< in: persistent cursor */ /*********************************************************//** Moves the persistent cursor to the next record in the tree. If no records are left, the cursor stays 'after last in tree'. diff --git a/include/btr0pcur.ic b/include/btr0pcur.ic index d86601e5a32..054ce753c7d 100644 --- a/include/btr0pcur.ic +++ b/include/btr0pcur.ic @@ -388,38 +388,6 @@ btr_pcur_commit_specify_mtr( pcur->pos_state = BTR_PCUR_WAS_POSITIONED; } -/**************************************************************//** -Sets the pcur latch mode to BTR_NO_LATCHES. */ -UNIV_INLINE -void -btr_pcur_detach( -/*============*/ - btr_pcur_t* pcur) /*!< in: persistent cursor */ -{ - ut_a(pcur->pos_state == BTR_PCUR_IS_POSITIONED); - - pcur->latch_mode = BTR_NO_LATCHES; - - pcur->pos_state = BTR_PCUR_WAS_POSITIONED; -} - -/**************************************************************//** -Tests if a cursor is detached: that is the latch mode is BTR_NO_LATCHES. -@return TRUE if detached */ -UNIV_INLINE -ibool -btr_pcur_is_detached( -/*=================*/ - btr_pcur_t* pcur) /*!< in: persistent cursor */ -{ - if (pcur->latch_mode == BTR_NO_LATCHES) { - - return(TRUE); - } - - return(FALSE); -} - /**************************************************************//** Sets the old_rec_buf field to NULL. */ UNIV_INLINE diff --git a/include/btr0sea.h b/include/btr0sea.h index 9e82602934e..d9f2cf9c81b 100644 --- a/include/btr0sea.h +++ b/include/btr0sea.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -137,11 +137,10 @@ UNIV_INTERN void btr_search_drop_page_hash_index( /*============================*/ - buf_block_t* block, /*!< in: block containing index page, + buf_block_t* block); /*!< in: block containing index page, s- or x-latched, or an index page for which we know that block->buf_fix_count == 0 */ - dict_index_t* index_in); /************************************************************************ Drops a page hash index based on index */ UNIV_INTERN @@ -150,8 +149,8 @@ btr_search_drop_page_hash_index_on_index( /*=====================================*/ dict_index_t* index); /* in: record descriptor */ /********************************************************************//** -Drops a page hash index when a page is freed from a fseg to the file system. -Drops possible hash index if the page happens to be in the buffer pool. */ +Drops a possible page hash index when a page is evicted from the buffer pool +or freed in a file segment. */ UNIV_INTERN void btr_search_drop_page_hash_when_freed( @@ -235,19 +234,6 @@ void btr_search_s_unlock_all(void); /*==========================*/ - -/** Flag: has the search system been enabled? -Protected by btr_search_latch and btr_search_enabled_mutex. */ -extern char btr_search_enabled; - -extern ulint btr_search_index_num; - -/** Flag: whether the search system has completed its disabling process, -It is set to TRUE right after buf_pool_drop_hash_index() in -btr_search_disable(), indicating hash index entries are cleaned up. -Protected by btr_search_latch and btr_search_enabled_mutex. */ -extern ibool btr_search_fully_disabled; - /** The search info struct in an index */ struct btr_search_struct{ ulint ref_count; /*!< Number of blocks in this index tree @@ -316,26 +302,6 @@ struct btr_search_sys_struct{ /** The adaptive hash index */ extern btr_search_sys_t* btr_search_sys; -/** @brief The latch protecting the adaptive search system - -This latch protects the -(1) hash index; -(2) columns of a record to which we have a pointer in the hash index; - -but does NOT protect: - -(3) next record offset field in a record; -(4) next or previous records on the same page. - -Bear in mind (3) and (4) when using the hash index. -*/ -//extern rw_lock_t* btr_search_latch_temp; - -extern rw_lock_t** btr_search_latch_part; - -/** The latch protecting the adaptive search system */ -//#define btr_search_latch (*btr_search_latch_temp) - #ifdef UNIV_SEARCH_PERF_STAT /** Number of successful adaptive hash index lookups */ extern ulint btr_search_n_succ; diff --git a/include/btr0types.h b/include/btr0types.h index 07c06fb18d7..6f515c3f58c 100644 --- a/include/btr0types.h +++ b/include/btr0types.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -30,6 +30,7 @@ Created 2/17/1996 Heikki Tuuri #include "rem0types.h" #include "page0types.h" +#include "sync0rw.h" /** Persistent cursor */ typedef struct btr_pcur_struct btr_pcur_t; @@ -38,6 +39,32 @@ typedef struct btr_cur_struct btr_cur_t; /** B-tree search information for the adaptive hash index */ typedef struct btr_search_struct btr_search_t; +/** @brief The latch protecting the adaptive search system + +This latch protects the +(1) hash index; +(2) columns of a record to which we have a pointer in the hash index; + +but does NOT protect: + +(3) next record offset field in a record; +(4) next or previous records on the same page. + +Bear in mind (3) and (4) when using the hash index. +*/ +//extern rw_lock_t* btr_search_latch_temp; + +extern rw_lock_t** btr_search_latch_part; + +/** The latch protecting the adaptive search system */ +//#define btr_search_latch (*btr_search_latch_temp) + +/** Flag: has the search system been enabled? +Protected by btr_search_latch. */ +extern char btr_search_enabled; + +extern ulint btr_search_index_num; + #ifdef UNIV_BLOB_DEBUG # include "buf0types.h" /** An index->blobs entry for keeping track of off-page column references */ diff --git a/include/buf0buf.h b/include/buf0buf.h index d85dac5cc91..0ea74fb9eb2 100644 --- a/include/buf0buf.h +++ b/include/buf0buf.h @@ -244,13 +244,11 @@ buf_pool_free( ulint n_instances); /*!< in: numbere of instances to free */ /********************************************************************//** -Drops the adaptive hash index. To prevent a livelock, this function -is only to be called while holding btr_search_latch and while -btr_search_enabled == FALSE. */ +Clears the adaptive hash index on all pages in the buffer pool. */ UNIV_INTERN void -buf_pool_drop_hash_index(void); -/*==========================*/ +buf_pool_clear_hash_index(void); +/*===========================*/ /********************************************************************//** Relocate a buffer control block. Relocates the block on the LRU list @@ -583,17 +581,6 @@ buf_page_peek_if_too_old( /*=====================*/ const buf_page_t* bpage); /*!< in: block to make younger */ /********************************************************************//** -Returns the current state of is_hashed of a page. FALSE if the page is -not in the pool. NOTE that this operation does not fix the page in the -pool if it is found there. -@return TRUE if page hash index is built in search system */ -UNIV_INTERN -ibool -buf_page_peek_if_search_hashed( -/*===========================*/ - ulint space, /*!< in: space id */ - ulint offset);/*!< in: page number */ -/********************************************************************//** Gets the youngest modification log sequence number for a frame. Returns zero if not file page or no modification occurred yet. @return newest modification to page */ @@ -952,7 +939,27 @@ buf_block_set_io_fix( /*=================*/ buf_block_t* block, /*!< in/out: control block */ enum buf_io_fix io_fix);/*!< in: io_fix state */ - +/*********************************************************************//** +Makes a block sticky. A sticky block implies that even after we release +the buf_pool->mutex and the block->mutex: +* it cannot be removed from the flush_list +* the block descriptor cannot be relocated +* it cannot be removed from the LRU list +Note that: +* the block can still change its position in the LRU list +* the next and previous pointers can change. */ +UNIV_INLINE +void +buf_page_set_sticky( +/*================*/ + buf_page_t* bpage); /*!< in/out: control block */ +/*********************************************************************//** +Removes stickiness of a block. */ +UNIV_INLINE +void +buf_page_unset_sticky( +/*==================*/ + buf_page_t* bpage); /*!< in/out: control block */ /********************************************************************//** Determine if a buffer block can be relocated in memory. The block can be dirty, but it must not be I/O-fixed or bufferfixed. */ @@ -1569,13 +1576,16 @@ struct buf_block_struct{ /* @} */ /** @name Hash search fields - These 6 fields may only be modified when we have + These 5 fields may only be modified when we have an x-latch on btr_search_latch AND - we are holding an s-latch or x-latch on buf_block_struct::lock or - we know that buf_block_struct::buf_fix_count == 0. An exception to this is when we init or create a page - in the buffer pool in buf0buf.c. */ + in the buffer pool in buf0buf.c. + + Another exception is that assigning block->index = NULL + is allowed whenever holding an x-latch on btr_search_latch. */ /* @{ */ @@ -1584,21 +1594,21 @@ struct buf_block_struct{ pointers in the adaptive hash index pointing to this frame */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - volatile unsigned is_hashed:1; /*!< TRUE if hash index has - already been built on this - page; note that it does not - guarantee that the index is - complete, though: there may - have been hash collisions, - record deletions, etc. */ unsigned curr_n_fields:10;/*!< prefix length for hash indexing: number of full fields */ unsigned curr_n_bytes:15;/*!< number of bytes in hash indexing */ unsigned curr_left_side:1;/*!< TRUE or FALSE in hash indexing */ - dict_index_t* index; /*!< Index for which the adaptive - hash index has been created. */ - volatile rw_lock_t* btr_search_latch; + dict_index_t* index; /*!< Index for which the + adaptive hash index has been + created, or NULL if the page + does not exist in the + index. Note that it does not + guarantee that the index is + complete, though: there may + have been hash collisions, + record deletions, etc. */ + volatile rw_lock_t* btr_search_latch; /* @} */ # ifdef UNIV_SYNC_DEBUG /** @name Debug fields */ diff --git a/include/buf0buf.ic b/include/buf0buf.ic index 98d575075ba..55d89b66375 100644 --- a/include/buf0buf.ic +++ b/include/buf0buf.ic @@ -444,6 +444,7 @@ buf_page_get_io_fix( case BUF_IO_NONE: case BUF_IO_READ: case BUF_IO_WRITE: + case BUF_IO_PIN: return(io_fix); } ut_error; @@ -494,6 +495,49 @@ buf_block_set_io_fix( buf_page_set_io_fix(&block->page, io_fix); } +/*********************************************************************//** +Makes a block sticky. A sticky block implies that even after we release +the buf_pool->mutex and the block->mutex: +* it cannot be removed from the flush_list +* the block descriptor cannot be relocated +* it cannot be removed from the LRU list +Note that: +* the block can still change its position in the LRU list +* the next and previous pointers can change. */ +UNIV_INLINE +void +buf_page_set_sticky( +/*================*/ + buf_page_t* bpage) /*!< in/out: control block */ +{ +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(mutex_own(&buf_pool->LRU_list_mutex)); +#endif + ut_ad(mutex_own(buf_page_get_mutex(bpage))); + ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_NONE); + + bpage->io_fix = BUF_IO_PIN; +} + +/*********************************************************************//** +Removes stickiness of a block. */ +UNIV_INLINE +void +buf_page_unset_sticky( +/*==================*/ + buf_page_t* bpage) /*!< in/out: control block */ +{ +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(mutex_own(&buf_pool->LRU_list_mutex)); +#endif + ut_ad(mutex_own(buf_page_get_mutex(bpage))); + ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_PIN); + + bpage->io_fix = BUF_IO_NONE; +} + /********************************************************************//** Determine if a buffer block can be relocated in memory. The block can be dirty, but it must not be I/O-fixed or bufferfixed. */ diff --git a/include/buf0types.h b/include/buf0types.h index 156093aad01..d140936a886 100644 --- a/include/buf0types.h +++ b/include/buf0types.h @@ -57,7 +57,10 @@ enum buf_flush { enum buf_io_fix { BUF_IO_NONE = 0, /**< no pending I/O */ BUF_IO_READ, /**< read pending */ - BUF_IO_WRITE /**< write pending */ + BUF_IO_WRITE, /**< write pending */ + BUF_IO_PIN /**< disallow relocation of + block and its removal of from + the flush_list */ }; /** Parameters of binary buddy system for compressed pages (buf0buddy.h) */ diff --git a/include/fil0fil.h b/include/fil0fil.h index 840a9fbb13a..92fdca0db1b 100644 --- a/include/fil0fil.h +++ b/include/fil0fil.h @@ -34,6 +34,7 @@ Created 10/25/1995 Heikki Tuuri #include "sync0rw.h" #include "ibuf0types.h" #endif /* !UNIV_HOTBACKUP */ +#include "trx0types.h" /** When mysqld is run, the default directory "." is the mysqld datadir, but in the MySQL Embedded Server Library and ibbackup it is not the default @@ -329,18 +330,23 @@ Reads the flushed lsn and arch no fields from a data file at database startup. */ UNIV_INTERN void -fil_read_flushed_lsn_and_arch_log_no( -/*=================================*/ +fil_read_first_page( +/*================*/ os_file_t data_file, /*!< in: open data file */ ibool one_read_already, /*!< in: TRUE if min and max parameters below already contain sensible data */ + ulint* flags, /*!< out: tablespace flags */ #ifdef UNIV_LOG_ARCHIVE - ulint* min_arch_log_no, /*!< in/out: */ - ulint* max_arch_log_no, /*!< in/out: */ + ulint* min_arch_log_no, /*!< out: min of archived + log numbers in data files */ + ulint* max_arch_log_no, /*!< out: max of archived + log numbers in data files */ #endif /* UNIV_LOG_ARCHIVE */ - ib_uint64_t* min_flushed_lsn, /*!< in/out: */ - ib_uint64_t* max_flushed_lsn); /*!< in/out: */ + ib_uint64_t* min_flushed_lsn, /*!< out: min of flushed + lsn values in data files */ + ib_uint64_t* max_flushed_lsn); /*!< out: max of flushed + lsn values in data files */ /*******************************************************************//** Increments the count of pending insert buffer page merges, if space is not being deleted. @@ -474,8 +480,11 @@ fil_open_single_table_tablespace( accessing the first page of the file */ ulint id, /*!< in: space id */ ulint flags, /*!< in: tablespace flags */ - const char* name); /*!< in: table name in the + const char* name, /*!< in: table name in the databasename/tablename format */ + trx_t* trx); /*!< in: transaction. This is only used + for IMPORT TABLESPACE, must be NULL + otherwise */ /********************************************************************//** It is possible, though very improbable, that the lsn's in the tablespace to be imported have risen above the current system lsn, if a lengthy purge, ibuf diff --git a/include/fsp0fsp.h b/include/fsp0fsp.h index 7abd3914eda..d5e235aa870 100644 --- a/include/fsp0fsp.h +++ b/include/fsp0fsp.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ @@ -34,6 +34,90 @@ Created 12/18/1995 Heikki Tuuri #include "page0types.h" #include "fsp0types.h" +/* @defgroup fsp_flags InnoDB Tablespace Flag Constants @{ */ + +/** Number of flag bits used to indicate the tablespace page size */ +#define FSP_FLAGS_WIDTH_PAGE_SSIZE 4 +/** Zero relative shift position of the PAGE_SSIZE field */ +#define FSP_FLAGS_POS_PAGE_SSIZE 6 +/** Bit mask of the PAGE_SSIZE field */ +#define FSP_FLAGS_MASK_PAGE_SSIZE \ + ((~(~0 << FSP_FLAGS_WIDTH_PAGE_SSIZE)) \ + << FSP_FLAGS_POS_PAGE_SSIZE) +/** Return the value of the PAGE_SSIZE field */ +#define FSP_FLAGS_GET_PAGE_SSIZE(flags) \ + ((flags & FSP_FLAGS_MASK_PAGE_SSIZE) \ + >> FSP_FLAGS_POS_PAGE_SSIZE) + +/* @} */ + +/* @defgroup Tablespace Header Constants (moved from fsp0fsp.c) @{ */ + +/** Offset of the space header within a file page */ +#define FSP_HEADER_OFFSET FIL_PAGE_DATA + +/* The data structures in files are defined just as byte strings in C */ +typedef byte fsp_header_t; +typedef byte xdes_t; + +/* SPACE HEADER + ============ + +File space header data structure: this data structure is contained in the +first page of a space. The space for this header is reserved in every extent +descriptor page, but used only in the first. */ + +/*-------------------------------------*/ +#define FSP_SPACE_ID 0 /* space id */ +#define FSP_NOT_USED 4 /* this field contained a value up to + which we know that the modifications + in the database have been flushed to + the file space; not used now */ +#define FSP_SIZE 8 /* Current size of the space in + pages */ +#define FSP_FREE_LIMIT 12 /* Minimum page number for which the + free list has not been initialized: + the pages >= this limit are, by + definition, free; note that in a + single-table tablespace where size + < 64 pages, this number is 64, i.e., + we have initialized the space + about the first extent, but have not + physically allocted those pages to the + file */ +#define FSP_SPACE_FLAGS 16 /* fsp_space_t.flags, similar to + dict_table_t::flags */ +#define FSP_FRAG_N_USED 20 /* number of used pages in the + FSP_FREE_FRAG list */ +#define FSP_FREE 24 /* list of free extents */ +#define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE) + /* list of partially free extents not + belonging to any segment */ +#define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE) + /* list of full extents not belonging + to any segment */ +#define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE) + /* 8 bytes which give the first unused + segment id */ +#define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE) + /* list of pages containing segment + headers, where all the segment inode + slots are reserved */ +#define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE) + /* list of pages containing segment + headers, where not all the segment + header slots are reserved */ +/*-------------------------------------*/ +/* File space header size */ +#define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE) + +#define FSP_FREE_ADD 4 /* this many free extents are added + to the free list from above + FSP_FREE_LIMIT at a time */ +/* @} */ + +/* @} */ + /**********************************************************************//** Initializes the file space system. */ UNIV_INTERN @@ -352,6 +436,18 @@ fseg_print( mtr_t* mtr); /*!< in: mtr */ #endif /* UNIV_BTR_PRINT */ +/********************************************************************//** +Extract the page size from tablespace flags. +This feature, storing the page_ssize into the tablespace flags, is added +to InnoDB 5.6.4. This is here only to protect against a crash if a newer +database is opened with this code branch. +@return page size of the tablespace in bytes */ +UNIV_INLINE +ulint +fsp_flags_get_page_size( +/*====================*/ + ulint flags); /*!< in: tablespace flags */ + #ifndef UNIV_NONINL #include "fsp0fsp.ic" #endif diff --git a/include/fsp0fsp.ic b/include/fsp0fsp.ic index 434c370b527..c92111a9d89 100644 --- a/include/fsp0fsp.ic +++ b/include/fsp0fsp.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ @@ -43,3 +43,31 @@ fsp_descr_page( return(UNIV_UNLIKELY((page_no & (zip_size - 1)) == FSP_XDES_OFFSET)); } +/********************************************************************//** +Extract the page size from tablespace flags. +This feature, storing the page_ssize into the tablespace flags, is added +to InnoDB 5.6.4. This is here only to protect against a crash if a newer +database is opened with this code branch. +@return page size of the tablespace in bytes */ +UNIV_INLINE +ulint +fsp_flags_get_page_size( +/*====================*/ + ulint flags) /*!< in: tablespace flags */ +{ + ulint page_size = 0; + ulint ssize = FSP_FLAGS_GET_PAGE_SSIZE(flags); + + /* Convert from a 'log2 minus 9' to a page size in bytes. */ + if (UNIV_UNLIKELY(ssize)) { + page_size = (512 << ssize); + + ut_ad(page_size <= UNIV_PAGE_SIZE); + } else { + /* If the page size was not stored, then it is the + original 16k. */ + page_size = UNIV_PAGE_SIZE; + } + + return(page_size); +} diff --git a/include/ha0ha.h b/include/ha0ha.h index 3299000bf3c..8bba564d153 100644 --- a/include/ha0ha.h +++ b/include/ha0ha.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -31,13 +31,14 @@ Created 8/18/1994 Heikki Tuuri #include "hash0hash.h" #include "page0types.h" #include "buf0types.h" +#include "rem0types.h" /*************************************************************//** Looks for an element in a hash table. @return pointer to the data of the first hash table node in chain having the fold number, NULL if not found */ UNIV_INLINE -void* +const rec_t* ha_search_and_get_data( /*===================*/ hash_table_t* table, /*!< in: hash table */ @@ -51,11 +52,11 @@ ha_search_and_update_if_found_func( /*===============================*/ hash_table_t* table, /*!< in/out: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data, /*!< in: pointer to the data */ + const rec_t* data, /*!< in: pointer to the data */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* new_block,/*!< in: block containing new_data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* new_data);/*!< in: new pointer to the data */ + const rec_t* new_data);/*!< in: new pointer to the data */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG /** Looks for an element when we know the pointer to the data and @@ -113,14 +114,6 @@ chosen to be a slightly bigger prime number. # define ha_create(n_c,n_m,level) ha_create_func(n_c,n_m) #endif /* UNIV_SYNC_DEBUG */ -/*************************************************************//** -Empties a hash table and frees the memory heaps. */ -UNIV_INTERN -void -ha_clear( -/*=====*/ - hash_table_t* table); /*!< in, own: hash table */ - /*************************************************************//** Inserts an entry into a hash table. If an entry with the same fold number is found, its node is updated to point to the new data, and no new node @@ -138,7 +131,7 @@ ha_insert_for_fold_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block, /*!< in: buffer block containing the data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* data); /*!< in: data, must not be NULL */ + const rec_t* data); /*!< in: data, must not be NULL */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG /** @@ -174,7 +167,7 @@ ha_search_and_delete_if_found( /*==========================*/ hash_table_t* table, /*!< in: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data); /*!< in: pointer to the data */ + const rec_t* data); /*!< in: pointer to the data */ #ifndef UNIV_HOTBACKUP /*****************************************************************//** Removes from the chain determined by fold all nodes whose data pointer @@ -217,7 +210,7 @@ struct ha_node_struct { #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block; /*!< buffer block containing the data, or NULL */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* data; /*!< pointer to the data */ + const rec_t* data; /*!< pointer to the data */ ulint fold; /*!< fold value for the data */ }; diff --git a/include/ha0ha.ic b/include/ha0ha.ic index 734403c4cd9..f224776c134 100644 --- a/include/ha0ha.ic +++ b/include/ha0ha.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -25,6 +25,7 @@ Created 8/18/1994 Heikki Tuuri #include "ut0rnd.h" #include "mem0mem.h" +#include "btr0types.h" /***********************************************************//** Deletes a hash node. */ @@ -39,10 +40,10 @@ ha_delete_hash_node( Gets a hash node data. @return pointer to the data */ UNIV_INLINE -void* +const rec_t* ha_node_get_data( /*=============*/ - ha_node_t* node) /*!< in: hash chain node */ + const ha_node_t* node) /*!< in: hash chain node */ { return(node->data); } @@ -57,7 +58,7 @@ ha_node_set_data_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block, /*!< in: buffer block containing the data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* data) /*!< in: pointer to the data */ + const rec_t* data) /*!< in: pointer to the data */ { #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG node->block = block; @@ -105,41 +106,12 @@ ha_chain_get_first( hash_get_nth_cell(table, hash_calc_hash(fold, table))->node); } -/*************************************************************//** -Looks for an element in a hash table. -@return pointer to the first hash table node in chain having the fold -number, NULL if not found */ -UNIV_INLINE -ha_node_t* -ha_search( -/*======*/ - hash_table_t* table, /*!< in: hash table */ - ulint fold) /*!< in: folded value of the searched data */ -{ - ha_node_t* node; - - ASSERT_HASH_MUTEX_OWN(table, fold); - - node = ha_chain_get_first(table, fold); - - while (node) { - if (node->fold == fold) { - - return(node); - } - - node = ha_chain_get_next(node); - } - - return(NULL); -} - /*************************************************************//** Looks for an element in a hash table. @return pointer to the data of the first hash table node in chain having the fold number, NULL if not found */ UNIV_INLINE -void* +const rec_t* ha_search_and_get_data( /*===================*/ hash_table_t* table, /*!< in: hash table */ @@ -148,6 +120,10 @@ ha_search_and_get_data( ha_node_t* node; ASSERT_HASH_MUTEX_OWN(table, fold); +#ifdef UNIV_SYNC_DEBUG +// ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_SHARED)); +#endif /* UNIV_SYNC_DEBUG */ + ut_ad(btr_search_enabled); node = ha_chain_get_first(table, fold); @@ -172,12 +148,14 @@ ha_search_with_data( /*================*/ hash_table_t* table, /*!< in: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data) /*!< in: pointer to the data */ + const rec_t* data) /*!< in: pointer to the data */ { ha_node_t* node; ASSERT_HASH_MUTEX_OWN(table, fold); + ut_ad(btr_search_enabled); + node = ha_chain_get_first(table, fold); while (node) { @@ -202,11 +180,15 @@ ha_search_and_delete_if_found( /*==========================*/ hash_table_t* table, /*!< in: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data) /*!< in: pointer to the data */ + const rec_t* data) /*!< in: pointer to the data */ { ha_node_t* node; ASSERT_HASH_MUTEX_OWN(table, fold); +#ifdef UNIV_SYNC_DEBUG +// ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + ut_ad(btr_search_enabled); node = ha_search_with_data(table, fold, data); diff --git a/include/page0page.h b/include/page0page.h index 3647dc57235..616939586e0 100644 --- a/include/page0page.h +++ b/include/page0page.h @@ -893,6 +893,7 @@ page_parse_create( ulint comp, /*!< in: nonzero=compact page format */ buf_block_t* block, /*!< in: block or NULL */ mtr_t* mtr); /*!< in: mtr or NULL */ +#ifndef UNIV_HOTBACKUP /************************************************************//** Prints record contents including the data relevant only in the index page context. */ @@ -902,6 +903,7 @@ page_rec_print( /*===========*/ const rec_t* rec, /*!< in: physical record */ const ulint* offsets);/*!< in: record descriptor */ +# ifdef UNIV_BTR_PRINT /***************************************************************//** This is used to print the contents of the directory for debugging purposes. */ @@ -941,6 +943,8 @@ page_print( in directory */ ulint rn); /*!< in: print rn first and last records in directory */ +# endif /* UNIV_BTR_PRINT */ +#endif /* !UNIV_HOTBACKUP */ /***************************************************************//** The following is used to validate a record on a page. This function differs from rec_validate as it can also check the n_owned field and diff --git a/include/row0upd.ic b/include/row0upd.ic index 11db82f64da..10646241125 100644 --- a/include/row0upd.ic +++ b/include/row0upd.ic @@ -28,7 +28,6 @@ Created 12/27/1996 Heikki Tuuri # include "trx0trx.h" # include "trx0undo.h" # include "row0row.h" -# include "btr0sea.h" #endif /* !UNIV_HOTBACKUP */ #include "page0zip.h" diff --git a/include/srv0srv.h b/include/srv0srv.h index a36ee77929a..248e1efff00 100644 --- a/include/srv0srv.h +++ b/include/srv0srv.h @@ -285,6 +285,9 @@ extern ibool srv_print_lock_waits; extern ibool srv_print_buf_io; extern ibool srv_print_log_io; extern ibool srv_print_latch_waits; + +extern ulint srv_flush_checkpoint_debug; + #else /* UNIV_DEBUG */ # define srv_print_thread_releases FALSE # define srv_print_lock_waits FALSE diff --git a/include/sync0rw.h b/include/sync0rw.h index 6420bc5d3bf..971099c91f5 100644 --- a/include/sync0rw.h +++ b/include/sync0rw.h @@ -543,7 +543,7 @@ mutex. */ UNIV_INTERN void rw_lock_debug_mutex_enter(void); -/*==========================*/ +/*===========================*/ /******************************************************************//** Releases the debug mutex. */ UNIV_INTERN @@ -634,7 +634,8 @@ struct rw_lock_struct { }; #ifdef UNIV_SYNC_DEBUG -/** The structure for storing debug info of an rw-lock */ +/** The structure for storing debug info of an rw-lock. All access to this +structure must be protected by rw_lock_debug_mutex_enter(). */ struct rw_lock_debug_struct { os_thread_id_t thread_id; /*!< The thread id of the thread which diff --git a/include/sync0rw.ic b/include/sync0rw.ic index a6dfa603c59..3eaa6172631 100644 --- a/include/sync0rw.ic +++ b/include/sync0rw.ic @@ -406,6 +406,7 @@ rw_lock_s_lock_func( #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */ + ut_ad(!rw_lock_own(lock, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ /* TODO: study performance of UNIV_LIKELY branch prediction hints. */ diff --git a/include/sync0sync.h b/include/sync0sync.h index d32c872c407..1437e797f6f 100644 --- a/include/sync0sync.h +++ b/include/sync0sync.h @@ -674,7 +674,6 @@ or row lock! */ #define SYNC_LOG_FLUSH_ORDER 156 #define SYNC_RECV 168 #define SYNC_WORK_QUEUE 162 -#define SYNC_SEARCH_SYS_CONF 161 /* for assigning btr_search_enabled */ #define SYNC_SEARCH_SYS 160 /* NOTE that if we have a memory heap that can be extended to the buffer pool, its logical level is diff --git a/include/trx0trx.h b/include/trx0trx.h index 4e010592e5a..39b8ccf26ec 100644 --- a/include/trx0trx.h +++ b/include/trx0trx.h @@ -494,6 +494,7 @@ struct trx_struct{ this is set to 1 then registered should also be set to 1. This is used in the XA code */ + unsigned called_commit_ordered:1;/* 1 if innobase_commit_ordered has run. */ /*------------------------------*/ ulint isolation_level;/* TRX_ISO_REPEATABLE_READ, ... */ ulint check_foreigns; /* normally TRUE, but if the user diff --git a/log/log0log.c b/log/log0log.c index ae5f071261d..8ba34ef8a83 100644 --- a/log/log0log.c +++ b/log/log0log.c @@ -1691,10 +1691,13 @@ log_preflush_pool_modified_pages( recv_apply_hashed_log_recs(TRUE); } + retry: n_pages = buf_flush_list(ULINT_MAX, new_oldest); - if (sync) { - buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); + if (sync && n_pages != 0) { + //buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); + os_thread_sleep(100000); + goto retry; } if (n_pages == ULINT_UNDEFINED) { @@ -2016,6 +2019,13 @@ log_checkpoint( { ib_uint64_t oldest_lsn; +#ifdef UNIV_DEBUG + if (srv_flush_checkpoint_debug == 1) { + + return TRUE; + } +#endif + if (recv_recovery_is_on()) { recv_apply_hashed_log_recs(TRUE); } @@ -2107,7 +2117,11 @@ log_make_checkpoint_at( physical write will always be made to log files */ { - /* Preflush pages synchronously */ +#ifdef UNIV_DEBUG + if (srv_flush_checkpoint_debug == 1) + return; +#endif +/* Preflush pages synchronously */ while (!log_preflush_pool_modified_pages(lsn, TRUE)); @@ -2133,7 +2147,13 @@ log_checkpoint_margin(void) ibool checkpoint_sync; ibool do_checkpoint; ibool success; -loop: + +#ifdef UNIV_DEBUG + if (srv_flush_checkpoint_debug == 1) + return; +#endif + + loop: sync = FALSE; checkpoint_sync = FALSE; do_checkpoint = FALSE; @@ -2156,13 +2176,15 @@ loop: /* A flush is urgent: we have to do a synchronous preflush */ sync = TRUE; - advance = 2 * (age - log->max_modified_age_sync); + advance = age - log->max_modified_age_sync; } else if (age > log_max_modified_age_async()) { /* A flush is not urgent: we do an asynchronous preflush */ advance = age - log_max_modified_age_async(); + log->check_flush_or_checkpoint = FALSE; } else { advance = 0; + log->check_flush_or_checkpoint = FALSE; } checkpoint_age = log->lsn - log->last_checkpoint_lsn; @@ -2179,9 +2201,9 @@ loop: do_checkpoint = TRUE; - log->check_flush_or_checkpoint = FALSE; + //log->check_flush_or_checkpoint = FALSE; } else { - log->check_flush_or_checkpoint = FALSE; + //log->check_flush_or_checkpoint = FALSE; } mutex_exit(&(log->mutex)); @@ -2189,6 +2211,7 @@ loop: if (advance) { ib_uint64_t new_oldest = oldest_lsn + advance; +retry: success = log_preflush_pool_modified_pages(new_oldest, sync); /* If the flush succeeded, this thread has done its part @@ -2203,7 +2226,7 @@ loop: log->check_flush_or_checkpoint = TRUE; mutex_exit(&(log->mutex)); - goto loop; + goto retry; } } @@ -3081,7 +3104,11 @@ void log_check_margins(void) /*===================*/ { -loop: +#ifdef UNIV_DEBUG + if (srv_flush_checkpoint_debug == 1) + return; +#endif + loop: log_flush_margin(); log_checkpoint_margin(); diff --git a/page/page0page.c b/page/page0page.c index 17f6c6bbc36..4858929082a 100644 --- a/page/page0page.c +++ b/page/page0page.c @@ -215,12 +215,6 @@ page_set_max_trx_id( { page_t* page = buf_block_get_frame(block); #ifndef UNIV_HOTBACKUP - const ibool is_hashed = block->is_hashed; - - if (is_hashed) { - rw_lock_x_lock(btr_search_get_latch(block->index->id)); - } - ut_ad(!mtr || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); #endif /* !UNIV_HOTBACKUP */ @@ -241,12 +235,6 @@ page_set_max_trx_id( } else { mach_write_to_8(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), trx_id); } - -#ifndef UNIV_HOTBACKUP - if (is_hashed) { - rw_lock_x_unlock(btr_search_get_latch(block->index->id)); - } -#endif /* !UNIV_HOTBACKUP */ } /************************************************************//** @@ -1603,13 +1591,14 @@ page_rec_print( " n_owned: %lu; heap_no: %lu; next rec: %lu\n", (ulong) rec_get_n_owned_old(rec), (ulong) rec_get_heap_no_old(rec), - (ulong) rec_get_next_offs(rec, TRUE)); + (ulong) rec_get_next_offs(rec, FALSE)); } page_rec_check(rec); rec_validate(rec, offsets); } +# ifdef UNIV_BTR_PRINT /***************************************************************//** This is used to print the contents of the directory for debugging purposes. */ @@ -1770,6 +1759,7 @@ page_print( page_dir_print(page, dn); page_print_list(block, index, rn); } +# endif /* UNIV_BTR_PRINT */ #endif /* !UNIV_HOTBACKUP */ /***************************************************************//** diff --git a/page/page0zip.c b/page/page0zip.c index fc9f30ed94e..d4b0dd8339d 100644 --- a/page/page0zip.c +++ b/page/page0zip.c @@ -4456,7 +4456,7 @@ page_zip_reorganize( #ifndef UNIV_HOTBACKUP temp_block = buf_block_alloc(buf_pool); - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); block->check_index_page_at_flush = TRUE; #else /* !UNIV_HOTBACKUP */ ut_ad(block == back_block1); diff --git a/percona-suite/percona_flush_contiguous_neighbors-master.opt b/percona-suite/percona_flush_contiguous_neighbors-master.opt new file mode 100644 index 00000000000..075af88054f --- /dev/null +++ b/percona-suite/percona_flush_contiguous_neighbors-master.opt @@ -0,0 +1 @@ +--innodb_flush_neighbor_pages=cont diff --git a/percona-suite/percona_flush_contiguous_neighbors.result b/percona-suite/percona_flush_contiguous_neighbors.result new file mode 100644 index 00000000000..8c6b81f0848 --- /dev/null +++ b/percona-suite/percona_flush_contiguous_neighbors.result @@ -0,0 +1,21 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (id INT AUTO_INCREMENT, foo CHAR(255), PRIMARY KEY (id)) ENGINE=InnoDB; +INSERT INTO t1(foo) VALUES ('a'), ('b'); +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +DROP TABLE t1; diff --git a/percona-suite/percona_flush_contiguous_neighbors.test b/percona-suite/percona_flush_contiguous_neighbors.test new file mode 100644 index 00000000000..d80d9dc9430 --- /dev/null +++ b/percona-suite/percona_flush_contiguous_neighbors.test @@ -0,0 +1,36 @@ +# Test for innodb_flush_neighbor_pages=contiguous. +# The test is very crude: we simply overflow the buffer pool with such a number of +# new/modified pages that some flushing is bound to happen. + +--source include/have_innodb.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (id INT AUTO_INCREMENT, foo CHAR(255), PRIMARY KEY (id)) ENGINE=InnoDB; + +INSERT INTO t1(foo) VALUES ('a'), ('b'); +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; + +# TODO: cannot record a stable value here. A check of > 0 should be enough, +# but the variable is not accessible through INFORMATION_SCHEMA currently. +# SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_flushed'; + +DROP TABLE t1; diff --git a/percona-suite/percona_query_cache_with_comments.inc b/percona-suite/percona_query_cache_with_comments.inc index bed87bd4c22..2619105b322 100644 --- a/percona-suite/percona_query_cache_with_comments.inc +++ b/percona-suite/percona_query_cache_with_comments.inc @@ -91,5 +91,27 @@ let $query=select * from t1 -- comment in the end ; --source include/percona_query_cache_with_comments_eval.inc +let $query=select */* a comment \*/from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select *# a comment \\ +from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select *-- a comment \\ +from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select "\\\\"" /* not a comment */" from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select "\\\\"" /*! not a comment */" from t1; +--source include/percona_query_cache_with_comments_eval.inc + +# following two queries related to bug #856404. +# There are different queries, but opt_query_cache_strip_comments thinks that they are equal. let $query=select ' \' ' from t1; --source include/percona_query_cache_with_comments_eval.inc + +let $query=select ' \' /* comment inside quotes with internal backslash quote */' from t1; +--source include/percona_query_cache_with_comments_eval.inc diff --git a/percona-suite/percona_query_cache_with_comments.result b/percona-suite/percona_query_cache_with_comments.result index 169fdf80fef..d1a6ded08d7 100644 --- a/percona-suite/percona_query_cache_with_comments.result +++ b/percona-suite/percona_query_cache_with_comments.result @@ -831,7 +831,7 @@ show status like "Qcache_hits"; Variable_name Value Qcache_hits 50 ----------------------------------------------------- -select ' \' ' from t1 +select */* a comment \*/from t1 ----------------------------------------------------- show status like "Qcache_queries_in_cache"; Variable_name Value @@ -842,6 +842,167 @@ Qcache_inserts 1 show status like "Qcache_hits"; Variable_name Value Qcache_hits 50 +select */* a comment \*/from t1; +a +1 +2 +3 +select */* a comment \*/from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 52 +----------------------------------------------------- +select *# a comment \ +from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 52 +select *# a comment \ +from t1; +a +1 +2 +3 +select *# a comment \ +from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 54 +----------------------------------------------------- +select *-- a comment \ +from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 54 +select *-- a comment \ +from t1; +a +1 +2 +3 +select *-- a comment \ +from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 56 +----------------------------------------------------- +select "\\"" /* not a comment */" from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 56 +select "\\"" /* not a comment */" from t1; +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +select "\\"" /* not a comment */" from t1; +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 57 +----------------------------------------------------- +select "\\"" /*! not a comment */" from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 57 +select "\\"" /*! not a comment */" from t1; +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +select "\\"" /*! not a comment */" from t1; +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 3 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 58 +----------------------------------------------------- +select ' \' ' from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 3 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 58 select ' \' ' from t1; ' ' @@ -854,13 +1015,44 @@ select ' \' ' from t1; ' show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 2 +Qcache_queries_in_cache 4 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 2 +Qcache_inserts 4 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 51 +Qcache_hits 59 +----------------------------------------------------- +select ' \' /* comment inside quotes with internal backslash quote */' from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 4 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 4 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 59 +select ' \' /* comment inside quotes with internal backslash quote */' from t1; +' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ +select ' \' /* comment inside quotes with internal backslash quote */' from t1; +' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 5 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 5 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 60 DROP TABLE t1; SET GLOBAL query_cache_size=default; set global query_cache_strip_comments=OFF; diff --git a/percona-suite/percona_query_cache_with_comments_disable.result b/percona-suite/percona_query_cache_with_comments_disable.result index a13a44d9a1c..7e793a942c5 100644 --- a/percona-suite/percona_query_cache_with_comments_disable.result +++ b/percona-suite/percona_query_cache_with_comments_disable.result @@ -830,7 +830,7 @@ show status like "Qcache_hits"; Variable_name Value Qcache_hits 25 ----------------------------------------------------- -select ' \' ' from t1 +select */* a comment \*/from t1 ----------------------------------------------------- show status like "Qcache_queries_in_cache"; Variable_name Value @@ -841,6 +841,167 @@ Qcache_inserts 20 show status like "Qcache_hits"; Variable_name Value Qcache_hits 25 +select */* a comment \*/from t1; +a +1 +2 +3 +select */* a comment \*/from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 21 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 21 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 26 +----------------------------------------------------- +select *# a comment \ +from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 21 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 21 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 26 +select *# a comment \ +from t1; +a +1 +2 +3 +select *# a comment \ +from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 22 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 22 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 27 +----------------------------------------------------- +select *-- a comment \ +from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 22 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 22 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 27 +select *-- a comment \ +from t1; +a +1 +2 +3 +select *-- a comment \ +from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 23 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 23 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 28 +----------------------------------------------------- +select "\\"" /* not a comment */" from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 23 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 23 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 28 +select "\\"" /* not a comment */" from t1; +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +select "\\"" /* not a comment */" from t1; +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 24 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 24 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 29 +----------------------------------------------------- +select "\\"" /*! not a comment */" from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 24 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 24 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 29 +select "\\"" /*! not a comment */" from t1; +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +select "\\"" /*! not a comment */" from t1; +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 25 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 25 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 30 +----------------------------------------------------- +select ' \' ' from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 25 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 25 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 30 select ' \' ' from t1; ' ' @@ -853,13 +1014,44 @@ select ' \' ' from t1; ' show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 21 +Qcache_queries_in_cache 26 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 21 +Qcache_inserts 26 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 26 +Qcache_hits 31 +----------------------------------------------------- +select ' \' /* comment inside quotes with internal backslash quote */' from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 26 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 26 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 31 +select ' \' /* comment inside quotes with internal backslash quote */' from t1; +' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ +select ' \' /* comment inside quotes with internal backslash quote */' from t1; +' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 27 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 27 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 32 DROP TABLE t1; SET GLOBAL query_cache_size=default; set global query_cache_strip_comments=OFF; diff --git a/percona-suite/percona_query_response_time-replication.result b/percona-suite/percona_query_response_time-replication.result index c00520110c2..a6e88be6103 100644 --- a/percona-suite/percona_query_response_time-replication.result +++ b/percona-suite/percona_query_response_time-replication.result @@ -100,10 +100,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -146,10 +146,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; @@ -251,10 +251,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -297,10 +297,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; @@ -375,7 +375,7 @@ SHOW QUERY_RESPONSE_TIME; 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -391,7 +391,7 @@ time count total 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; @@ -469,7 +469,7 @@ SHOW QUERY_RESPONSE_TIME; 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -488,7 +488,7 @@ time count total 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; @@ -556,7 +556,7 @@ SHOW QUERY_RESPONSE_TIME; 1.000000 34 12.250000 156.000000 33 77.099997 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -565,7 +565,7 @@ time count total 1.000000 34 12.250000 156.000000 33 77.099997 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; @@ -632,7 +632,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 34 12.250000 1000.000000 33 77.099997 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -640,7 +640,7 @@ time count total 0.001000 0 0.000000 1.000000 34 12.250000 1000.000000 33 77.099997 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; @@ -709,7 +709,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 34 12.250000 1000.000000 33 77.099997 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -717,7 +717,7 @@ time count total 0.001000 0 0.000000 1.000000 34 12.250000 1000.000000 33 77.099997 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; diff --git a/percona-suite/percona_query_response_time-stored.result b/percona-suite/percona_query_response_time-stored.result index 7385231241e..fb458d6e7ab 100644 --- a/percona-suite/percona_query_response_time-stored.result +++ b/percona-suite/percona_query_response_time-stored.result @@ -80,10 +80,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -126,10 +126,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -204,10 +204,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -250,10 +250,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -301,7 +301,7 @@ SHOW QUERY_RESPONSE_TIME; 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -317,7 +317,7 @@ time count total 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -368,7 +368,7 @@ SHOW QUERY_RESPONSE_TIME; 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -387,7 +387,7 @@ time count total 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -428,7 +428,7 @@ SHOW QUERY_RESPONSE_TIME; 1.000000 55 8.450000 156.000000 11 25.699999 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -437,7 +437,7 @@ time count total 1.000000 55 8.450000 156.000000 11 25.699999 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -477,7 +477,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 55 8.450000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -485,7 +485,7 @@ time count total 0.001000 0 0.000000 1.000000 55 8.450000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -527,7 +527,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 55 8.450000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -535,7 +535,7 @@ time count total 0.001000 0 0.000000 1.000000 55 8.450000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; diff --git a/percona-suite/percona_query_response_time.result b/percona-suite/percona_query_response_time.result index 4c4d50319c0..1eb90d3cdd4 100644 --- a/percona-suite/percona_query_response_time.result +++ b/percona-suite/percona_query_response_time.result @@ -45,10 +45,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -91,10 +91,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -231,10 +231,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -277,10 +277,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -328,10 +328,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -374,10 +374,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -514,10 +514,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -560,10 +560,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -584,7 +584,7 @@ SHOW QUERY_RESPONSE_TIME; 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -600,7 +600,7 @@ time count total 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -710,7 +710,7 @@ SHOW QUERY_RESPONSE_TIME; 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -726,7 +726,7 @@ time count total 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -750,7 +750,7 @@ SHOW QUERY_RESPONSE_TIME; 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -769,7 +769,7 @@ time count total 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -882,7 +882,7 @@ SHOW QUERY_RESPONSE_TIME; 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -901,7 +901,7 @@ time count total 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -915,7 +915,7 @@ SHOW QUERY_RESPONSE_TIME; 1.000000 0 0.000000 156.000000 0 0.000000 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -924,7 +924,7 @@ time count total 1.000000 0 0.000000 156.000000 0 0.000000 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -1027,7 +1027,7 @@ SHOW QUERY_RESPONSE_TIME; 1.000000 11 4.050000 156.000000 11 25.699999 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -1036,7 +1036,7 @@ time count total 1.000000 11 4.050000 156.000000 11 25.699999 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -1049,7 +1049,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 0 0.000000 1000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -1057,7 +1057,7 @@ time count total 0.001000 0 0.000000 1.000000 0 0.000000 1000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -1159,7 +1159,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 11 4.050000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -1167,7 +1167,7 @@ time count total 0.001000 0 0.000000 1.000000 11 4.050000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -1182,7 +1182,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 0 0.000000 1000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -1190,7 +1190,7 @@ time count total 0.001000 0 0.000000 1.000000 0 0.000000 1000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -1292,7 +1292,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 11 4.050000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -1300,7 +1300,7 @@ time count total 0.001000 0 0.000000 1.000000 11 4.050000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; diff --git a/percona-suite/percona_server_variables_debug.result b/percona-suite/percona_server_variables_debug.result index ea1c02e7716..ae02a48c8fa 100644 --- a/percona-suite/percona_server_variables_debug.result +++ b/percona-suite/percona_server_variables_debug.result @@ -109,6 +109,7 @@ INNODB_FILE_FORMAT INNODB_FILE_FORMAT_CHECK INNODB_FILE_FORMAT_MAX INNODB_FILE_PER_TABLE +INNODB_FLUSH_CHECKPOINT_DEBUG INNODB_FLUSH_LOG_AT_TRX_COMMIT INNODB_FLUSH_METHOD INNODB_FLUSH_NEIGHBOR_PAGES @@ -228,6 +229,7 @@ MAX_SP_RECURSION_DEPTH MAX_TMP_TABLES MAX_USER_CONNECTIONS MAX_WRITE_LOCK_COUNT +METADATA_LOCKS_CACHE_SIZE MIN_EXAMINED_ROW_LIMIT MULTI_RANGE_COUNT MYISAM_DATA_POINTER_SIZE diff --git a/percona-suite/percona_server_variables_release.result b/percona-suite/percona_server_variables_release.result index e5965cf7e5e..29ac402c144 100644 --- a/percona-suite/percona_server_variables_release.result +++ b/percona-suite/percona_server_variables_release.result @@ -225,6 +225,7 @@ MAX_SP_RECURSION_DEPTH MAX_TMP_TABLES MAX_USER_CONNECTIONS MAX_WRITE_LOCK_COUNT +METADATA_LOCKS_CACHE_SIZE MIN_EXAMINED_ROW_LIMIT MULTI_RANGE_COUNT MYISAM_DATA_POINTER_SIZE diff --git a/percona-suite/percona_status_wait_query_cache_mutex.result b/percona-suite/percona_status_wait_query_cache_mutex.result index 678ed685a5b..c243b8ad02f 100644 --- a/percona-suite/percona_status_wait_query_cache_mutex.result +++ b/percona-suite/percona_status_wait_query_cache_mutex.result @@ -3,21 +3,18 @@ flush query cache; flush query cache; reset query cache; flush status; -DROP TABLE IF EXISTS t; -CREATE TABLE t(id INT, number INT); -INSERT INTO t VALUES (0,1); -INSERT INTO t VALUES (1,2); -INSERT INTO t VALUES (2,3); -SET SESSION debug="+d,status_waiting_on_query_cache_mutex_sleep"; -SET DEBUG_SYNC='status_waiting_on_query_cache_mutex SIGNAL thread_ready'; -SELECT number from t where id > 0; -SHOW PROCESSLIST; -Id User Host db Command Time State Info Rows_sent Rows_examined Rows_read -### root ### test Query ### NULL SHOW PROCESSLIST ### ### ### -### root ### test Query ### Waiting on query cache mutex SELECT number from t where id > 0 ### ### ### -SELECT id, info, state FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id; -id info state -### SELECT id, info, state FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id executing -### SELECT number from t where id > 0 Waiting on query cache mutex -DROP TABLE t; +SET DEBUG_SYNC='after_query_cache_mutex SIGNAL mutex_locked WAIT_FOR unlock_mutex'; +SELECT "mutex_locked_query" as action; +SET DEBUG_SYNC='now WAIT_FOR mutex_locked'; +SET DEBUG_SYNC='before_query_cache_mutex SIGNAL try_lock_mutex'; +SELECT "try_lock_mutex_query" as action; +SET DEBUG_SYNC='now WAIT_FOR try_lock_mutex'; +SELECT SQL_NO_CACHE state FROM INFORMATION_SCHEMA.PROCESSLIST WHERE info='SELECT "try_lock_mutex_query" as action'; +state +Waiting on query cache mutex +SET DEBUG_SYNC='now SIGNAL unlock_mutex'; +action +mutex_locked_query +action +try_lock_mutex_query SET GLOBAL query_cache_size=0; diff --git a/percona-suite/percona_status_wait_query_cache_mutex.test b/percona-suite/percona_status_wait_query_cache_mutex.test index 1e586ca4e7a..b20f088d6ae 100644 --- a/percona-suite/percona_status_wait_query_cache_mutex.test +++ b/percona-suite/percona_status_wait_query_cache_mutex.test @@ -3,29 +3,33 @@ --source include/have_debug_sync.inc SET GLOBAL query_cache_size=1355776; --source include/percona_query_cache_with_comments_clear.inc +--let try_lock_mutex_query=SELECT "try_lock_mutex_query" as action --- disable_warnings -DROP TABLE IF EXISTS t; --- enable_warnings -CREATE TABLE t(id INT, number INT); -INSERT INTO t VALUES (0,1); -INSERT INTO t VALUES (1,2); -INSERT INTO t VALUES (2,3); +--connect (mutex_locked_conn, localhost, root,,) +--connect (try_mutex_lock_conn, localhost, root,,) ---connect (conn,localhost,root,,) - ---connection conn -SET SESSION debug="+d,status_waiting_on_query_cache_mutex_sleep"; -SET DEBUG_SYNC='status_waiting_on_query_cache_mutex SIGNAL thread_ready'; -SEND SELECT number from t where id > 0; +--connection mutex_locked_conn +SET DEBUG_SYNC='after_query_cache_mutex SIGNAL mutex_locked WAIT_FOR unlock_mutex'; +send SELECT "mutex_locked_query" as action; --connection default ---replace_column 1 ### 3 ### 6 ### 9 ### 10 ### 11 ### -SHOW PROCESSLIST; +SET DEBUG_SYNC='now WAIT_FOR mutex_locked'; ---replace_column 1 ### -SELECT id, info, state FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id; +--connection try_mutex_lock_conn +SET DEBUG_SYNC='before_query_cache_mutex SIGNAL try_lock_mutex'; +send_eval $try_lock_mutex_query; ---disconnect conn -DROP TABLE t; +--connection default +SET DEBUG_SYNC='now WAIT_FOR try_lock_mutex'; +eval SELECT SQL_NO_CACHE state FROM INFORMATION_SCHEMA.PROCESSLIST WHERE info='$try_lock_mutex_query'; +SET DEBUG_SYNC='now SIGNAL unlock_mutex'; + +--connection mutex_locked_conn +reap; +--connection try_mutex_lock_conn +reap; + +--connection default +--disconnect mutex_locked_conn +--disconnect try_mutex_lock_conn SET GLOBAL query_cache_size=0; diff --git a/percona-suite/percona_sync_flush.result b/percona-suite/percona_sync_flush.result new file mode 100644 index 00000000000..12335257b32 --- /dev/null +++ b/percona-suite/percona_sync_flush.result @@ -0,0 +1,35 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (id INT AUTO_INCREMENT, foo CHAR(255), PRIMARY KEY (id)) ENGINE=InnoDB; +SET @@global.innodb_flush_checkpoint_debug=1; +INSERT INTO t1(foo) VALUES ('a'), ('b'); +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +SET @@global.innodb_flush_checkpoint_debug=0; +UPDATE t1 SET foo='d' WHERE foo='c'; +DROP TABLE t1; diff --git a/percona-suite/percona_sync_flush.test b/percona-suite/percona_sync_flush.test new file mode 100644 index 00000000000..35e8d8f92d2 --- /dev/null +++ b/percona-suite/percona_sync_flush.test @@ -0,0 +1,33 @@ +# Test for InnoDB sync state flushing. + +--source include/have_innodb.inc +--source include/have_debug.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (id INT AUTO_INCREMENT, foo CHAR(255), PRIMARY KEY (id)) ENGINE=InnoDB; + +# It is hard to get to InnoDB sync state flushing in MTR with regular workload. Perhaps +# it is possible with many parallel connections, but that would be brittle anyway. +# So, just disable preflushing and checkpointing and issue simple workload. +SET @@global.innodb_flush_checkpoint_debug=1; + +INSERT INTO t1(foo) VALUES ('a'), ('b'); + +let $rep=0; +while ($rep < 14) +{ + INSERT INTO t1(foo) SELECT foo FROM t1; + UPDATE t1 SET foo='c'; + inc $rep; +} + +# By now checkpoint age should be well past sync flush point. Allow +# preflushing/checkpointing again and do some work in order to do the sync flush. +SET @@global.innodb_flush_checkpoint_debug=0; + +UPDATE t1 SET foo='d' WHERE foo='c'; + +DROP TABLE t1; diff --git a/row/row0ins.c b/row/row0ins.c index da035421ab9..adc75bd5760 100644 --- a/row/row0ins.c +++ b/row/row0ins.c @@ -437,11 +437,9 @@ row_ins_cascade_calc_update_vec( dict_table_t* table = foreign->foreign_table; dict_index_t* index = foreign->foreign_index; upd_t* update; - upd_field_t* ufield; dict_table_t* parent_table; dict_index_t* parent_index; upd_t* parent_update; - upd_field_t* parent_ufield; ulint n_fields_updated; ulint parent_field_no; ulint i; @@ -477,13 +475,15 @@ row_ins_cascade_calc_update_vec( dict_index_get_nth_col_no(parent_index, i)); for (j = 0; j < parent_update->n_fields; j++) { - parent_ufield = parent_update->fields + j; + const upd_field_t* parent_ufield + = &parent_update->fields[j]; if (parent_ufield->field_no == parent_field_no) { ulint min_size; const dict_col_t* col; ulint ufield_len; + upd_field_t* ufield; col = dict_index_get_nth_col(index, i); @@ -496,6 +496,8 @@ row_ins_cascade_calc_update_vec( ufield->field_no = dict_table_get_nth_col_pos( table, dict_col_get_no(col)); + + ufield->orig_len = 0; ufield->exp = NULL; ufield->new_val = parent_ufield->new_val; @@ -983,10 +985,9 @@ row_ins_foreign_check_on_constraint( goto nonstandard_exit_func; } - if ((node->is_delete - && (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)) - || (!node->is_delete - && (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL))) { + if (node->is_delete + ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) + : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) { /* Build the appropriate update vector which sets foreign->n_fields first fields in rec to SQL NULL */ @@ -995,6 +996,8 @@ row_ins_foreign_check_on_constraint( update->info_bits = 0; update->n_fields = foreign->n_fields; + UNIV_MEM_INVALID(update->fields, + update->n_fields * sizeof *update->fields); for (i = 0; i < foreign->n_fields; i++) { upd_field_t* ufield = &update->fields[i]; @@ -1663,7 +1666,7 @@ row_ins_scan_sec_index_for_duplicate( ulint n_fields_cmp; btr_pcur_t pcur; ulint err = DB_SUCCESS; - unsigned allow_duplicates; + ulint allow_duplicates; mtr_t mtr; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; @@ -1694,7 +1697,7 @@ row_ins_scan_sec_index_for_duplicate( btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); - allow_duplicates = thr_get_trx(thr)->duplicates & TRX_DUP_IGNORE; + allow_duplicates = thr_get_trx(thr)->duplicates; /* Scan index records and check if there is a duplicate */ @@ -1828,7 +1831,7 @@ row_ins_duplicate_error_in_clust( sure that in roll-forward we get the same duplicate errors as in original execution */ - if (trx->duplicates & TRX_DUP_IGNORE) { + if (trx->duplicates) { /* If the SQL-query will update or replace duplicate key we will take X-lock for @@ -1872,7 +1875,7 @@ row_ins_duplicate_error_in_clust( offsets = rec_get_offsets(rec, cursor->index, offsets, ULINT_UNDEFINED, &heap); - if (trx->duplicates & TRX_DUP_IGNORE) { + if (trx->duplicates) { /* If the SQL-query will update or replace duplicate key we will take X-lock for diff --git a/row/row0mysql.c b/row/row0mysql.c index 7ffccf35371..5e75e487f6b 100644 --- a/row/row0mysql.c +++ b/row/row0mysql.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 2000, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -290,21 +290,21 @@ row_mysql_pad_col( /* space=0x0020 */ pad_end = pad + len; ut_a(!(len % 2)); - do { + while (pad < pad_end) { *pad++ = 0x00; *pad++ = 0x20; - } while (pad < pad_end); + }; break; case 4: /* space=0x00000020 */ pad_end = pad + len; ut_a(!(len % 4)); - do { + while (pad < pad_end) { *pad++ = 0x00; *pad++ = 0x00; *pad++ = 0x00; *pad++ = 0x20; - } while (pad < pad_end); + } break; } } @@ -2735,7 +2735,7 @@ row_import_tablespace_for_mysql( success = fil_open_single_table_tablespace( TRUE, table->space, table->flags == DICT_TF_COMPACT ? 0 : table->flags, - table->name); + table->name, trx); if (success) { table->ibd_file_missing = FALSE; table->tablespace_discarded = FALSE; @@ -4118,6 +4118,7 @@ end: trx->error_state = DB_SUCCESS; trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; + err = DB_ERROR; goto funct_exit; } diff --git a/srv/srv0srv.c b/srv/srv0srv.c index 1efda4ef18b..d5f94768dba 100644 --- a/srv/srv0srv.c +++ b/srv/srv0srv.c @@ -446,7 +446,7 @@ UNIV_INTERN ulint srv_ibuf_accel_rate = 100; #define PCT_IBUF_IO(pct) ((ulint) (srv_io_capacity * srv_ibuf_accel_rate * ((double) pct / 10000.0))) UNIV_INTERN ulint srv_checkpoint_age_target = 0; -UNIV_INTERN ulint srv_flush_neighbor_pages = 1; /* 0:disable 1:enable */ +UNIV_INTERN ulint srv_flush_neighbor_pages = 1; /* 0:disable 1:area 2:contiguous */ UNIV_INTERN ulint srv_enable_unsafe_group_commit = 0; /* 0:disable 1:enable */ UNIV_INTERN ulint srv_read_ahead = 3; /* 1: random 2: linear 3: Both */ @@ -471,6 +471,9 @@ UNIV_INTERN ibool srv_print_lock_waits = FALSE; UNIV_INTERN ibool srv_print_buf_io = FALSE; UNIV_INTERN ibool srv_print_log_io = FALSE; UNIV_INTERN ibool srv_print_latch_waits = FALSE; + +UNIV_INTERN ulong srv_flush_checkpoint_debug = 0; + #endif /* UNIV_DEBUG */ UNIV_INTERN ulint srv_n_rows_inserted = 0; @@ -1220,7 +1223,7 @@ retry: enter_innodb_with_tickets(trx); return; } - os_atomic_increment_lint(&srv_conc_n_threads, -1); + (void) os_atomic_increment_lint(&srv_conc_n_threads, -1); } if (!has_yielded) { @@ -1250,7 +1253,7 @@ retry: static void srv_conc_exit_innodb_timer_based(trx_t* trx) { - os_atomic_increment_lint(&srv_conc_n_threads, -1); + (void) os_atomic_increment_lint(&srv_conc_n_threads, -1); trx->declared_to_be_inside_innodb = FALSE; trx->n_tickets_to_enter_innodb = 0; return; @@ -1472,7 +1475,7 @@ srv_conc_force_enter_innodb( ut_ad(srv_conc_n_threads >= 0); #ifdef HAVE_ATOMIC_BUILTINS if (srv_thread_concurrency_timer_based) { - os_atomic_increment_lint(&srv_conc_n_threads, 1); + (void) os_atomic_increment_lint(&srv_conc_n_threads, 1); trx->declared_to_be_inside_innodb = TRUE; trx->n_tickets_to_enter_innodb = 1; return; @@ -3617,11 +3620,18 @@ retry_flush_batch: PCT_IO(10), IB_ULONGLONG_MAX); } - srv_main_thread_op_info = "making checkpoint"; +#ifdef UNIV_DEBUG + if (srv_flush_checkpoint_debug != 1) { +#endif - /* Make a new checkpoint about once in 10 seconds */ + srv_main_thread_op_info = "making checkpoint"; - log_checkpoint(TRUE, FALSE); + /* Make a new checkpoint about once in 10 seconds */ + + log_checkpoint(TRUE, FALSE); +#ifdef UNIV_DEBUG + } +#endif srv_main_thread_op_info = "reserving kernel mutex"; @@ -3700,6 +3710,10 @@ background_loop: } mutex_exit(&kernel_mutex); +#ifdef UNIV_DEBUG + if (srv_flush_checkpoint_debug == 1) + goto skip_flush; +#endif flush_loop: srv_main_thread_op_info = "flushing buffer pool pages"; srv_main_flush_loops++; @@ -3740,6 +3754,9 @@ flush_loop: goto flush_loop; } +#ifdef UNIV_DEBUG +skip_flush: +#endif srv_main_thread_op_info = "reserving kernel mutex"; mutex_enter(&kernel_mutex); diff --git a/srv/srv0start.c b/srv/srv0start.c index 793b70f50ce..b11e63a8e56 100644 --- a/srv/srv0start.c +++ b/srv/srv0start.c @@ -735,6 +735,7 @@ open_or_create_data_files( ibool one_created = FALSE; ulint size; ulint size_high; + ulint flags; ulint rounded_size_pages; char name[10000]; @@ -917,12 +918,31 @@ open_or_create_data_files( return(DB_ERROR); } skip_size_check: - fil_read_flushed_lsn_and_arch_log_no( - files[i], one_opened, + fil_read_first_page( + files[i], one_opened, &flags, #ifdef UNIV_LOG_ARCHIVE min_arch_log_no, max_arch_log_no, #endif /* UNIV_LOG_ARCHIVE */ min_flushed_lsn, max_flushed_lsn); + + if (UNIV_PAGE_SIZE + != fsp_flags_get_page_size(flags)) { + + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Error: data file %s" + " uses page size %lu,\n", + name, + fsp_flags_get_page_size(flags)); + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: but the only supported" + " page size in this release is=%lu\n", + (ulong) UNIV_PAGE_SIZE); + + return(DB_ERROR); + } + one_opened = TRUE; } else { /* We created the data file and now write it full of @@ -1060,8 +1080,8 @@ skip_size_check: (ulong) TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * 9); } - fil_read_flushed_lsn_and_arch_log_no( - files[i], one_opened, + fil_read_first_page( + files[i], one_opened, &flags, #ifdef UNIV_LOG_ARCHIVE min_arch_log_no, max_arch_log_no, #endif /* UNIV_LOG_ARCHIVE */ diff --git a/sync/sync0rw.c b/sync/sync0rw.c index e561ae319a5..8884812d84d 100644 --- a/sync/sync0rw.c +++ b/sync/sync0rw.c @@ -623,6 +623,9 @@ rw_lock_x_lock_func( ibool spinning = FALSE; ut_ad(rw_lock_validate(lock)); +#ifdef UNIV_SYNC_DEBUG + ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); +#endif /* UNIV_SYNC_DEBUG */ i = 0; @@ -710,7 +713,7 @@ mutex. */ UNIV_INTERN void rw_lock_debug_mutex_enter(void) -/*==========================*/ +/*===========================*/ { loop: if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) { @@ -937,11 +940,13 @@ rw_lock_list_print_info( putc('\n', file); } + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(file, info); info = UT_LIST_GET_NEXT(list, info); } + rw_lock_debug_mutex_exit(); } #ifndef INNODB_RW_LOCKS_USE_ATOMICS mutex_exit(&(lock->mutex)); @@ -985,11 +990,13 @@ rw_lock_print( putc('\n', stderr); } + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(stderr, info); info = UT_LIST_GET_NEXT(list, info); } + rw_lock_debug_mutex_exit(); } } diff --git a/sync/sync0sync.c b/sync/sync0sync.c index b38e2183b0f..d2c4617d65c 100644 --- a/sync/sync0sync.c +++ b/sync/sync0sync.c @@ -1222,7 +1222,6 @@ sync_thread_add_level( case SYNC_OUTER_ANY_LATCH: case SYNC_FILE_FORMAT_TAG: case SYNC_DOUBLEWRITE: - case SYNC_SEARCH_SYS_CONF: case SYNC_TRX_LOCK_HEAP: case SYNC_KERNEL: case SYNC_IBUF_BITMAP_MUTEX: diff --git a/trx/trx0trx.c b/trx/trx0trx.c index 73c4e5afb80..a14f5db8176 100644 --- a/trx/trx0trx.c +++ b/trx/trx0trx.c @@ -111,6 +111,7 @@ trx_create( trx->is_registered = 0; trx->owns_prepare_mutex = 0; + trx->called_commit_ordered = 0; trx->start_time = ut_time(); From db4b6aa3aedd26775f0e663f6574774c33dd9cea Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 15 Feb 2012 16:38:38 +0100 Subject: [PATCH 82/83] Fix wrong type causing build failure on windows. --- storage/xtradb/include/srv0srv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index 65b341c0f13..87d28b1dde3 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -289,7 +289,7 @@ extern ibool srv_print_buf_io; extern ibool srv_print_log_io; extern ibool srv_print_latch_waits; -extern ulint srv_flush_checkpoint_debug; +extern ulong srv_flush_checkpoint_debug; #else /* UNIV_DEBUG */ # define srv_print_thread_releases FALSE From 13113c9e1a5b5d49c1e124587d6a60546d789154 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 15 Feb 2012 17:09:56 +0100 Subject: [PATCH 83/83] Fix wrong type causing build failure on windows. --- storage/xtradb/include/srv0srv.h | 2 +- storage/xtradb/srv/srv0srv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index 87d28b1dde3..b660f7ea104 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -243,7 +243,7 @@ extern long long srv_ibuf_max_size; extern ulong srv_ibuf_active_contract; extern ulong srv_ibuf_accel_rate; extern ulint srv_checkpoint_age_target; -extern ulint srv_flush_neighbor_pages; +extern ulong srv_flush_neighbor_pages; extern ulint srv_deprecated_enable_unsafe_group_commit; extern ulong srv_read_ahead; extern ulong srv_adaptive_flushing_method; diff --git a/storage/xtradb/srv/srv0srv.c b/storage/xtradb/srv/srv0srv.c index 2a4fc183c92..3476743a692 100644 --- a/storage/xtradb/srv/srv0srv.c +++ b/storage/xtradb/srv/srv0srv.c @@ -446,7 +446,7 @@ UNIV_INTERN ulong srv_ibuf_accel_rate = 100; #define PCT_IBUF_IO(pct) ((ulint) (srv_io_capacity * srv_ibuf_accel_rate * ((double) pct / 10000.0))) UNIV_INTERN ulint srv_checkpoint_age_target = 0; -UNIV_INTERN ulint srv_flush_neighbor_pages = 1; /* 0:disable 1:area 2:contiguous */ +UNIV_INTERN ulong srv_flush_neighbor_pages = 1; /* 0:disable 1:area 2:contiguous */ UNIV_INTERN ulint srv_deprecated_enable_unsafe_group_commit = 0; UNIV_INTERN ulong srv_read_ahead = 3; /* 1: random 2: linear 3: Both */